- 云原生安全:攻防實踐與體系構建
- 劉文懋 江國龍 浦明 阮博男 葉曉虎
- 1396字
- 2021-11-04 18:12:38
4.5.2 原理描述
前文中我們給出了一種基于ARP欺騙和DNS劫持的攻擊場景。要深入理解這個場景,就需要從Pod視角來看一下場景內的流量是如何流動的。我們以場景中涉及的example.com為例進行講解。
假設某Pod A需要訪問example.com,那么它首先必須知道該域名對應的IP,因此,它需要發出一個DNS查詢請求。向哪里發送呢?默認情況下,Pod的DNS策略為ClusterFirst[1],也就是說,Pod A會向集群DNS服務kube-dns發起請求。DNS請求實際上是一個UDP報文,在我們的例子中,kube-dns服務的IP為10.96.0.10,而Pod A的IP為10.244.0.195,兩者不在同一子網。因此,該UDP報文會被Pod A發送給默認網關,也就是cni0。接著,結合背景知識部分可知,節點iptables對該報文進行DNAT處理,將目的地改為10.244.0.134,也就是CoreDNS Pod的IP地址。
那么,怎么把報文發送過去呢?cni0通過查詢自己維護的MAC地址表,找到10.244.0.134對應的MAC地址,然后將報文發到網橋的對應端口上。CoreDNS Pod收到報文后,向上級DNS服務器查詢example.com的IP,收到結果后向Pod A發出DNS響應。至此,Pod A知道了example.com對應的IP。
接下來,Pod A就可以向example.com對應的IP發出基于TCP的HTTP請求了,這是一個正常的IP路由流程,不再贅述。
如何實施中間人攻擊呢?假如攻擊者想要欺騙Pod A,就應該想辦法讓Pod A以為攻擊者所在的Pod才是DNS服務器。然而,Pod A并未直接向10.244.0.134發出ARP請求,上面過程提到的ARP解析是由cni0負責的。因此,攻擊者只需要讓cni0以為CoreDNS Pod的IP地址10.244.0.134對應的MAC地址為攻擊者所在Pod網卡的MAC地址即可。那么攻擊者可以持續向cni0發送ARP響應幀,告訴cni0,自己才是10.244.0.134。
根據ARP,攻擊者可以按照圖4-15給出的方式構造響應幀,其中,上方是ARP幀格式,下方是攻擊者構造的具體響應幀內容。

圖4-15 ARP響應幀結構
假設攻擊者Pod對cni0網橋的ARP欺騙成功,理論上,稍后它將收到由Pod A發送的DNS查詢請求。后面的攻擊就比較順利了——向Pod A返回DNS響應,聲稱example.com對應的IP地址是自己的IP;很快,它就會收到Pod A對example.com的HTTP請求,此時,攻擊者即可任意定制HTTP響應內容。
至此,原理上似乎沒有問題。但攻擊者在Pod內,怎么獲得cni0網橋和CoreDNS Pod的網絡信息呢?
首先是cni0網橋。網橋的IP和MAC地址獲取方式比較多樣。例如,由于cni0既是網橋又是默認網關,我們可以直接查詢Pod的路由表,獲得網橋IP地址:
root@test:/# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 10.244.0.1 0.0.0.0 UG 0 0 0 eth0 10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 10.244.0.0 10.244.0.1 255.255.0.0 UG 0 0 0 eth0
然后直接查詢ARP緩存,獲得網橋MAC地址。如果沒有,可以先向網橋發送一個ARP請求:
root@test:/# arp -n Address HWtype HWaddress Flags Mask Iface 10.244.0.1 ether 0a:58:0a:f4:00:01 C eth0
或者,也可以直接向集群外部發送一個ICMP消息,設置ttl為1,然后從返回的ICMP消息中同時獲得網橋的IP和MAC地址。相關的Python代碼如下:
from scapy.layers.inet import IP, Ether, ICMP from scapy.sendrecv import srp1 def get_bridge_mac_ip(verbose): res = srp1(Ether() / IP(dst="8.8.8.8", ttl=1) / ICMP(), verbose=verbose) return res[Ether].src, res[IP].src
我們再來看如何獲得CoreDNS Pod的IP和MAC地址。結合背景知識部分DNS內容可知,Pod內部僅僅能拿到一個kube-dns服務的IP,通常是10.96.0.10。但是,如果攻擊者Pod向該服務發送一個DNS查詢請求,實際上是服務背后的CoreDNS Pod來回復DNS響應的(經過DNAT處理,目的地改為CoreDNS Pod)。而DNS響應又是一個UDP報文,因此我們可以從中提取到CoreDNS Pod的MAC地址。但是,DNS響應又會被進行SNAT處理,其中的IP地址被重新替換為kube-dns服務IP10.96.0.10。所以,以上步驟只能讓攻擊者拿到CoreDNS Pod的MAC地址。
如何獲取它的IP地址呢?攻擊者可以向整個子網的每個IP發出ARP請求,收集它們的MAC地址,然后與前面獲得的CoreDNS Pod的MAC地址進行比對,如果一致,則說明對應IP即為CoreDNS Pod的IP。
相關的Python代碼如下:
from scapy.layers.inet import IP, UDP, Ether from scapy.sendrecv import srp1, srp from scapy.layers.dns import DNS, DNSQR def get_coredns_pod_mac_ip(kube_dns_svc_ip, self_ip, verbose): mac = srp1(Ether() / IP(dst=kube_dns_svc_ip) / UDP(dport=53) / DNS(rd=1, qd=DNSQR()), verbose=verbose).src answers, _ = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="{}/24".format(self_ip)), timeout=4, verbose= verbose) for answer in answers: if answer[1].src == mac: return mac, answer[1][ARP].psrc return None, None
原理部分到此結束,下面我們進入實戰環節。
[1] 可以通過“kubectl get pod [POD-NAME] -o yaml”查看。
- 特種木馬防御與檢測技術研究
- 零信任網絡:在不可信網絡中構建安全系統
- Web安全與攻防入門很輕松(實戰超值版)
- Digital Forensics with Kali Linux
- 安全防御入門手冊
- Mastering Reverse Engineering
- 網絡用戶行為的安全可信分析與控制
- Kali Linux高級滲透測試(原書第4版)
- Mastering Python for Networking and Security
- Web代碼安全漏洞深度剖析
- 大數據時代的智慧城市與信息安全
- 零信任安全從入門到精通
- INSTANT Penetration Testing:Setting Up a Test Lab How-to
- 網絡安全等級保護2.0:定級、測評、實施與運維
- 精通Veeam Backup&Replication(原書第2版)