很蠢的一次经历,先上源码:
<?php
error_reporting(0);
include "config.php";
//flag in /
function check_letter($code){
$letter_blacklist = str_split("abcdefghijklmnopqrstuvwxyz1234567890");
for ($i = 0; $i < count($letter_blacklist); $i+=2){
if (preg_match("/".$letter_blacklist[$i]."/i", $code)){
die("xi nei~");
}
}
}
function check_character($code){
$character_blacklist = array('=','\+','%','_','\)','\(','\*','&','\^','-','\$','#','`','@','!','~','\]','\[','}','{','\'','\"',';',' ','\/','\.','\?',',','<',':','>');
for ($i = 1; $i < count($character_blacklist); $i+=2){
if (preg_match("/".$character_blacklist[$i]."/", $code)){
die("tongtong xi nei~");
}
}
}
$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if (!file_exists($dir)) {
mkdir($dir);
}
if (isset($_GET["code"])) {
$code = substr($_GET["code"], 0, 12);
check_letter($code);
check_character($code);
file_put_contents("$dir" . "index.php", "<?php ".$code.$fuxkfile);
echo $dir;
}else{
highlight_file(__FILE__);
}
查看源码可以知道此处的code参数是可控的,然后当时看到file_put_contents()的处理的时候,第一反应是直接将一句话写入index.php,然后文件包含,但是后来看到前面绕过了很多参数,然后后来的尝试也失败了,并且限制了code参数的长度要小于13,所以加上绕过基本无法实现,于是就尝试其他的做法:直接进行命令执行。看到上面的黑名单,这里的for循环实际上是只过滤了其中一半的字符,当时真的没仔细看,大体一过,认为这里是对code进行了一半的检查,然后过滤单数位置的字母数字,后来看到for循环里的blacklist是上面的字母数字的参数,就直接无语了...我是笨b...后面的特殊字符也一样,于是进行命令执行的时候就可以有很多没有被过滤的字符,被放出来的字母和数字有:bdfhjlnprtvxz24680,特殊字符中奇数位的特殊字符被释放出来:=、/、、%、)、^、$、、!等一些,其实到了这里基本上就有思路了,利用nl命令拿flag,payload:?code=?><?=
nl%09/`,这里payload的构造是因为首先闭合前面的<?php,然后写入命令并执行,字母里只有nl和pr被放了出来,通配符的原因是在源码中只存在index.php,所以直接写入,然后访问给出的目录获取flag就可以了。
总结:我是笨b。
评论 (0)