21 January 2009

ARP Ping Using Scapy

here's a quick script i whipped up a while ago.
it uses scapy to perform an ARP ping of a network, and provides a CSV report of any MAC addresses it finds, along with the associated IP's.

It requires tcpdump to be installed and in the $PATH, as well as root privs to run.

#!/usr/bin/env python
# note that this script requires tcpdump to be installed
# additionally, it requires root privs to run.
# ----
# Portions of this code can be attributed to the book
# Python for Unix and Linux System Administration
# by Noah Gift and Jeremy M. Jones. 
# Copyright 2008 Noah Gift and Jeremy M. Jones
# ISBN-13: 978-0-596-51582-9
# ----

import sys
if len(sys.argv) != 2:
    print "Usage: pingarp \n  eg: pingarp 192.168.1.0/24"
    sys.exit(1)

from scapy import srp,Ether,ARP,conf
conf.verb=0
ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=sys.argv[1]),
              timeout=2)

print r"MAC,IP"
for snd,rcv in ans:
    print rcv.sprintf(r"%Ether.src%,%ARP.psrc%")


here's sample output:
$ sudo ./pingarp 192.168.11.0/24
MAC,IP
00:16:01:8b:54:4a,192.168.11.1
00:13:ce:e9:6e:95,192.168.11.3
00:40:ca:8a:72:48,192.168.11.6

20 January 2009

crappy blogger templates

i'm going to have to consider either writing my own template, or moving to another blog technology.
every one of the default templates sucks for posting code, or any other long string of text for that matter. there's a lot more i could complain about, but that single fact at the moment is bugging me.

so, i've switched to a very basic template, and added the following bit of css to the code for now:

.post pre, .post code {
overflow: auto;
}


this works, but is less than ideal i think. not sure there's a good answer, but i'm definitely going to start looking into one. for now, sorry for the ugly layout, but hey, if it's that bad, RSS ftw! ;-)

Scapy Notes

Scapy is an "interactive packet manipulation program" written in python. It basically is a packet workshop framework which allows one to craft their own packets from scratch to match a variety of protocols, then send them on the wire and capture the results for analysis. Since it is written in python, it allows one to essentially create any number of tools, including scanners, fuzzers, DoS tools, etc. More info on it can be found at the scapy home page.

Basic Usage
When scapy is run from the command line, it loads the scapy modules and then drops you at the python shell prompt. This is useful for a number of reasons, but primary among them is that this means anything you can do in python, you can do in scapy as well. For the moment though, we're going to focus solely on the scapy specific modules.

Building a Packet
Scapy makes it extremely easy to build a packet, here's what it looks like:

First, we call scapy interactively:
[root@snsvc]# scapy
Welcome to Scapy (v1.1.1 / f88d99910220)
>>>

Next, we create the IP frame, then the TCP packet:
>>> a=IP()
>>> b=TCP()

Now we combine the two to create the TCP/IP datagram:
>>> c=a/b

We can use scapy's ls command to view the contents of the packet:
>>> ls(c)
version : BitField = 4 (4)
ihl : BitField = None (None)
tos : XByteField = 0 (0)
len : ShortField = None (None)
id : ShortField = 1 (1)
flags : FlagsField = 0 (0)
frag : BitField = 0 (0)
ttl : ByteField = 64 (64)
proto : ByteEnumField = 6 (0)
chksum : XShortField = None (None)
src : Emph = '127.0.0.1' (None)
dst : Emph = '127.0.0.1' ('127.0.0.1')
options : IPoptionsField = '' ('')
--
sport : ShortEnumField = 20 (20)
dport : ShortEnumField = 80 (80)
seq : IntField = 0 (0)
ack : IntField = 0 (0)
dataofs : BitField = None (None)
reserved : BitField = 0 (0)
flags : FlagsField = 2 (2)
window : ShortField = 8192 (8192)
chksum : XShortField = None (None)
urgptr : ShortField = 0 (0)
options : TCPOptionsField = {} ({})

Changing Packet Details
Now, if we want to change any of the fields in the packet, we can do so by altering their values. For example, to change the IP destination to 192.168.1.1 and set the TCP destination port to 443, we do the following:
>>> a.dst='192.168.1.1'
>>> b.dport=443

Now we recreate the TCP/IP packet again, and view the changes using ls:
>>> c=a/b
>>> ls(c)
version : BitField = 4 (4)
ihl : BitField = None (None)
tos : XByteField = 0 (0)
len : ShortField = None (None)
id : ShortField = 1 (1)
flags : FlagsField = 0 (0)
frag : BitField = 0 (0)
ttl : ByteField = 64 (64)
proto : ByteEnumField = 6 (0)
chksum : XShortField = None (None)
src : Emph = '192.168.1.3' (None)
dst : Emph = '192.168.1.1' ('127.0.0.1')
options : IPoptionsField = '' ('')
--
sport : ShortEnumField = 20 (20)
dport : ShortEnumField = 443 (80)
seq : IntField = 0 (0)
ack : IntField = 0 (0)
dataofs : BitField = None (None)
reserved : BitField = 0 (0)
flags : FlagsField = 2 (2)
window : ShortField = 8192 (8192)
chksum : XShortField = None (None)
urgptr : ShortField = 0 (0)
options : TCPOptionsField = {} ({})

Note that even though we didn't change the IP source, the value has changed. This is because scapy determined which interface would be used to send the packet to the destination we configured, and changed the source to that interface's address for us. We can override this if desired.

Sending the Packet
We use the sr() function to send the data across the wire. This function sends the packet, sniffs the response, and matches sent packets with the received responses. It works at layer 3, and will return the whole result of a probe.
>>> sr(c)
Begin emission:
...Finished to send 1 packets.
*
Received 4 packets, got 1 answers, remaining 0 packets
(, )

Viewing Results
We can view the results by assigning them to variables:
>>> res,unans=_
>>> res.nsummary()
0000 IP / TCP 192.168.1.3:ftp_data > 192.168.1.1:https S ==> IP / TCP 192.168.1.1:https > 192.168.1.3:ftp_data SA / Padding

Here we see we sent a SYN packet to port 443, and received a SYN/ACK packet back from the destination. We also see there was some Padding added to the SYN/ACK. We can view the information in the padding by accessing the results list directly:
>>> res[0][1]
>>

Scripted Usage
Because scapy is written in python, it can be used from within any python script simply by using the import scapy statement.
For example, here's a simple script to perform a TCP SYN scan of ports 0-1024 on a given host (provided as a parameter to the script):
#!/usr/bin/env python
import sys
from scapy import sr,IP,TCP,conf
conf.verb = 0
dstip = sys.argv[1]

print "\nBeginning scan of "+dstip
res,unans = sr(IP(dst=dstip)/TCP(dport=[(0,1024)]),timeout=1)
if res:
print "\nReceived answers from the following ports:\n"
for s,r in res:
print r.sprintf("%TCP.sport%")
print "\nScan completed\n"

And here's the results of running this:
[root@snsvc]# ./scanner 192.168.1.1

Beginning scan of 192.168.1.1

Received answers from the following ports:

telnet
http
https

Scan completed

Install/Config Notes
"Error during evauluation of config file"
When running scapy from inside other python scripts, you may encounter the following error message:
ERROR: Error during evaluation of config file [None]
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/scapy.py", line 12183, in read_config_file
execfile(configfile)

Not very helpful, but easy to fix. The problem is that scapy is looking for a config file which doesn't exist. The good news is that one just has to be present, no configuration is required. To fix this, simply do the following:
# touch ~/.scapy_startup.py

Using the Loopback Interface
The loopback interface is a special interface, in that packets going through it are not really assembled and dissassembled. The kernel routes the packet to its destination while it is still stored an internal structure.

In order to use the loopback interface, you need to send your packets using PF_INET/SOCK_RAW instead of PF_PACKET/SOCK_RAW. This can be done by changing the supersocket used by scapy, which is accessed via the configuration.

The default scapy values for sockets are as follows:
+------------------------+----------------+
| Configuration Variable | Default Value |
+------------------------+----------------+
| L2listen | L2ListenSocket |
+------------------------+----------------+
| L2socket | L2Socket |
+------------------------+----------------+
| L3socket | L3PacketSocket |
+------------------------+----------------+

To use the loopback interface, change the L3socket setting to L3RawSocket.
This can be done using the following command (either via the scapy CLI or inside a script):
conf.L3socket=L3RawSocket

04 January 2009

captcha madness

i went to gmail today to login to an older email account i haven't checked in a while... apparently *too* long, because i got presented a captcha upon entering the username and password.

i was having a hard time reading the text (no surprises there, captcha's really suck as a technology), so for fun i decided to try clicking the "handicap" icon so i could listen to the captcha in audio format.

for some reason, it's never occurred to me that, just as visual captcha uses random crap in the image to try to prevent OCR from determining the letters, the audio version would contain a whole lot of noise in an effort to prevent text to speech from doing the same.

if you've ever wondered what an audible version of the mass confusion that is a modern captcha file might sound like: here you go.

all i can say is, it's a good thing i can see.