CTF之代码审计汇总

版权声明:本文由CliffordWR原创,转载请注明出处。 https://blog.csdn.net/CliffordR/article/details/82974027

  最近在做bugku中代码审计的题目,发现了web题目中存在着大量的php漏洞以及弱类型函数的绕过问题,现在借着bugku中的题目来统一的整理一下。希望通过整理可以温故而知新。
第一题:extract变量覆盖 焦点:extract($_GET)

<?php $flag='xxx'; extract($_GET); if(isset($shiyan)) { $content=trim(file_get_contents($flag)); if($shiyan==$content) { echo'flag{xxx}'; } else { echo'Oh.no'; } } ?>

  该题目中extract函数并没有使用第二个参数,即函数得到两个value相同的key时,后一个产生的变量的值将覆盖前一个变量的值。参考payload:?shiyan&flag
第二题:strcmp比较字符串 焦点:if (strcmp($_GET[‘a’], $flag) == 0)

<?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'; } ?>

这个函数是用于比较字符串的函数 int strcmp ( string $str1 , string $str2 ) 参数 str1第一个字符串。str2第二个字符串。
如果 str1 小于 str2 返回 < 0;
如果 str1 大于 str2 返回 > 0;
如果两者相等,返回 0。
重点:任意数组通过strcmp和任意字符串相比较的结果都是NULL
数组和字符串比较永远都是零,已知flag{xxxxx}为字符串,那么我们就构造a为数组
参考: ?a[]

第三题:urldecode二次编码绕过 焦点: G E T [ i d ] = u r l d e c o d e ( _GET[id] = urldecode( _GET[id])

<?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判断
if(eregi(“hackerDJ”,$_GET[id])) {
echo("
not allowed!
如果,传入的id的值为hackerDJ,则返回not allowed
  下边使用urldecode对id的值进行解码,所以可以让id得到的值是hackerDJ的url编码,由于浏览器会自行解码一次,所以编码两次就好,因为要对hackerDJ编码,但是hackerDJ不是规则的,我们需要对着ascii码表编码两次。其实没有必要将hackerDJ全部进行二次编码,在这里我们仅对D进行编码,查ascii码表:D对应的ascii码为44,然后再找一个在线URL编码网站,%44 URL编码后为 %2544
参考:?id=hacker%2544J
第四题:md5()函数
MD5函数在对数组加密的时候会返回NULL
参考:?username[]=1&password[]=2

第五题:数组返回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'; } ?>

本题突破口:
if (ereg ("^[a-zA-Z0-9]+$", $_GET[‘password’]) === FALSE)
else if (strpos ($_GET[‘password’], ‘–’) !== FALSE)
首先password参数必须被修改过,其次它是个数组,进行数组绕过。
参考:?password[]
第六题: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! '; ?>

  题目说是sha1函数的绕过,sha1和md5都是在同时期被爆出加密数组返回NULL的漏洞,所以这道题和md5的思路一样。
参考payload:?name[]=1&password[]=2
第七题:md5加密相等绕过 焦点:

$a != 'QNKCDZO' && $md51 == $md52
<?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";} ?>

  解题思路是查看QNKCDZO的md5值,发现是0e开头的字符串,php在判断所有0e开头的字符串都认为是相等的,所以再找出一个字符串md5得值也是0e开头即可。("==“为等于运算符,”==="为全等运算符,===更为严格,使用===时将不会出现该错误)
参考payload:?a=s878926199a

第八题:十六进制与数字比较

<?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); ?>

  该题目不允许输入1-9的数字,并且输入的数据要与$number的值相等,因为是"==",所以可以采用16进制输入
num = 3735929054
print (’%#x’%num)
输出结果为:0xdeadc0de 参考:?password=0xdeadc0de

第九题: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 '; } } ?>

  这道题目可以用一个简单的思路去解,首先,数组恒大于数字,其次,用strlen测量数组长度返回值为NULL,同样用strpos返回值也是NULL,然后本题目用的是严格的运算符号 “===“和”!==”,ereg返回值为false没问题,NULL !== FALSE也没问题,所以题目就很好解了。
参考payload:?password[]= 或 ?password[]=%00
第十题: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,上数组报错false没问题,同样是strpos返回NULL,上数组返回NULL !== FALSE没毛病。
参考payload:?ctf[]= 体现ereg的%00绕过可以这样构造:?ctf[]=%00

第十一题:弱类型整数大小比较绕过

$temp = $_GET['password']; is_numeric($temp)?die("no numeric"):NULL; if($temp>1336){ echo $flag;

  分析:传入password赋值给temp,is_numeric判断temp是不是数字,是则die,不是数字就继续向下运行,再就是传入的值必须大于1336,上边提到过,数组在比较中恒大于具体的值,并且数组不是数字或者文本型数字,可以绕过数字检测。
参考:?password[]=

第十二题:数字验证正则绕过

<?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; } } ?>

  preg_match在应用于数组时必然为0,所以42在处理后是0,传入数组passwod[]得解
参考:password[]

猜你喜欢

转载自blog.csdn.net/CliffordR/article/details/82974027
今日推荐