taisho3日記

WriteUpなど。

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