I'm currently expanding the functionality of my AOL Instant Messenger interceptor for a project I'm working on with a researcher from IBM. For this particular project, the script will need to be able to intercept timestamps and screen names in addition to the data the program is already equipped to capture. Timestamps are easy, because they are handled entirely by the client application and aren't really part of the protocol. It's really as easy as adding a #{Time.now} to the relevant output string.
Screen names are a lot more challenging. The OSCAR protocol only embeds the destination screen name in outgoing messages and the sender screen name in incoming messages. As a result, it is very difficult to identify the screen name of the other party associated with each message. The packet sniffer will have to intercept the screen names during the sign-on process and associate those screen names with a local network IP address. I'm not sure yet, but the fact that the OSCAR protocol uses encryption for login strings might make this a lot more interesting.
The script has to be able to intercept data from two separate network interfaces simultaneously. In other programming languages this might be a problem, but thanks to Ruby's excellent support for simple threading, I can do it with relative ease. The following is a trivial example that demonstrates how to monitor packets from multiple interfaces at the same time using Ruby:
pc1 = Pcaplet.new("-s 1500 -i eth1")
pc2 = Pcaplet.new("-s 1500 -i eth3")
f1 = Pcap::Filter.new("tcp", pc1.capture)
f2 = Pcap::Filter.new("tcp", pc2.capture)
def display dev, pck
puts "#{dev}: #{pck.tcp_data}"
end
fork {
pc1.each_packet {|pk| display "eth1", pk}
}
pc2.each_packet {|pk| display "eth3", pk}
The power and elegance of Ruby never cease to impress me.
Tags: ruby, programming, pcap, oscar
Posted on 2006-06-14
After reading an article about network monitoring with ngrep at Newsforge, I developed an interest in libpcap, a portable network packet sniffing library originally designed by LBL.
Packet sniffing is useful for a wide variety of tasks, particularly reverse engineering network protocols and spying on local network users. I found some Ruby bindings and started messing around. My first goal was to write a small network sniffer that would display http GET requests transmitted by any system on the network. I monitored packets transmitted by Firefox Get requests and managed to build a filter capable of extracting them. The filter also appears to work with Safari, and to a very limited extent, with IE, which appears to use a slightly different format for the requests.
Once I had basic GET filtering figured out, I decided to construct a system that would simplify filter extension. My PacketSniffer class allows me to add filters using pcap filtering strings and anonymous functions. The end result is a psuedo-language for network sniffing. Filter definitions look like this:
ps.filter 'tcp and dst port 80', proc {|pk|
if pk.tcp_data =~ /GET(.*)HTTP.*Host:([^\r\n]*)/xm
puts "(->) <#{pk.src}> http://#{$2.strip}#{$1.strip}"
end
}
The first argument of the filter method is the pcap filter string, 'tcp and dst port 80', which, in this case, tells libpcap to filter all tcp packets sent to port 80 of a remote server. The second argument of the filter method is an anonymous function that will be called every time libpcap receives a packet that meets the constraints of the filter string.
Next, I wanted to make an AIM message sniffer. Intercepting AIM packets is really not that difficult, it's just a matter of figuring out which port AIM uses (5190) and building pcap filter strings to grab packets sent to or recevied from that port. Parsing the packets OTOH is a pain in the ass. The OSCAR protocol is an insane mess and there are a lot of inconsistencies between various implementations. My aim_msg_parse function is really kludgy, but it is now capable of extracting the AIM SN of the user sending the message as well as the message itself.
The current version of my script works relatively well. In tests on my own network, it was capable of intercepting AIM and GET packets from OS X, Windows and Linux systems. If you want to try it out yourself, you will need my script, libpcap, and the ruby bindings. On Linux systems, you must run the script as root. I have not run it on a Windows system, but with a Windows port of libpcap, it might work.
Tags: ruby, programming, pcap, oscar
Posted on 2005-07-23