-
Notifications
You must be signed in to change notification settings - Fork 3
/
05-sending-first-arp-packet.html
174 lines (155 loc) · 10.5 KB
/
05-sending-first-arp-packet.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Sending our First Packet</title>
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<link href="stylesheets/font-awesome.min.css" rel="stylesheet">
<script src="javascripts/scale.fix.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1 class="header"><a href="index.html">Scapy for Network Tools</a></h1>
<p class="header">Using the power of Python + Scapy to build network tools</p>
<ul>
<li class="download"><a class="buttons" href="https://github.com/thepacketgeek/building-network-tools-with-scapy/zipball/master">Download ZIP</a></li>
<li class="download"><a class="buttons" href="https://github.com/thepacketgeek/building-network-tools-with-scapy/tarball/master">Download TAR</a></li>
<li><a class="buttons github" href="https://github.com/thepacketgeek/building-network-tools-with-scapy">View On GitHub</a></li>
</ul>
<p class="header">This project is maintained by <a class="header name" href="https://github.com/thepacketgeek">thepacketgeek</a></p>
</header>
<section>
<h3 id="01">
05 - Sending our First Packet; ARP Response
</h3>
<p>With a good understanding of how to view our packets we can now move onto some packet generation. Let's talk a bit about sniffing first and how existing packets are our best tool for creating new ones.</p>
<h4>Sniff() function arguments</h4>
<p>We've used the <code>sniff()</code> function a couple times already to capture some packets for viewing. I'm going to explain a little bit more about the <code>sniff()</code> function and its arguments. The arguments we will be talking about are: </p>
<ul>
<li><strong>count:</strong> Number of packets to capture. 0 means infinity.</li>
<li><strong>iface:</strong> Sniff for packets only on the provided interface.</li>
<li><strong>prn:</strong> Function to apply to each packet. If something is returned, it is displayed. For instance you can use prn = lambda x: x.summary().</li>
<li><strong>store:</strong> Whether to store sniffed packets or discard them. When you only want to monitor your network forever, set store to 0.</li>
<li><strong>timeout:</strong> Stop sniffing after a given time (default: None).</li>
</ul>
<p>These should all be self-explanatory except for the <code>filter</code> and <code>prn</code> arguments. The <code>filter</code> argument takes <a href="http://biot.com/capstats/bpf.html" target="_blank">BPF syntax filters</a>, just like Wireshark or tcpdump capture filters. The <code>prn</code> argument is a very cool capability of the <code>sniff()</code> function and you can read more about it here: <a href="http://thepacketgeek.com/scapy-sniffing-with-custom-actions-part-1/" target="_blank">Scapy and custom actions.</a></p>
<p>Since we want to generate our first ARP packet we should go ahead and sniff one to see what it takes to recreate one using the <code>.show()</code> and <code>.command()</code> method. Here's a sniff using the <code>count</code> and <code>filter</code> arguments:
<pre><code>>>> pkts = sniff(count=5,filter="arp")
>>> pkts.summary()
Ether / ARP who has 172.16.20.255 says 172.16.20.40 / Padding
Ether / ARP who has 172.16.20.244 says 172.16.20.40 / Padding
Ether / ARP who has 172.16.20.252 says 172.16.20.40 / Padding
Ether / ARP who has 172.16.20.253 says 172.16.20.40 / Padding
Ether / ARP who has 172.16.20.80 says 172.16.20.74 / Padding
>>> pkts[0].show()
###[ Ethernet ]###
dst= ff:ff:ff:ff:ff:ff
src= 00:11:22:aa:bb:cc
type= 0x806
###[ ARP ]###
hwtype= 0x1
ptype= 0x800
hwlen= 6
plen= 4
op= who-has
hwsrc= 00:11:22:aa:bb:cc
psrc= 172.16.20.40
hwdst= 00:00:00:00:00:00
pdst= 172.16.20.255
###[ Padding ]###
>>> pkts[0].command()
"Ether(src='00:11:22:aa:bb:cc', dst='ff:ff:ff:ff:ff:ff', type=2054)/ARP(hwdst='00:00:00:00:00:00', ptype=2048, hwtype=1, psrc='172.16.20.40', hwlen=6, plen=4, pdst='172.16.20.255', hwsrc='00:11:22:aa:bb:cc', op=2)"</code></pre>
<h4>Building a Packet</h4>
<p>It looks like ARP packets only have 2 layers plus padding that we have to worry about. We can use the <code>ls()</code> function on the Ether and ARP layers to see what options are available to us:</p>
<pre><code>>>> ls(Ether)
dst : DestMACField = (None)
src : SourceMACField = (None)
type : XShortEnumField = (0)
>>> ls(ARP)
hwtype : XShortField = (1)
ptype : XShortEnumField = (2048)
hwlen : ByteField = (6)
plen : ByteField = (4)
op : ShortEnumField = (1)
hwsrc : ARPSourceMACField = (None)
psrc : SourceIPField = (None)
hwdst : MACField = ('00:00:00:00:00:00')
pdst : IPField = ('0.0.0.0')</code></pre>
<p>Let's create our ARP packet and start assigning some values:</p>
<pre><code>>>> arppkt = Ether()/ARP()
>>> arppkt
<Ether type=0x806 |<ARP |>></code></pre>
<p>Let's create our ARP packet and start assigning some values. We can copy/paste the string returned from the <code>.command()</code> method to initiate our packet:</p>
<pre><code>>>> arppkt = Ether(src='00:11:22:aa:bb:cc', dst='ff:ff:ff:ff:ff:ff', type=2054)/ARP(hwdst='00:00:00:00:00:00', ptype=2048, hwtype=1, psrc='172.16.20.40', hwlen=6, plen=4, pdst='172.16.20.255', hwsrc='00:11:22:aa:bb:cc', op=2)
>>> arppkt[ARP].hwsrc = "00:11:22:aa:bb:cc"
>>> arppkt[ARP].pdst = "172.16.20.1"
>>> arppkt[Ether].dst = "ff:ff:ff:ff:ff:ff"
>>> arppkt</code></pre>
<Ether dst=ff:ff:ff:ff:ff:ff type=0x806 |<ARP hwsrc=00:11:22:aa:bb:cc pdst=172.16.20.1 |>></code></pre>
<p>We start by defining the layers we want with the <code>Layer()</code> notation. This will work for any layer in the <code>ls()</code> command output. That's a lot of options! You can also define all the options in one statement by passing in the fields as arguments to the related layer:</p>
<pre><code>>>> arppkt = Ether(dst="ff:ff:ff:ff:ff:ff",src="00:11:22:aa:bb:cc")/ARP(hwsrc="00:11:22:aa:bb:cc",pdst="172.16.20.1")
>>> arppkt
<Ether dst=ff:ff:ff:ff:ff:ff type=0x806 |<ARP hwsrc=00:11:22:aa:bb:cc pdst=172.16.20.1 |>></code></pre>
<p>The layers we want are defined with the with the <code>Layer()</code> notation. This will work for any layer in the <code>ls()</code> command output. That's a lot of options! You can also define the packet from scratch with all the options in one statement by passing in the fields as arguments to the related layer.</p>
<p>Note that the special glue holding these packets together is the <code>/</code> operator. If you happen to forget a layer when you're first defining the packet, you can add on a layer very easily using the existing packet and the <code>/</code> operator like this:</p>
<pre><code>>>> tcppkt
<Ether type=0x800 |<IP |>>
>>> tcppkt = tcppkt/TCP()
>>> tcppkt
<Ether type=0x800 |<IP frag=0 proto=tcp |<TCP |>>></code></pre>
<h4>Sending a packet</h4>
<p>Yup, you guessed it, its finally time to send this ARP packet out on the wire! Since ARP is a L2 protocol we're going to use the <code>sendp()</code> function as the <code>send()</code> function only works with L3 Packets (IP or IPv6 headers):</p>
<pre><code>>>> arppkt
<Ether dst=ff:ff:ff:ff:ff:ff src=00:11:22:aa:bb:cc type=0x806 |<ARP hwsrc=00:11:22:aa:bb:cc pdst=172.16.20.1 |>>
>>> sendp(arppkt)
.
Sent 1 packets.</code></pre>
<img src="images/05-sent-arp-packet.png"/>
<p class="caption">Screenshot of capture packet in Wireshark</p>
<p>What, what! Check that out! Our packet out from the scapy console and in the wire! Pretty cool, right? Well, here's a fun fact. We don't need to create and build the packet before sending it, we can define the packet right there in the <code>send()</code> or <code>sendp()</code> function like this:</p>
<pre><code>>>> sendp(Ether(dst="ff:ff:ff:ff:ff:ff",src="00:11:22:aa:bb:cc")/ARP(hwsrc="00:11:22:aa:bb:cc",pdst="172.16.20.1")
.
Sent 1 packets.</code></pre>
<p>In fact, we can do some other cool things with these send functions. If we had an array of packets (such as one created with Python loops and some random or incrementing values for IP address/TCP port), the send function would send each packet in that array: </p>
<pre><code>>>> pkts
<Sniffed: TCP:0 UDP:5 ICMP:4 Other:1>
>>> send(pkts)
..........
Sent 10 packets.</code></pre>
<p>The send commands have some arguments to control the packet sending, here's the main ones you might consider using:</p>
<p><strong>send(pkts, inter=0, loop=0)<br>sendp(pkts, inter=0, loop=0)</strong></p>
<ul>
<li><strong>iface:</strong> The interface to send the packets out from.</li>
<li><strong>inter:</strong> Time in seconds to wait between 2 packets.</li>
<li><strong>loop:</strong> Send the packets endlessly if not 0.</li>
<li><strong>pkts:</strong> Can be a packet, an implicit packet or a list of them.</li>
</ul>
<nav>
<p class="previous"><a href="04-looking-at-packets.html"><i class="icon-arrow-left"></i> Previous</a></p>
<p class="next"><a href="06-sending-and-receiving.html">Next <i class="icon-arrow-right"></i></a></p>
</nav>
</section>
</div>
<footer>
<p>Hosted on GitHub Pages — Theme by <a href="https://github.com/orderedlist">orderedlist</a></p>
</footer>
<!--[if !IE]><script>fixScale(document);</script><![endif]-->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-44238008-3");
pageTracker._trackPageview();
} catch(err) {}
</script>
</body>
</html>