天天看點

使用菜刀HTTP流量代理繞過WAF

在實際的滲透測試中,Webshell真正免殺的第一步就是確定 Webshell 的源腳本免殺,其次是傳輸内容的編碼混淆。

在實際的滲透過程中,我們常常因為WAF而頭疼。源碼免殺了而傳輸層卻被攔截了實在難受。雖然現在很多優秀的應用。如蟻劍,C刀,冰蠍等。本文就通過在不修改程式源碼,不重複造輪子,代碼量最少的前提下實作類似冰蠍的加密傳輸。

但僅将 request 包内容進行編碼,發送到伺服器是遠遠不夠的;部分 WAF 或者資訊防洩漏系統還會對網頁的 response 傳回包流量進行檢測。這時候,無論源腳本的免殺構造多精巧,request 包編碼的多複雜,response 傳回的明文内容都會暴露它是一個徹底的 Webshell 腳本。

目前網絡上一些公開用戶端,通常僅支援 request 包的自定義編碼功能,伺服器的代碼執行 response 結果通常是明文狀态,且無法定義方法進行服務端 response 内容的編碼,并最後解碼後展示執行結果。

本篇文章主要分享自己為解決以上問題,根據 caidao.exe,編寫普适的本地代理腳本—CaiDaoProxy.py,繞過WAF和流量檢測軟體對一句話 Webshell 檢測的相關思路。

使用 caidao.exe (20160620 版 MD5: AC86066FFD58779F4C0DB5030574B0CB) 進行 CaiDaoProxy.py 的開發大緻有以下幾個原因:

  • 20160620 版本後的 caidao.exe 擁有配置檔案,可以直接修改配置檔案中發往伺服器的語句
  • 中間人 Proxy 攔截修改模式對流量的可操作性較強,可随意修改發送包和響應包的任意内容
  • 避免為解決中間流量編碼混淆等問題重複造輪子,制作 "新型菜刀" 用戶端
  • 表面用的是普通的 caidao.exe,其實用的是過WAF版的CaiDaoProxy。

原理

一言以蔽之:CaiDaoProxy.py 是一個中間人HTTP流量代理腳本。

它可以在 caidao.exe 發送給目标的 request 内容、目标傳回給 caidao.exe 的 response 内容上進行修改,以完成在僅修改菜刀配置檔案 caidao.conf 的基礎上,結合特定的 Webshell 完成目标到 caidao.exe 之間的流量編碼混淆,達到躲過 webshell 流量檢測的目的。

配合基礎的免殺源檔案,将躲過大部分 Webshell 檢測軟體和監測平台的 Webshell 發現手段。其實作原理主要如下圖所示:

使用菜刀HTTP流量代理繞過WAF

可以發現,發送到服務端 www.example.com 的請求是編碼混淆過的,服務端的響應也是編碼混淆過的。

對于一些 WAF 和主機流量防護軟體來說,原來的caidao 請求特征值"z0"、"z1"、"z2",分隔符 "[email protected]"及其它敏感内容(實體路徑、執行指令結果等)都無法輕易檢測到了。

源檔案免殺

前言中講了,在有檔案的 Webshell 中,源檔案免殺是第一步。源檔案免殺的php、asp一句話腳本參考我以前寫的 文章 構造起來不算困難。

但一句話形式的(實際文本内容比較多) JSP Webshell 網絡公開講繞過檢測的比較少,是以分享一個比較簡單的 JSP Webshell免殺方法—unicode編碼。

這裡 提供一個 caidao.exe 20160620 及以後版本 (預設分隔符: [email protected]) 可正常連接配接,源檔案免殺的 jsp 一句話示例腳本,密碼: 

LandGrey

原理是 Java 編譯器可将 unicode 編碼的 java 源代碼 (下圖所示的 jsp 中的 "\uxxxx" 形式的 unicode 編碼後的代碼) 正常編譯成 class檔案。

使用菜刀HTTP流量代理繞過WAF

将提供的 Webshell 放在伺服器上,通路後打開 Tomcat 的 work 編譯目錄,可發現反編譯後正常的 class 檔案和 unicode 編碼的 java 源代碼檔案。

使用菜刀HTTP流量代理繞過WAF

傳輸内容加密

這裡的傳輸内容加密是指:

以伺服器的角度來看:用戶端發送給它的 request 包中的 POST 參數名和參數值無法輕易知曉其含義;

并且伺服器傳回給用戶端的 response 包中的内容也無法輕易知曉其含義。

随着攻防對抗的更新,現在的 Webshell 用戶端都有較為原始的"傳輸内容加密"政策,比如 caidao.exe 預設将發送的部分内容進行一次 base64 編碼、16進制轉碼等,但現在預設的這些小 trick,在躲避檢測上起到的作用越來越小,一些防護軟體會嘗試簡單的各種簡單方式解碼,還原成明文的内容,然後再檢測傳輸内容是否異常。

限于篇幅,php 、asp等腳本的 CaiDaoProxy.py 實作隻介紹其思路,重點說明 jsp 一句話 Webshell 流量加密的 CaiDaoProxy.py 實作方法。

CaiDaoProxy 的 HTTP 代理功能可使用 Python 的 BaseHTTPServer 基礎庫完成,預設監聽本地一個端口,比如 9000;然後 caidao.exe 位址欄填入 

http://127.0.0.1:9000/?=http://www.example.com/webshell.jsp

,真正請求位址由 CaiDaoProxy 剝離出來即可。

  • 對于常見的 php、asp、aspx等一句話 webshell 來說:
  1. 可在 caidao.exe 向服務端發送 request 包時,用CaiDaoProxy.py 攔截請求,随機化參數名并組合兩種及以上不同的簡單編碼(如php的 base64_encode -> strrev-> base64_encode),編碼參數值來混淆請求流量,然後再發給服務端;
  2. 服務端 Webshell 根據編碼方式,解碼請求值,并在服務端執行;
  3. 可更改 caidao.conf 檔案或者在 CaiDaoProxy.py 腳本中統一修改發往服務端執行的代碼,将服務端執行的内容輸出 

    print

     或者 

    echo

    值進行相應編碼;
  4. CaiDaoProxy.py 腳本攔截到編碼後的服務端輸出,根據編碼方法,統一解碼後傳回給 caidao.exe 即可。
  • 對于 jsp 一句話 Webshell 來說:主要邏輯都在服務端的 jsp 腳本中,是以我們可以選擇基礎的對稱加密算法 DES 來加密通信流量。然後可約定加解密方法:
  1. CaiDaoProxy 發送請求前,進行 DES加密 -> Base64編碼
  2. 服務端接收請求後,進行 Base64解碼 -> DES解密
  3. 服務端輸出響應結果時,進行 DES加密 -> Base64編碼
  4. CaiDaoProxy 接收響應後,進行 Base64解碼 -> DES解密

服務端關鍵加解密代碼:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.SecretKeyFactory;
import java.security.SecureRandom;

// 密鑰
String DesKey = "LandGrey";

// DES 加密函數
byte[] DesEncrpyt(String content) {
  try {
    SecureRandom random = new SecureRandom();
    DESKeySpec desKey = new DESKeySpec(DesKey.getBytes());
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
    SecretKey securekey = keyFactory.generateSecret(desKey);
    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
    return cipher.doFinal(content.getBytes());
  } catch (Throwable e) {
    e.printStackTrace();
  }
  return null;
}

// DES 解密函數
byte[] DesDecrpyt(byte[] content) {
  try {
    SecureRandom random = new SecureRandom();
    DESKeySpec desKey = new DESKeySpec(DesKey.getBytes());
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
    SecretKey securekey = keyFactory.generateSecret(desKey);
    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.DECRYPT_MODE, securekey, random);
    return cipher.doFinal(content);
  } catch (Throwable e) {
    e.printStackTrace();
  }
  return null;
}
           

CaiDaoProxy 關鍵加解密代碼:

import base64
from pyDes import des, ECB, PAD_PKCS5

// 密鑰
DesKey = "LandGrey"

// DES加解密類
class DesCipher:
    def __init__(self, secret_key):
        self.secret_key = secret_key

    def encrypt(self, s):
        iv = self.secret_key
        k = des(self.secret_key, ECB, iv, pad=None, padmode=PAD_PKCS5)
        en = k.encrypt(bytes(s), padmode=PAD_PKCS5)
        return en

    def decrypt(self, s):
        iv = self.secret_key
        k = des(self.secret_key, ECB, iv, pad=None, padmode=PAD_PKCS5)
        de = k.decrypt(s, padmode=PAD_PKCS5)
        return de
           

然後,就可以參考本文 0x03:源檔案免殺 的思路,将新的支援流量加解密的 jsp 一句話 Webshell 進行 unicode 編碼,一個簡單的源檔案免殺和通信流量加密的 JSP 一句話 Webshell 就制作完成了。

CaiDaoProxy.py 使用效果圖:

使用菜刀HTTP流量代理繞過WAF
使用菜刀HTTP流量代理繞過WAF

後記

在編寫通用的有檔案一句話 Webshell HTTP 代理 CaiDaoProxy 過程中,相當自己又梳理了一遍 caidao.exe 工具的基本原理,對後面更進階的 Webshell Detect Bypass 技術的學習大有裨益。

雖然這種源腳本和流量都免殺的一句話已經适應較多繞過檢測的場景,但當防護軟體有程序監控、元件監控或 RASP 功能時,如果使用 caidao.exe 的虛拟終端功能,有極大機率會被檢測出來,這也是目前一個比較重要,且需要考慮的 Webshell Bypass 問題。

繼續閱讀