Inspektera HTTP med Ruby/libpcap

Då jag nyligen har börjat utforska Ruby, så bestämde jag mig för att skriva ett litet verktyg för att avlyssna och inspektera trafik på nätverket. Har efter någon timmes arbete skrivit ett skript som analysera HTTP-trafik och skriver ut vem som begärt vad och vilken typ av förfrågan det är.

HTTP används även på andra portar…

För att avlyssna trafik med hjälp av Ruby så använder jag mig av Ruby/Pcap som gör det otroligt enkelt att använda sig av libpcap i Ruby. Ett av de kraven jag hade var att mitt verktyg skulle analysera varje pakets innehåll och på så sätt avgöra om det var HTTP trafik eller inte. Många verktyg verkar helt enkelt bara lyssna på port 80 och sen göra ett antagande att allt som skickas på port 80 är HTTP trafik.

#!/usr/bin/env ruby
#
# File:   httpcap.rb
# Author: Jesper Wallin (jesper@ifconfig.se)
# Date:   21-02-2010
#
 
# use libpcap
require 'pcaplet'
require 'uri'
 
# tap in on a connection
def tap(iface = 'eth0')
  puts "starting to capture packets on #{iface}..."
 
  # sniff packets on interface
  network = Pcaplet.new("-i #{iface} -n -s 1500")
 
  # create a filter so we only care about tcp traffic
  filter = Pcap::Filter.new('tcp', network.capture)
 
  # add the filter
  network.add_filter(filter)
 
  # iterate over every packet
  network.each do |p|
    # only care for packets that match our filter
    if filter =~ p
 
      # try to match any HTTP request
      if p.tcp_data =~ /\A([^\ ]+)\ ([^\ ]+)\ HTTP\/1\.\d.*?^Host:\ ([-.a-zA-Z0-9]+)/mi
 
        # parse the url in order to remove any query variables.
        uri = URI.parse("http://#{$3.strip}:#{p.tcp_dport}#{$2.strip}")
 
        # add the port number to the url, but don't bother if it's on port 80.
        # we can safely assume it's http:// since we're unable to read SSL.
        if uri.port == 80
          uri = "http://#{uri.host}#{uri.path}"
        else
          uri = "http://#{uri.host}:#{uri.port}#{uri.path}"
        end
 
        # result/output
        puts "#{p.ip_src}:#{p.tcp_sport} > #{p.ip_dst}:#{p.tcp_dport} [#{$1}] #{uri}"
      end
    end
 
  end
end
 
# start snooping on eth0
tap('eth0')

libpcap kräver root

Detta skript kommer analysera TCP-trafik på alla portar. Om ett paket ser ut att vara en HTTP förfrågan, så försöker vi ta reda på ut vilken adress som begärts av vem. Längst ner i skriptet kallar vi på metoden tap och anger vilket interface vi ska lyssna på. För att ha rättigheter att läsa all trafik så måste skriptet köras som användaren root:

# ruby httpcap.rb
starting to capture packets on eth0
192.168.1.2:62438 > 74.125.79.104:80 [GET] http://www.google.com/
192.168.1.2:62457 > 213.80.108.30:80 [GET] http://www.ifconfig.se/
192.168.1.2:62458 > 213.80.108.30:80 [GET] http://www.ifconfig.se/inspektera-http-ruby-libpcap
192.168.1.2:62459 > 213.80.108.30:80 [GET] http://axfr.nohack.se/
...

Etik och Moral

Användandet av det här verktyget blir ju lite av en moralfråga då man enkelt kan spionera på vilka sidor som besöks av användarna på nätverket. Detta gäller förvisso alla verktyg som använder sig av libpcap eller liknande. Syftet med detta skript är främst att jag ska lära mig mer om Ruby men även att ha ett smidigt verktyg som enkelt låter mig analysera vilka adresser min dator frågar efter. Personligen anser jag att man alltid ska betrakta all trafik som skickas i klartext som avlyssnad då vem som helst mellan dig och den dator du ansluter till kan läsa all trafik.