bugku—— 代码审计 做题记录
目錄
1,extract變量覆蓋
2,strcmp比較字符串
3,urldecode二次編碼繞過
4,md5()函數
5,數組返回NULL繞過
6,弱類型整數大小比較繞過
7,sha()函數比較繞過
8,md5加密相等繞過
9,十六進制與數字比較
10, 變量覆蓋
11,ereg正則%00截斷
12,strpos數組繞過
13,數字驗證正則繞過
1,extract變量覆蓋
入口給了一段php代碼:
<?php $flag='xxx'; extract($_GET); if(isset($shiyan)) { $content=trim(file_get_contents($flag)); if($shiyan==$content) { echo'flag{xxx}'; }else { echo'Oh.no'; } } ?>題目分析:URL 通過 get 的方式傳參,傳輸的數據以數組的形式被封裝在$_GET 中;extract()函數從數組中將變量導入到當前的符號表,該函數使用數組鍵名作為變量名,使用數組鍵值作為變量值;isset()函數判斷是否存在變量$shiyan;trim()函數移除字符串兩側的空白字符或其他預定義字符 ,這里是移除字符串兩側的空格;file_get_contents()函數將整個文件讀入一個字符串;假如$shiyan的值等于文件的內容($content)時,就打印出flag
我們要做的 就是 通過GET 方式傳入 $shiyan 使 它的值等于? 文件的內容 $content
最初的想法是 利用 extract() 的變量覆蓋 傳入 $shiyan 然后在利用個? php弱類型??
只傳入? ?shiyan=0? ? ? 發現不行
只能同時傳入 shiyan 和 flag 了使? 讀取文件錯誤 就會試 $content 的值為 布爾的0
傳入
?shiyan=&flag=得到flag:
flag{bugku-dmsj-p2sm3N}extract變量覆蓋:
extract() 函數從數組中將變量導入到當前的符號表。該函數使用數組鍵名作為變量名,使用數組鍵值作為變量值。針對數組中的每個元素,將在當前符號表中創建對應的一個變量。該函數返回成功設置的變量數目。
將鍵值 “Cat”、”Dog” 和 “Horse” 賦值給變量?$a、$b和?$c:
<?php $a = "Original"; $my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse"); extract($my_array); echo "$a = $a; $b = $b; $c = $c"; ?>運行結果為:
$a = Cat; $b = Dog; $c = Horse在通過 get 和 post方法進行覆蓋已有變量時 的前提:register_global=ON??
?
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';} ?>代碼大意是: 通過get傳入 變量 a 如果 變量 a 的和字符串比較 相同的話 就輸出flag:
這里利用的是 strcmp() 函數的漏洞:函數期望的是? 比較兩個字符串,但是如果我們比較的是? 數組 和 字符串 就會出錯 ,但會判定為相等?
傳入:
?
得到flag:
flag{bugku_dmsj_912k}
?
3,urldecode二次編碼繞過
eregi()函數在一個字符串搜索指定的模式的字符串。搜索不區分大小寫
<?php if(eregi("hackerDJ",$_GET[id])) {echo("not allowed!"); exit();} $_GET[id] = urldecode($_GET[id]); if($_GET[id] == "hackerDJ"){echo "Access granted!";echo "flag";} ?>eregi()函數
定義和用法:eregi()函數在一個字符串搜索指定的模式的字符串。搜索不區分大小寫。Eregi()可以特別有用的檢查有效性字符串,如密碼。可選的輸入參數規則包含一個數組的所有匹配表達式,他們被正則表達式的括號分組。
返回值:如果匹配成功返回true,否則,則返回false
使用eregi()函數來判斷,所以參數中不能直接有hackerDJ,獲取參數后使用urldecode對id的值進行解碼,所以可以讓id解碼后的值是hackerDJ進行url編碼后的值,由于瀏覽器會自行解碼一次,所以編碼兩次就好
解題方法:
(在進行編碼時,默認字母是不進行編碼的,urlencode 編碼的原理就是 將字符的ascii 碼轉化為 16進制 再加上%
,所以我們只需要將? 化成16進制形式,再每兩位加%,然后將得到的結果 再進行編碼)
GET請求:?id=%25%36%38%25%36%31%25%36%33%25%36%62%25%36%35%25%37%32%25%34%34%25%34%61?
4,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';} ?>題目分析: username 和 password 不相等? ,但他們經過 md5()編碼后相等
由于md5()函數不能處理數組,所以構造:
?username[]=2&password[]=3?
5,數組返回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);elseecho 'Invalid password'; } ?>看到ereg()就聯想到? %00截斷 、處理數組返回null
截斷:??
?password=123%00--數組:
?password[]=123--但是:
ereg只能處理字符,而你是數組,所以返回的是null,三個等號的時候不會進行類型轉換。所以null不等于false。strpos的參數同樣不能夠是數組,所以返回的依舊是null,null不等于false也是正確?
6,弱類型整數大小比較繞過
$temp = $_GET['password']; is_numeric($temp)?die("no numeric"):NULL; if($temp>1336){ echo $flag;要求:password 不是一個數字,但其值 大于1336?
這里利用? ?php 弱類型? ?在 進行? 字符串 和 數字比較時會先將 字符串轉化為 數字
?password=78966fd還可以構造數組:
php中很多函數都不能處理數組,is-numeric()也一樣? ,還有就是? 數組與數字比較大小時,永遠判定數組大于 數字(不確定)
?password[]=1也正確了
?
7,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);elseecho 'Invalid password.'; } elsecho 'Login first!'; ?>var_dump()格式化輸出
漏洞 :sha1() 函數不能處理 數組? ?處理數組時會返回? null
構造:
7.php?name[]=1&password[]=2?
?
8,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";} ?>要求: 傳入 變量 a ,a不等于?QNKCDZO? 但要使 a md5加密后 的值 跟?QNKCDZO加密后的值相等
漏洞: md5()? 繞過 ,??QNKCDZO? 加密后是:0e830400451993494058024219903391? 在php處理時會被認為是 科學計數法? 即結果是? 0
那我們再構造一個? 加密后是 0e開頭的字符串就行了
?a=s878926199a0e545993274517709034328855841020附上MD5漏洞總結:https://blog.csdn.net/vhkjhwbs/article/details/97618629
?
?
9,十六進制與數字比較
<?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);?>要求:
傳入的參數password 前十位 不能是 1~9,并且 等于?3735929054
漏洞: 十六進制 在與數字比較時 會被自動先化為? 十進制
這里 數字?3735929054的 16進制是 :0xdeadc0de? (注意 這里3735929054是個數字而不是一個字符串)
?password=0xdeadc0de?
?
10變量覆蓋
?
11,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';} } ?>利用 ereg() %00截斷 上邊做過類似的題,不再贅述!
?password=9e9%00*-*或者利用? strlen(),strpos(),ereg()函數不能處理數組 ,并且? 在 用 ===? 時 null 不等于 false
?password[]=1?
12,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 '騷年,繼續努力吧啊~'; } ?>利用 ereg()和 strpos()函數不能處理數組? ?并且? 在 ===? 或 !== 情況下? null 不等于 false
?ctf[]=113,數字驗證正則繞過
<?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; } } ?>分析:[:graph:] 可打印的非空白字符
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))? ?如果password 不是12字符以上 就輸出字符 ‘flag’并退出
?
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))? ?如果password中被匹配的組數小于6,就停止
?
f ($c < 3) break;? ?password中必須包含 四種類型中三種或四種
?
最后? password 還得等于 42
?
構造:
password=42.asd+ASD.00000000000?
?
?
?
?
總結
以上是生活随笔為你收集整理的bugku—— 代码审计 做题记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CTF——PHP审计——变量覆盖
- 下一篇: Python 中的 sys 库 和 os