一道代码审计的题目,先贴出来源码
<?php
error_reporting(0);
if(!isset($_GET['msg'])){
highlight_file(__FILE__);
die();
}
@$msg = $_GET['msg'];
if(@file_get_contents($msg)!=="Hello Challenge!"){
die('Wow so rude!!!!1');
}
echo "Hello Hacker! Have a look around.\n";
@$k1=$_GET['key1'];
@$k2=$_GET['key2'];
$cc = 1337;$bb = 42;
if(intval($k1) !== $cc || $k1 === $cc){
die("lol no\n");
}
if(strlen($k2) == $bb){
if(preg_match('/^\d+$/', $k2) && !is_numeric($k2)){
if($k2 == $cc){
@$cc = $_GET['cc'];
}
}
}
list($k1,$k2) = [$k2, $k1];
if(substr($cc, $bb) === sha1($cc)){
foreach ($_GET as $lel => $hack){
$$lel = $hack;
}
}
$b = "2";$a="b";//;1=b
if($$a !== $k1){
die("lel no\n");
}
echo "Good Job ;)";
// TODO
// echo $flag;
?>
逐行审计一下代码
首先要以GET方式传入变量msg
,否则会直接退出当前脚本并显示当前的页面的源码
file_get_contents
是用来将文件的内容读入到一个字符串中的首选方法,当其解析的字符串为php://input伪协议时,会保存我们以POST方式传入的Hello Challenge
即可完成验证。
联想到今年校赛使用的data协议,我们也可以将msg赋值为data://text/plain,Hello Challenge
,同样也可以完成验证。
此处需要我们传入的$k1
不等于1337但intval($k1)
需要等于1337,intval函数起到的作用是返回变量的整数值
我们可以看到当传入的值为字符串时会截取字母前的数字,我们只要依葫芦画瓢传入k1
的值1337e10
接着传入的$k2
的长度需要是42,然后就是题目最坑的一点了我们都知道正则匹配的结尾符号是$
,但此题的结尾符号为$
,就导致了不知道该怎么进行绕过的情况,采用数组绕过的话无法通过字符串长度的限制,原本以为此题要求变量k2从头至尾经过正则匹配都要是数字然后is_numeric
判断不为数字,一时想不到解决办法。看到了此题的坑点之后直接使用payload:000000000000000000000000000000000001337%EF%BC%84
,最后的%EF%BC%84
为$
的url编码。之后我们就可以对变量$cc
重新赋值。
首先是
substr($cc, $bb) === sha1($cc)
先使用substr截取修改过后$cc
的前$bb
位需要等于$cc
的sha1
值,我们可以传入数组使这两种函数的返回值均为NULL进行绕过。接着我们就可以使用变量覆盖,将k1的值覆盖为2即可读取flag。