cymru1

This tutorial will demonstrate some Kung Fu with Team Cymru’s Python whois module.  In both offensive and defensive roles within infosec you will need to do quite a lot of whois look ups and this python module can save you loads of time.  Lets jump in and start to play with this module’s functionality.

Once you installed the module you can import the module and checkout what functionality it offers:

>>> from cymruwhois import Client
>>> c = Client()
>>> dir(c)
['KEY_FMT', '__doc__', '__init__', '__module__', '_begin', '_connect', '_connected', '_disconnect', '_lookupmany_raw', '_readline', '_sendline', 'c', 'cache', 'disconnect', 'get_cached', 'host', 'lookup', 'lookupmany', 'lookupmany_dict', 'port', 'read_and_discard']
>>>

Now we can lookup a single IP address with the “lookup” function.  In a later script we will be using the “lookupmany” since it lets us pass it an array of IPs:

>>> google = c.lookup('8.8.8.8')
>>> google
<cymruwhois.record instance: 15169|8.8.8.8|8.8.8.0/24|US|GOOGLE - Google Inc.,US>
>>> type(google)
<type 'instance'>
>>>

Now we have an instance of the cymruwhois.record and we can extract information in the following way:

>>>
>>> dir(google)
['__doc__', '__init__', '__module__', '__repr__', '__str__', 'asn', 'cc', 'ip', 'owner', 'prefix']
>>> google.ip
'8.8.8.8'
>>> google.owner
'GOOGLE - Google Inc.,US'
>>> google.cc
'US'
>>> google.asn
'15169'
>>> google.prefix
'8.8.8.0/24'
>>>

So from here we could wrap this around a for loop and do it over and over, but Team Cymru already provides a function called “lookupmany” which is a lot better than for looping the lookup function.  Below is a heavily commented script that shows how you can pull all this together to read a list of IPs from a file to perform the whois look up.

What I normally do is extract the IPs of interest using tcpdump, BPF filters, and bash-fu.  Below we grab just SYNs with “tcp

[13]=2″ and then pipe STDOUT to STDIN of awk and grab the 6th element in the line with “awk ‘{print $6}’, then pull out just the IP with the last awk command, and finally redirect STDOUT to a file:

~$ tcpdump -ttttnnr t.cap tcp[13]=2 | awk '{print $6}' | awk -F "." '{print $1"."$2"."$3"."$4}' > ips.txt
reading from file t.cap, link-type LINUX_SLL (Linux cooked)
~$ python ip2net.py -r ips.txt
[+] Querying from:  ips.txt
173.194.0.0/16       # -   173.194.8.102 (US) - GOOGLE - Google Inc.,US
~$

Now lets take a quick look at the ip2net.py script heavily commented so you can understand how it breaks down:

#!/usr/bin/env python
import sys, os, optparse
from cymruwhois import Client

def look(iplist):
    c=Client() # creates an instance of the Client class
    try:
        if ips != None:
            r = c.lookupmany_dict(iplist) # leverages the lookupmany_dict() function to pass in a list of IPs
            for ip in iplist: # Iterates over the ips in the list to use a key value in the dictionary from lookupman_dict()
                net = r[ip].prefix; owner = r[ip].owner; cc = r[ip].cc # gets the networking information from the dictionary
                line = '%-20s # - %15s (%s) - %s' % (net,ip,cc,owner) # formats the line to print cleanly
                    print line
    except:pass

def checkFile(ips): # Checks to ensure the file can be read
        if not os.path.isfile(ips):
                print '[-] ' + ips + ' does not exist.'
                sys.exit(0)
        if not os.access(ips, os.R_OK):
                print '[-] ' + ips + ' access denied.'
                sys.exit(0)
        print '[+] Querying from:  ' +ips

def main():
        parser = optparse.OptionParser('%prog '+ 
        '-r <file_with IPs> || -i <IP>')
        parser.add_option('-r', dest='ips', type='string', 
                help='specify target file with IPs')
    parser.add_option('-i', dest='ip', type='string', 
        help='specify a target IP address')
        (options, args) = parser.parse_args()
    ip = options.ip      # Assigns a -i <IP> to variable 'ip'
    global ips; ips = options.ips # Assigns a -r <fileName> to variable 'ips'
        if (ips == None) and (ip == None): # If proper arguments aren't given print the script usage
                print parser.usage
                sys.exit(0)
        if ips != None:    # Execute if ips has a value
        checkFile(ips)    # Execute the function to check if the file can be read
        iplist = []    # create the ipslist list object
            for line in open(ips, 'r'): # Parse File to create a list
            iplist.append(line.strip('n')) # Appends that line in the file to list and removes the new line char
        look(iplist)    # pass the iplist list object to the look() function

    else:    # Executes lookup() function for a single IP stored in variable 'ip'
        try:
            c=Client()
            r = c.lookup(ip)
                    net = r.prefix; owner = r.owner; cc = r.cc
                    line = '%-20s # - %15s (%s) - %s' % (net,ip,cc,owner)
                    print line
        except:pass

if __name__ == "__main__":
      main()