在網路攻擊的偵察階段,攻擊者常使用 DNS 查詢來取得目標系統資訊。本文介紹如何利用 Python 建構名為 HoneyResolver 的 DNS 伺服器,作為蜜罐誘騙攻擊者。HoneyResolver 能夠針對不同的子網域名稱傳回不同的 DNS 解析結果,將可疑的查詢導向蜜罐,同時確保合法子網域名稱解析正常運作。此方法能有效收集攻擊者的行為資訊,並降低真實系統遭受攻擊的風險。透過 Python 的 dnslib 函式庫,我們可以輕鬆建立客製化的 DNS 伺服器,並根據需求設定解析規則。結合蜜罐技術,HoneyResolver 能夠在網路安全防禦中扮演重要的角色,提供更主動的防禦策略。
實作DNS欺騙以誘導攻擊者進入蜜罐
在網路安全領域,攻擊者在發起攻擊前通常會進行大量的偵察工作,以收集目標系統的資訊。DNS(Domain Name System)查詢是攻擊者常用的偵察手段之一,因為它可以洩露目標系統的結構和服務資訊。本篇文章將探討如何利用Python實作一個簡單的DNS伺服器,即HoneyResolver,用於誘導攻擊者存取蜜罐(honeypot),從而達到欺騙和監控的目的。
HoneyResolver的設計與實作
HoneyResolver的主要目標是對合法的子網域名稱傳回正確的DNS解析結果,而對其他子網域名稱則傳回指向蜜罐的IP地址。以下是實作HoneyResolver的關鍵步驟和程式碼片段。
初始化DNS伺服器
首先,需要匯入必要的函式庫,包括dnslib,它提供了建立DNS伺服器所需的類別和函式。
from dnslib import *
from dnslib.server import DNSServer
import time
host = "localhost"
port = 8053
subdomains = {
"www.": "10.0.0.1",
"smtp.": "10.0.0.2"
}
domain = "example.com"
honeyip = "10.0.0.0"
class HoneyResolver:
def resolve(self, request, handler):
# 解析請求的子網域名稱
subdomain = str(request.q.qname.stripSuffix(domain + "."))
# 根據子網域名稱是否在合法列表中傳回不同的DNS回應
if subdomain in subdomains:
reply = request.reply()
ip = subdomains[subdomain]
reply.add_answer(RR(
rname=request.q.qname,
rtype=QTYPE.A,
rclass=1,
ttl=300,
rdata=A(ip)))
else:
reply = request.reply()
reply.add_answer(RR(
rname=request.q.qname,
rtype=QTYPE.A,
rclass=1,
ttl=300,
rdata=A(honeyip)))
return reply
# 初始化並啟動DNS伺服器
resolver = HoneyResolver()
server = DNSServer(resolver, port=port, address=host)
server.start_thread()
# 保持伺服器執行直到手動停止
while True:
time.sleep(5)
server.stop()
#### 內容解密:
- 初始化DNS伺服器:使用
dnslib函式庫建立一個DNS伺服器,並指定其執行在本地的8053埠。 - 定義子網域名稱解析規則:在
subdomains字典中定義了合法子網域名稱的解析結果,例如www.example.com解析到10.0.0.1。 - 處理DNS請求:
HoneyResolver類別中的resolve方法負責處理收到的DNS請求,根據請求的子網域名稱是否在subdomains中傳回相應的DNS回應。 - 傳回DNS回應:對於合法的子網域名稱,傳回正確的IP地址;對於其他子網域名稱,則傳回蜜罐的IP地址
10.0.0.0。
組態DNSExploration使用HoneyResolver
為了測試HoneyResolver,需要修改DNSExploration指令碼,使其使用HoneyResolver作為DNS伺服器。
res.nameservers = ["127.0.0.1"]
res.port = 8053
domain = "example.com"
nums = False
#### 內容解密:
- 設定DNS伺服器:將DNS解析請求傳送到本地的8053埠,即HoneyResolver。
- 指定查詢網域名稱:設定要查詢的網域名稱為
example.com。 - 停用子網域名稱數字擴充套件搜尋:將
nums設為False,以避免擴充套件數字子網域名稱搜尋。
測試與結果
執行HoneyResolver後,再執行DNSExploration,將會看到如下結果:
www.example.com: ['10.0.0.1']
mail.example.com: ['10.0.0.0']
remote.example.com: ['10.0.0.0']
...
smtp.example.com: ['10.0.0.2']
#### 內容解密:
- 驗證解析結果:結果顯示,合法子網域名稱(如
www.和smtp.)被正確解析,而其他子網域名稱則被導向蜜罐IP10.0.0.0。 - 達成欺騙目的:透過HoneyResolver,成功地將非法的子網域名稱查詢導向了蜜罐,從而達到了欺騙攻擊者的目的。
強化HoneyResolver功能
目前實作的HoneyResolver功能相對簡單,未來可以考慮新增更多功能以增強其誘騙能力,例如:
支援更多DNS記錄型別:目前HoneyResolver僅支援A記錄,可以擴充套件至支援其他型別的DNS記錄,如MX、CNAME等,以模擬更真實的DNS解析服務。
動態調整解析結果:根據實際需要或特定條件動態改變解析結果,例如根據來源IP或查詢頻率調整回應內容,以增加誘騙的多樣性。
整合更多誘騙技術:結合其他誘騙技術,如HTTP誘騙服務、SMTP誘騙服務等,建立一個完整的網路誘騙系統,以更有效地吸引和監控攻擊者。
提升偵測與防禦能力
除了誘騙攻擊者外,如何有效地偵測和防禦潛在的攻擊也是非常重要的。未來可以結合機器學習或異常流量分析技術,對透過HoneyResolver收集到的資料進行深入分析,以識別新型攻擊模式或潛在威脅。
異常流量分析:利用機器學習演算法分析指向蜜罐的流量,識別出異常模式,可能對應於新的攻擊手法或工具。
與現有安全系統整合:將HoneyResolver收集到的情報與現有的安全資訊和事件管理(SIEM)系統或其他安全工具整合,提升整體的安全監控和事件回應能力。
結語
透過實作和佈署如HoneyResolver這樣的誘騙工具,組織可以主動出擊,不僅能夠吸引並監控潛在的攻擊者,還能從中學習並提升自身的安全防禦能力。隨著網路威脅的不斷演變,持續創新和最佳化誘騙技術與防禦策略將是未來網路安全領域的重要課題。
取得初始存取許可權
在第一章「實作攻擊前的目標」中,我們討論了攻擊者如何執行偵察並開發出執行攻擊所需的資源。在規劃攻擊並將這些資源投入使用後,下一步是嘗試取得目標環境的存取許可權。這個目標在MITRE ATT&CK框架中被描述為初始存取戰術。如圖2.1所示,該戰術包括九種技術,詳細描述了攻擊者可以實作初始存取的各種方式。
有效帳戶
有效帳戶技術利用了目標系統上必須存在使用者和機器帳戶的事實。如果攻擊者能夠猜測或以其他方式取得這些帳戶的憑證,他們就可以輕易地透過驗證為合法使用者來存取系統。
發現預設帳戶
測試有效的預設帳戶最好透過網路進行。多種不同的協定允許遠端存取電腦,包括RDP、SSH和Telnet。FTP、SMTP和許多網站都需要使用者身份驗證才能存取受保護的功能。使用這些系統的身份驗證入口,攻擊者可以測試一組憑證是否對特定裝置有效。
TestDefaultCredentials.py
import paramiko
import telnetlib
import socket
def SSHLogin(host, port, username, password):
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, port=port, username=username, password=password)
ssh_session = ssh.get_transport().open_session()
if ssh_session.active:
print("SSH登入成功於 %s:%s 使用使用者名稱 %s 和密碼 %s" % (host, port, username, password))
ssh.close()
except:
print("SSH登入失敗 %s %s" % (username, password))
def TelnetLogin(host, port, username, password):
tn = telnetlib.Telnet(host, port, timeout=1)
tn.read_until(b"login: ")
tn.write((username + "\n").encode("utf-8"))
tn.read_until(b"Password: ")
tn.write((password + "\n").encode("utf-8"))
try:
result = tn.expect([b"Last login"])
if (result[0] >= 0):
print("Telnet登入成功於 %s:%s 使用使用者名稱 %s 和密碼 %s" % (host, port, username, password))
tn.close()
except (EOFError, socket.timeout):
print("Telnet登入失敗 %s %s" % (username, password))
host = "127.0.0.1"
sshport = 2200
telnetport = 23
with open("defaults.txt", "r") as f:
for line in f:
vals = line.split()
username = vals[0].strip()
password = vals[1].strip()
SSHLogin(host, sshport, username, password)
TelnetLogin(host, telnetport, username, password)
程式碼解析:
此程式碼示例展示了攻擊者如何使用遠端存取協定來測試潛在的帳戶憑證。該程式碼嘗試使用SSH和Telnet協定對目標系統進行身份驗證。
- SSH登入函式:
SSHLogin函式嘗試使用給定的使用者名稱和密碼透過SSH連線到指定的主機和埠。如果連線成功,它會列印成功訊息。 - Telnet登入函式:
TelnetLogin函式嘗試使用給定的使用者名稱和密碼透過Telnet連線到指定的主機和埠。如果連線成功,它會列印成功訊息。 - 讀取預設憑證:程式碼從名為
defaults.txt的檔案中讀取預設的使用者名稱和密碼對,並嘗試使用這些憑證對目標主機進行SSH和Telnet登入。
防禦措施
為了防禦這種攻擊,系統管理員應該:
- 停用或更改預設帳戶的密碼。
- 使用強密碼和多因素身份驗證。
- 限制遠端存取協定的使用,例如關閉不必要的服務或限制存取特定IP。
- 監控異常的登入活動。
使用Python進行預設憑證測試與帳戶監控
預設憑證測試的實務應用
在進行網路安全測試時,攻擊者經常會嘗試使用預設或已知的憑證來嘗試登入遠端服務。本章節將探討如何使用Python來測試SSH和Telnet伺服器是否允許使用預設憑證進行驗證。
從檔案讀取預設憑證
首先,我們需要從一個名為defaults.txt的檔案中讀取預設的使用者名稱和密碼。這個檔案的格式為每行一組憑證,使用者名稱和密碼之間以空格分隔。
with open("defaults.txt", "r") as f:
for line in f:
vals = line.split()
username = vals[0].strip()
password = vals[1].strip()
使用Paramiko進行SSH連線
接下來,我們使用paramiko函式庫來建立SSH連線並測試預設憑證。
import paramiko
def SSHLogin(host, port, username, password):
try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(host, port, username, password)
ssh_session = ssh_client.get_transport().open_session()
if ssh_session.active:
print(f"SSH login successful on {host}:{port} with username {username} and password {password}")
ssh_client.close()
except Exception as e:
print(f"SSH login failed on {host}:{port} with username {username} and password {password}")
#### 內容解密:
- 建立SSH客戶端例項:使用
paramiko.SSHClient()建立一個SSH客戶端。 - 自動新增主機金鑰:使用
set_missing_host_key_policy(paramiko.AutoAddPolicy())來自動新增伺服器的公鑰到信任的主機金鑰列表中。 - 連線到SSH伺服器:使用
connect()方法嘗試連線到SSH伺服器,並傳入主機、埠、使用者名稱和密碼。 - 檢查連線是否活躍:透過檢查
ssh_session.active來判斷是否成功登入。 - 錯誤處理:捕捉任何在連線過程中發生的異常,並列印錯誤訊息。
使用Telnetlib進行Telnet查詢
除了SSH,我們還可以使用telnetlib來測試Telnet伺服器。
import telnetlib
def TelnetLogin(host, port, username, password):
try:
tn = telnetlib.Telnet(host, port)
tn.read_until(b"login:")
tn.write(username.encode('ascii') + b"\n")
tn.read_until(b"Password:")
tn.write(password.encode('ascii') + b"\n")
result = tn.expect([b"Last login"], timeout=1)
if result[0] != -1:
print(f"Telnet login successful on {host}:{port} with username {username} and password {password}")
else:
print(f"Telnet login failed on {host}:{port} with username {username} and password {password}")
tn.close()
except Exception as e:
print(f"Telnet login error on {host}:{port} with username {username} and password {password}")
#### 內容解密:
- 建立Telnet連線:使用
telnetlib.Telnet()建立到Telnet伺服器的連線。 - 傳送使用者名稱和密碼:使用
read_until()等待特定的提示,並使用write()傳送使用者名稱和密碼。 - 檢查登入是否成功:使用
expect()方法等待特定的字串(如"Last login")來判斷登入是否成功。 - 錯誤處理:捕捉任何異常,並列印錯誤訊息。
防禦者的帳戶監控
對於防禦者來說,監控Windows登入嘗試是非常重要的。我們可以使用Python的win32evtlog模組來讀取Windows的安全日誌。
import win32evtlog
def QueryEventLog(eventID):
server = "localhost"
logtype = "Security"
flags = win32evtlog.EVENTLOG_FORWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
logs = []
h = win32evtlog.OpenEventLog(server, logtype)
while True:
events = win32evtlog.ReadEventLog(h, flags, 0)
if events:
for event in events:
if event.EventID == eventID:
logs.append(event)
#### 內容解密:
- 開啟事件日誌:使用
OpenEventLog()開啟指定的事件日誌。 - 讀取事件日誌:使用
ReadEventLog()讀取事件日誌中的記錄。 - 篩選事件:根據事件ID篩選出感興趣的事件。
- 儲存事件:將篩選出的事件儲存到列表中。
透過這些技術,安全測試人員和防禦者可以更好地瞭解和保護他們的系統免受未授權的存取。