關於Scapy
Scapy的是一個強大的交互式數據包處理程序(使用python編寫)。它能夠僞造或者解碼大量的網絡協議數據包,能夠發送、捕捉、匹配請求和回覆包等等。它可以很容易地處理一些典型操作,比如端口掃描,tracerouting,探測,單元測試,攻擊或網絡發現(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,tethereal,P0F等)。最重要的他還有很多更優秀的特性——發送無效數據幀、注入修改的802.11數據幀、在WEP上解碼加密通道(VOIP)、ARP緩存攻擊(VLAN)等,這也是其他工具無法處理完成的。
安裝Scapy
這裏我沒有使用安裝包進行安裝,而是直接使用 命令 apt-get install python-scapy,根據提示安裝相應的數據包,這裏我使用的ubuntu 14.04,使用的安裝包如下:
tcpreplay graphviz imagemagick python-gnuplot python-pyx ebtables python-visual sox xpdf gv hexer librsvg2-binp
>>> conf.verb=2
ython-pcapy
安裝完畢後測試結果如下:
walfred@walfred-VirtualBox:~/wmw/scapy/test$ sudo scapy
Welcome to Scapy (2.2.0)
>>> IP()
<IP |>
>>> target="www.baidu.com"
>>> ip=IP(dst=target)
>>> ip
<IP dst=Net('www.baidu.com') |>
>>> [p for p in ip]
[<IP dst=180.97.33.107 |>]
>>>
Scapy的使用特性
1、conf 變量保存了配置信息
>>> conf
ASN1_default_codec = <ASN1Codec BER[1]>
AS_resolver = <scapy.as_resolvers.AS_resolver_multi instance at 0xb5fd4c0c>
BTsocket = <BluetoothL2CAPSocket: read/write packets on a connected L2CAP ...
L2listen = <L2ListenSocket: read packets at layer 2 using Linux PF_PACKET ...
L2socket = <L2Socket: read/write packets at layer 2 using Linux PF_PACKET ...
L3socket = <L3PacketSocket: read/write packets at layer 3 using Linux PF_P...
auto_fragment = 1
checkIPID = 0
checkIPaddr = 1
checkIPsrc = 1
check_TCPerror_seqack = 0
color_theme = <RastaTheme>
commands = arpcachepoison : Poison target's cache with (your MAC,victim's ...
debug_dissector = 0
debug_match = 0
default_l2 = <class 'scapy.packet.Raw'>
emph = <Emphasize []>
ethertypes = </etc/ethertypes/ ATMMPOA RAW_FR DNA_DL ATMFATE ATALK BPQ X25 P...
except_filter = ''
extensions_paths = '.'
histfile = '/home/walfred/.scapy_history'
iface = 'eth0'
iface6 = 'eth0'
interactive = True
interactive_shell = ''
ipv6_enabled = True
l2types = 0x1 <- Dot3 (802.3) 0x1 <-> Ether (Ethernet) 0xc -> IP (IP) 0x1...
l3types = 0x3 -> IP (IP) 0x800 <-> IP (IP) 0x806 <-> ARP (ARP) 0x86dd <->...
layers = Packet : None NoPayload : None Raw : Raw Padding : Padding ASN1...
load_layers = ['l2', 'inet', 'dhcp', 'dns', 'dot11', 'gprs', 'hsrp', 'inet6'...
logLevel = 20
manufdb = </usr/wireshark/wireshark/manuf/ >
mib = <MIB/ >
neighbor = Ether -> Dot1Q Ether -> IP Dot3 -> LLC Dot3 -> SNAP Dot3 -> IP ...
netcache = arp_cache: 0 valid items. Timeout=120s in6_neighbor: 0 valid it...
noenum = <Resolve []>
padding = 1
prog = display = 'display' dot = 'dot' hexedit = 'hexer' pdfreader = '...
promisc = 1
prompt = '>>> '
protocols = </etc/protocols/ pim ip ax_25 esp tcp ah mpls_in_ip rohc ipv6_o...
raw_layer = <class 'scapy.packet.Raw'>
raw_summary = False
readfunc = None
resolve = <Resolve []>
route = Network Netmask Gateway Iface Output IP 127.0.0.0 255.0.0.0 0.0...
route6 = Destination Next Hop iface src candidates 2400:dd01:3000:10::/6...
services_tcp = </etcrvices-tcp/ kpop zabbix_trapper noclog svn cmip_man b...
services_udp = </etcrvices-udp/ zabbix_trapper noclog cmip_man z3950 root...
session = ''
sniff_promisc = 1
stats_classic_protocols = [<class 'scapy.layers.inet.TCP'>, <class 'scapy.la...
stats_dot11_protocols = [<class 'scapy.layers.inet.TCP'>, <class 'scapy.laye...
stealth = 'not implemented'
temp_files = []
teredoPrefix = '2001::'
teredoServerPort = 3544
use_dnet = False
use_pcap = False
verb = 1
version = '2.2.0'
warning_threshold = 5
wepkey = ''
>>>
更改這些配置信息也比較方便:比如修改verb屬性
>>> conf.verb=2
2、數據操作
>>> IP()
<IP |>
>>> test_ip=IP(dst="192.168.115.188")<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
>>> test_ip.dst
'192.168.115.188'
>>> test_ip.ttl
64
>>> test_ip.ttl=32 修改ttl值
>>> test_ip
<IP ttl=32 dst=192.168.115.188 |>
>>> del(test_ip.ttl) 刪除tt值
>>> test_ip
<IP dst=192.168.115.188 |>
>>> test_ip.ttl 恢復了默認的ttl值
64
>>> test_tcp=TCP()
>>> test_tcp.flags
2
>>> test_tcp.flags="SA"
>>> test_tcp.flags
18
>>> test_tcp
<TCP flags=SA |>
>>> test_tcp.flags=23
>>> test_tcp
<TCP flags=FSRA |>
>>> i=IP(flags="DF+MF")
>>> i.flags
3
>>> i.flags=6
>>> i
<IP flags=DF+evil |>
>>>
>>> test_ip.src
'192.168.115.198'
>>> test_ip.dst
'192.168.115.188'
>>> del(test_ip.dst) 注意刪除後的變化
>>> test_ip.dst
'127.0.0.1'
>>> test_ip.src
'127.0.0.1'
>>> test_ip.dst="192.168.115.188" 重新設定目標地址
>>> test_ip.src
'192.168.115.198'
>>> </div>
注:以下的“/”符號表示兩個鏈路層的組合。這樣</span><span style="font-size:18px;">下層可以層重載上一層的默認值或多個字段值。
>>> IP()
<IP |>
>>>> IP()/TCP()
<IP frag=0 proto=tcp |<TCP |>>
>>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP >>
>>>> Ether()/IP()/TCP()
<Ether type=IPv4 |<IP frag=0 proto=tcp |<TCP |>>>
>>>> IP()/TCP()/"GET /HTTP/1.0\r\n\r\n" 數據部分可以直接使用字符串
<IP frag=0 proto=tcp |<TCP |<Raw load='GET /HTTP/1.0\r\n\r\n' |>>>
>>>> Ether()/IP()/UDP()
<Ether type=IPv4 |<IP frag=0 proto=udp |<UDP |>>>
>>>> Ether()/IP()/IP()/UDP()
<Ether type=IPv4 |<IP frag=0 proto=ipencap |<IP frag=0 proto=udp |<UDP |>>>>
>>> str(IP())
'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01'
>>> IP(_)
<IP version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=hopopt
chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>
>>> a=Ether()/IP(dst="www.baidu.com")/TCP()/"GET /index.html HTTP/1.0 \n\n"
>>> hexdump(a)
0000 00 03 0F 19 6A 49 08 00 27 FE D8 12 08 00 45 00 ....jI..'.....E.
0010 00 43 00 01 00 00 40 06 70 78 C0 A8 73 C6 B4 61 [email protected]
0020 21 6C 00 14 00 50 00 00 00 00 00 00 00 00 50 02 !l...P........P.
0030 20 00 B3 75 00 00 47 45 54 20 2F 69 6E 64 65 78 ..u..GET /index
0040 2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 .
0050 0A .
>>> b=str(a)
>>> b
"\x00\x03\x0f\x19jI\x08\x00'\xfe\xd8\x12\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06px
\xc0\xa8s\xc6\xb4a!l\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xb3u
\x00\x00GET /index.html HTTP/1.0 \n\n"
>>> c=Ether(b)
>>> c
<Ether dst=00:03:0f:19:6a:49 src=08:00:27:fe:d8:12 type=IPv4 |<IP version=4L
ihl=5L tos=0x0 len=67 id=1 flags= frag=0L ttl=64 proto=tcp chksum=0x7078
src=192.168.115.198 dst=180.97.33.108 options=[] |<TCP sport=ftp_data dport=http
seq=0 ack=0 dataofs=5L reserved=0L flags=S window=8192 chksum=0xb375 urgptr=0
options=[] |<Raw load='GET /index.html HTTP/1.0 \n\n' |>>>>
>>> c.hide_defaults() 如果覺得過於冗長,可以使用這個函數隱藏
>>> c
<Ether dst=00:03:0f:19:6a:49 src=08:00:27:fe:d8:12 type=IPv4 |<IP ihl=5L len=67
frag=0 proto=tcp chksum=0x7078 src=192.168.115.198 dst=180.97.33.108 |<TCP
dataofs=5L chksum=0xb375 options=[] |<Raw load='GET /index.html HTTP/1.0 \n\n' |
>>>>
>>> a=rdpcap("/mnt/share/test1.cap") 我使用的wireshark,保存成pcap的格式
>>> a
<test1.cap: TCP:13 UDP:53 ICMP:4 Other:3>
>>> a[9].pdfdump(layer_shift=1)
>>> a[9].psdump("/mnt/share/test1.eps",layer_shift=1)
如何產生多個數據包
>>> a=IP(dst="www.baidu.com/30")
>>> a
<IP dst=Net('www.baidu.com/30') |>
>>> [p for p in a]
[<IP dst=180.97.33.104 |>, <IP dst=180.97.33.105 |>, <IP dst=180.97.33.106 |>,
<IP dst=180.97.33.107 |>]
>>> b=IP(ttl=[1,2,(5,9)])
>>> b
<IP ttl=[1, 2, (5, 9)] |>
>>> [p for p in b]
[<IP ttl=1 |>, <IP ttl=2 |>, <IP ttl=5 |>, <IP ttl=6 |>, <IP ttl=7 |>, <IP
ttl=8 |>, <IP ttl=9 |>]
>>> c=TCP(dport=[80,443])
>>> [p for p in a/c] 產生多個數據包
[<IP frag=0 proto=tcp dst=180.97.33.104 |<TCP dport=http |>>, <IP frag=0
proto=tcp dst=180.97.33.104 |<TCP dport=https |>>, <IP frag=0 proto=tcp
dst=180.97.33.105 |<TCP dport=http |>>, <IP frag=0 proto=tcp dst=180.97.33.105 |
<TCP dport=https |>>, <IP frag=0 proto=tcp dst=180.97.33.106 |<TCP dport=http |
>>, <IP frag=0 proto=tcp dst=180.97.33.106 |<TCP dport=https |>>, <IP frag=0
proto=tcp dst=180.97.33.107 |<TCP dport=http |>>, <IP frag=0 proto=tcp
dst=180.97.33.107 |<TCP dport=https |>>]
>>>
3、發送數據包
學習send/sendp/sr/sr1/srp 發送數據包函數使用
>>> send(IP(dst="192.168.115.188")/ICMP()) send函數工作在第三層
.
Sent 1 packets.
>>> sendp(Ether()/IP(dst="192.168.115.188",ttl=(1,4)),iface="eth0")
....
Sent 4 packets.
>>> sendp("hello ,i am walfred ",iface="eth0",loop=1,inter=0.2) sendp函數工作在第二層,你可以選擇網卡和協議
..................................................................................................................................................................................................................................................................................................................................^C
Sent 322 packets.
fuzz函數的作用:可以更改一些默認的不可以被計算的值(比如校驗和checksums),更改的值是隨機的,但是類型是符合字段的值的。比如下面的例子,結果如下圖對比:
>>> send(IP(dst="www.baidu.com")/UDP()/NTP(version=4),loop=2) 未使用fuzz()
>>> sr(IP(dst="192.168.115.1")/TCP(dport=[21,22,23]))
Begin emission:
Finished to send 3 packets.
***
Received 3 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=_ 這也是scapy的核心了
>>> ans.show()
0000 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ftp S ==> IP / TCP 192.168.115.1:ftp > 192.168.115.198:ftp_data RA / Padding
0001 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ssh S ==> IP / TCP 192.168.115.1:ssh > 192.168.115.198:ftp_data RA / Padding
0002 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:telnet S ==> IP / TCP 192.168.115.1:telnet > 192.168.115.198:ftp_data SA / Padding
>>>sr(IP(dst="192.168.115.1")/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1) 網絡環境不好時,也可以追加inter retry timeout等附加信息,
函數sr1()是sr()一個變種,只返回應答發送的分組(或分組集)。這兩個函數發送的數據包必須是第3層數據包(IP,ARP等)。而函數SRP()位於第2層(以太網,802.3,等)。
>>> p=sr1(IP(dst="192.168.115.188")/ICMP()/"test")
Begin emission:
.....Finished to send 1 packets.
.*
Received 7 packets, got 1 answers, remaining 0 packets
>>> p
<IP version=4L ihl=5L tos=0x0 len=32 id=26000 flags= frag=0L ttl=128 proto=icmp chksum=0x6c79 src=192.168.115.188 dst=192.168.115.198 options=[] |<ICMP type=echo-reply code=0 chksum=0x1826 id=0x0 seq=0x0 |<Raw load='test' |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>>
>>> p.show()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 32
id= 26000
flags=
frag= 0L
ttl= 128
proto= icmp
chksum= 0x6c79
src= 192.168.115.188
dst= 192.168.115.198
\options\
###[ ICMP ]###
type= echo-reply
code= 0
chksum= 0x1826
id= 0x0
seq= 0x0
###[ Raw ]###
load= 'test'
###[ Padding ]###
load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'