ようこそゲストさん

chibilog

2009/04/16(木) Scapyでネットワーク遊び

はてブ情報 はてブに登録 はてブ数 2009/04/16 28:16 パソコン

Pythonで作られたScapyってやつが恐ろしいほど便利で楽しいのでメモ書きをしておきますよ。導入方法の例は、Ubuntu 8.10。ちなみにaptitudeでScapyのインストールできるけど、v1.2だった気がする。v2.xを使いたいのでaptitudeでScapyのインストールはしないことにする。v2.xを使いたい場合はPythonのバージョンが2.5以上が必要なので先ずシステムに入ってるPythonのバージョンを確認しておく。

$ python -V
Python 2.5.2

続いて、libdnetが必要なのでインストール。

$ sudo aptitude install libdnet

あとは以下のものもインストールしておくと便利なので、aptitudeでインストールしておいたほうがいい。

  • gnuplot
  • tcpdump
  • graphviz
  • imagemagick
  • nmap
  • python-gnuplot
  • python-pyx
  • python-crypto
  • python-visual

Scapyからlatestのzipをダウンロードして以下のようにインストールする。

$ unzip scapy-latest.zip
$ cd scapy-2.0.1
$ sudo python setup.py install

Scapyがあるかどうか確認。

$ which scapy
/usr/bin/scapy

Scapyの実行にはroot権限が必要。試しに実行してみる。

$ sudo scapy 
INFO: No IPv6 support in kernel
WARNING: No route found for IPv6 destination :: (no default route?)
Welcome to Scapy (2.0.1)
>>>

これで使える状態になっているので、試しにls()なんて打ってみるとぞろぞろと出てくる。

>>> ls()
ARP        : ARP
ASN1_Packet : None
BOOTP      : BOOTP
...

Scapyの使い方

パケットキャプチャ

Scapyで色々と遊んでみる。先ずはパケットキャプチャ。

>>> sniff(iface="eth0", prn=lambda x: x.show())
###[ IP ]###
    version= 4L
    ihl= 5L
    tos= 0x10    len= 1500
    id= 616
    flags= DF
    frag= 0L
    ttl= 64
    proto= tcp
    chksum= 0xab7d
    src= 192.168.0.250    dst= 192.168.0.220
    options= ''
...

sniff()を使えば上記のような出力が得られる。もっと簡単な表示でいい場合は、show()ではなくて、summary()を使う。

>>> sniff(iface="eth0", prn=lambda x: x.summary())
Ether / IP / TCP 192.168.0.250:ssh > 192.168.0.220:61264 PA / Raw
Ether / IP / TCP 192.168.0.250:ssh > 192.168.0.220:61264 PA / Raw

hpingみたいなポートへのping

>>> ans,unans = sr(IP(dst="192.168.0.200", ttl=7)/TCP(dport=[21,22,25,53,80,110,143,443,445]), retry=-2)
Begin emission:......*.......*.......*......*......*........*.........*.......Finished to send 9 packets.
.*.........*
Received 75 packets, got 9 answers, remaining 0 packets

>>> ans.make_lined_table(lambda(s,r): (s.dport, s.dst, r.sprintf("%IP.id% {TCP:%TCP.flags%}{ICMP:%IP.src% %ir.ICMP.type%}")))
 --------------+------+------+------+------+------+------+------+------+------+
              | 21   | 22   | 25   | 53   | 80   | 110  | 143  | 443  | 445  |
 --------------+------+------+------+------+------+------+------+------+------+
192.168.0.200 | 0 SA | 0 SA | 0 SA | 0 RA | 0 SA | 0 RA | 0 RA | 0 SA | 0 RA |
 --------------+------+------+------+------+------+------+------+------+------+

もっと簡単な出力でいいなら、以下のようにやっちゃう。

>>> sr(IP(dst="192.168.0.200")/TCP(dport=[22,23,80]))
Begin emission:
.........*.....*....Finished to send 3 packets.
.....*
Received 26 packets, got 3 answers, remaining 0 packets(<Results: TCP:3 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)

>>> ans,unans=_
>>> ans.summary()
IP / TCP 192.168.0.250:ftp_data > 192.168.0.200:ssh S ==> IP / TCP 192.168.0.200:ssh > 192.168.0.250:ftp_data SA / Padding
IP / TCP 192.168.0.250:ftp_data > 192.168.0.200:telnet S ==> IP / TCP 192.168.0.200:telnet > 192.168.0.250:f
tp_data RA / Padding
IP / TCP 192.168.0.250:ftp_data > 192.168.0.200:www S ==> IP / TCP 192.168.0.200:www > 192.168.0.250:ftp_dat
a SA / Padding

flagsがSAならポートが開いていて、RAであれば閉じている。


PDFも作れる

>>> p=IP()/ICMP()
>>> p.pdfdump("test.pdf")

たったこれだけなのに、何だかそれっぽいPDFが出来上がってくれるw


traceroute

>>> ans,unans = traceroute("www.yahoo.co.jp", dport=80)
Begin emission:
 **************************Finished to send 30 packets.
 ****
Received 30 packets, got 30 answers, remaining 0 packets
   203.216.235.201:tcp80 
1  192.168.0.1     11    
2  122.1.164.132   11    
3  122.1.164.129   11    
4  221.184.12.189  11    
5  60.37.11.141    11    
6  60.37.54.161    11    
7  60.37.54.206    11    
8  210.254.187.38  11    
9  210.163.230.86  11    
10 118.155.197.141 11    
11 124.211.14.22   11    
12 202.93.74.223   11    
13 203.216.238.194 11    
14 203.216.235.201 SA    
15 203.216.235.201 SA    
16 203.216.235.201 SA    
17 203.216.235.201 SA    
18 203.216.235.201 SA    
19 203.216.235.201 SA    
20 203.216.235.201 SA    
21 203.216.235.201 SA    
22 203.216.235.201 SA 
23 203.216.235.201 SA
24 203.216.235.201 SA
25 203.216.235.201 SA
26 203.216.235.201 SA
27 203.216.235.201 SA
28 203.216.235.201 SA
29 203.216.235.201 SA
30 203.216.235.201 SA

ルーティング関連の操作

現在のルーティング情報の確認。netstat -rn, route -n の出力と同じようなものが出てくる。

>>> conf.route
Network         Netmask         Gateway         Iface           Output IP
127.0.0.0       255.0.0.0       0.0.0.0         lo              127.0.0.1
192.168.0.0     255.255.255.0   0.0.0.0         eth0            192.168.0.250
169.254.0.0     255.255.0.0     0.0.0.0         eth0            192.168.0.250
0.0.0.0         0.0.0.0         192.168.0.1     eth0            192.168.0.250

指定したルーティング情報を削除してみる。その後に確認。

>>> conf.route.delt(net="0.0.0.0/0", gw="192.168.0.1")
>>> conf.route
Network         Netmask         Gateway         Iface           Output IP
127.0.0.0       255.0.0.0       0.0.0.0         lo              127.0.0.1
192.168.0.0     255.255.255.0   0.0.0.0         eth0            192.168.0.250
169.254.0.0     255.255.0.0     0.0.0.0         eth0            192.168.0.250

ルーティング情報を追加してみる。その後に確認。

>>> conf.route.add(host="192.168.1.100", gw="192.168.0.220")
>>> conf.route
Network         Netmask         Gateway         Iface           Output IP
127.0.0.0       255.0.0.0       0.0.0.0         lo              127.0.0.1
192.168.0.0     255.255.255.0   0.0.0.0         eth0            192.168.0.250
169.254.0.0     255.255.0.0     0.0.0.0         eth0            192.168.0.250
192.168.1.100   255.255.255.255 192.168.0.220    eth0            192.168.0.250

最初の状態に戻す。

>>> conf.route.resync()
>>> conf.route
Network         Netmask         Gateway         Iface           Output IP
127.0.0.0       255.0.0.0       0.0.0.0         lo              127.0.0.1
192.168.0.0     255.255.255.0   0.0.0.0         eth0            192.168.0.250
169.254.0.0     255.255.0.0     0.0.0.0         eth0            192.168.0.250
0.0.0.0         0.0.0.0         192.168.0.1     eth0            192.168.0.250

DHCPサーバを見つける

DHCP discover requestを送ることができる。

>>> conf.checkIPaddr = False
>>> fam,hw = get_if_raw_hwaddr(conf.iface)
>>> dhcp_discover = Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"), "end"])

以下を実行後は、数秒後にCTRL-C して止める
>>> ans,unans = srp(dhcp_discover, multi=True)

結果の出力
>>> ans.summary()
Ether / IP / UDP 0.0.0.0:bootpc > 255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP / UDP 192.168.0.1:bootps > 255.255.255.255:bootpc / BOOTP / DHCP

>>> for p in ans: print p[1][Ether].src, p[1][IP].src
...           
00:0a:79:aa:aa:aa 192.168.0.1

こんな感じで色々と遊べます。ARP Cache Poisoningなんかもできたり。便利だし遊べるのでインストールしておいて損は無いですよ。


【参考サイト】



名前:  非公開コメント   

URL(任意):
  • TB-URL  http://chibilog.name/0365/tb/