SECCON 2014 長野大会 DNS Security Challenge Writeupその6
■mondai6
○問題文
mondai6.pcapを見て以下の問いに答えて下さい。
問1:攻撃成功している回数は何回か?
答え:
○パケットデータ概要
下記のようなパケットがずっと繰り返し続く。
(凡例)パケットNo ソースIP:ソースポート -> デスティネーションIP:デスティネーションポート Info (補足)
70 192.168.1.100:45143 -> 192.168.1.1:53 Standard query 0x0e0b A www.example.com
71 192.168.1.1:53 -> 192.168.1.100:45143 Standard query response 0x0e0b A 192.168.0.10
72 192.168.1.1:53 -> 192.168.1.100:45143 Standard query response 0x0e0b A 192.168.1.2
73 192.168.1.100:45143 -> 192.168.1.1:53 Standard query 0xfb76 A www.example.com
74 192.168.1.1:53 -> 192.168.1.100:48119 Standard query response 0xfb76 A 192.168.0.10
75 192.168.1.1:53 -> 192.168.1.100:48119 Standard query response 0xfb76 A 192.168.1.2
76 192.168.1.100:53 -> 192.168.1.1:48119 Destination unreachable(port unreachable)
○回答考察
この問題はコードを書かせたいらしいと皆で意見が一致した。。
下記に気をつけてカウントしていく。
・AレコードのクエリーのトランザクションIDを記録し、その後同じトランザクションIDを持つ最初のレスポンスをカウントしていく。
・量が多いため、トランザクションIDが後半で重複する可能性を考慮する
・Destination unreachableがたまに見えるが、レスポンスの2個目の到着時にあて先のポートが閉じている(一つ目がすでに到着するため)とみて無視する(2つのレスポンスはほとんど同時に送出されているが、まれに時間差が長いときにあて先が反応か?)
あとは毎回2つくるレスポンスのうち、どちらが攻撃者のパケットであるか議論した。
(チェックサムが0のものという回答があったが、0だとチェックサムはまだ計算されていないという意味となり、wiresharkでチェックサムが不正なときにつく色にならず、気づいていなかった。。)
192.168.1.2を回答としてもつレスポンスは、問題ファイル中、レコードのTTLが微妙に変化していた(カウントダウンされていた)。
192.168.0.10を回答としてもつレスポンスは、問題ファイル中、レコードのTTLが変化していなかった(固定)。
かつ、フラグの状態から、192.168.1.1はキャッシュDNSと思われる。
よって、後者はキャッシュDNS内で行われるはずのTTLのカウントダウンがされていないため、こちらが不正に偽造されたパケットである可能性がある。
よって、先ほど計算したそれぞれの合計値のうち、192.168.0.10の合計値が回答となる。
答え:1111
コードは主に下記を参考にさせていただきました。
http://stackoverflow.com/questions/13223879/dns-rdata-parsing-with-python
・コード
#!/usr/bin/env python
import dpkt ,socket, sys
if len(sys.argv) < 2 or len(sys.argv) > 2:
print "Usage:\n", sys.argv[0], "filename.pcap"
sys.exit()
f = open(sys.argv[1])
pcap = dpkt.pcap.Reader(f)
id={}
taihi={}
packet_count=0
for ts, buf in pcap:
packet_count += 1
#ether
try: eth = dpkt.ethernet.Ethernet(buf)
except: continue
if eth.type != 2048: continue
#ip
try: ip = eth.data
except: continue
if ip.p != 17: continue
#udp
try: udp = ip.data
except: continue
#dns packet
if udp.sport != 53 and udp.dport != 53: continue
try: dns = dpkt.dns.DNS(udp.data)
except: continue
### dns flag
if dns.qr == dpkt.dns.DNS_Q:
if len(dns.qd) != 0:
for qr in dns.qd:
if qr.name == 'www.example.com':
if dns.id not in id:
id[dns.id]=' '
if dns.qr == dpkt.dns.DNS_R:
if len(dns.an) != 0:
for an in dns.an:
if an.type == dpkt.dns.DNS_A:
if an.name == 'www.example.com':
if dns.id in id:
taihi[packet_count]=socket.inet_ntoa(an.ip)
del id[dns.id]
count=0
count2=0
for k,v in taihi.items():
if v == '192.168.1.2':
count=count+1
if v == '192.168.0.10':
count2=count2+1
print '#count'
print '192.168.1.2 : ' + str(count)
print '192.168.0.10 : ' + str(count2)
・実行結果
#count
192.168.1.2 : 89
192.168.0.10 : 1111