前言
南宁杯是我第一次打CTF比赛,当时PHP基础比较薄弱,回头看看几题。
<?php
$white_list = range(0, 9);
require_once ('flag.php');
if (isset($_REQUEST['no'])) {
$a = $_REQUEST['no'];
if (@ereg("^[0-9]+$", $a) === FALSE) {
echo 'no must be number';
} else {
if (in_array($a, $white_list)) {
if (strlen($a) > 1) {
echo 'you are a great dark phper<br>';
echo "<img src='dark.gif'><br>";
echo $flag;
} else {
echo 'you no dark';
}
} else {
echo 'you are so dark';
}
}
}
else
highlight_file(__FILE__);
?>
题目解析
当时是解出来这道题了,但是并没有懂得其中原理,我当时的payload是
?no=1%00--0,2,3,4,5,6,7,8,9
当时我以为是我传进来一个数组然后通过了 比较,但是其实并不是这样的,我传进去的仍然是一个字符串,但是为什么能够通过比较呢?这里in_array存在一个弱类型比较的问题,in_array存在三个参数:mixed:类型 支持做种复合类型,参数传入也是可以是int,str,float,array haystack: 源数组,查找的数组。 strict : 参数接受两个 true 和false 两个参数.该参数主要检查 $needle 和$haystack 中的value 的类型是否一致。
如果第三个参数没使用true的话那么就会进行比较宽松的比较, 由于 PHP 是弱类型语言,在对两个不同类型的值进行操作(比较运算)时,会存在数据类型的 隐式转化。 那么我插入%00应该相当于1+空格,那么字符串长度就会大于1这样就会绕过大于一的限制,但是同时后面加入任何数都会转化为同类型进行比较,string类型全部转化为0那么也能够通过比较。这里相当于,
‘a'==’0?==>0==0
,但是为什么用%00这是因为ereg函数存在一个截断的漏洞。这样可以直接绕过这个函数的检测。当然另外一个payload也可以通过检测:?no=01
原因相似延伸-PHP弱类型比较
strcmp()函数
<?php $password="XXXXXXX"; if(isset($_POST['password'])){ if (strcmp($_POST['password'], $password) == 0) { echo "Right!!!login success"; exit(); } else { echo "Wrong password.."; } } ?>
这里其实存在一个漏洞,
strcmp()
函数其实本质是将字符串转化为ASCII码再相减作,如果相减为0那么就是通过匹配,但是这里如果传入的的值并不是字符串类型同样会返回FLASE(0)进而通过比较,那么最后的payloadpassword[]=0
.switch()函数
<?php $i ="3name"; switch ($i) { case 0: case 1: case 2: echo "this is two"; break; case 3: echo "flag"; break; } ?>
这里其实,
switch()
函数在进行case比较时候回将传入的字符串转化为整数型再进行比较。所以最终输出的是flag,这里和intval()
一致。MD5() 、sha1()
<?php if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) if (md5($_POST['a']) === md5($_POST['b'])) die('Flag: '.$flag); else print 'Wrong.'; } ?>
这两个函数在本次海啸杯也考察到了,不能处理数组,传入两个数组即可将其绕过。
json
<?php if (isset($_POST['message'])) { $message = json_decode($_POST['message']); $key ="*********"; if ($message->key == $key) { echo "flag"; } else { echo "fail"; } } else{ echo "~~~~"; } ?>
其实这个本质也是弱类型比较。只需构造
message={'key':0}
十六进制比较问题
<?php function noother_says_correct($number) { $one = ord('1'); $nine = ord('9'); for ($i = 0; $i < strlen($number); $i++) { $digit = ord($number{$i}); if ( ($digit >= $one) && ($digit <= $nine) ) { return false; } } return $number == '54975581388'; } $flag='*******'; if(noother_says_correct($_GET['key'])) echo $flag; else echo 'access denied'; ?>
这道题的意思就是要求输入一个key,然后这个key必须等于
54975581388
但是在自定义的函数里面又不允许出现数字,正好54975581388=0xccccccccc
这样就绕过了检测。HASH比较操作符问题
"0e132456789"=="0e7124511451155" //true "0e1abc"=="0" //true4219903
上面的比较确实会通过,那么为什么呢,在比较的时候,当出现xex模式,即匹配:
0e\d+
的 字符串将会当做科学计数法进行比较。<?php if (isset($_GET['Username']) && isset($_GET['password'])) { $logined = true; $Username = $_GET['Username']; $password = $_GET['password']; if (!ctype_alpha($Username)) {$logined = false;} if (!is_numeric($password) ) {$logined = false;} if (md5($Username) != md5($password)) {$logined = false;} if ($logined){ echo "successful"; }else{ echo "login failed!"; } } ?>
payload:
md5('240610708') == md5('QNKCDZO')