#!/usr/bin/python from __future__ import print_function # logging, python2-only. """ A script that reads data generated by p0f -f p0f.log, looking for all entries about an IP read from NCAT_REMOTE_ADDR environment variable. Then it prints out all the information it has found. To try it out, run "p0f -i any -o p0f.log" and ncat -l -k --sh-exec "python p0fme.py". Script tested under Python versions 2.7 and 3.3. """ P0F_LOG_FILE = "p0f.log" import datetime # logging import sys # logging import os # environ import time # sleeping to wait for data import sys # to flush STDOUT def expand_ipv6(ip): """ Expands short IPv6 address like ::1 into an expanded form without trailing zeros. Copied from: http://svn.python.org/projects/python/tags/r31b1/Lib/ipaddr.py (Py3 standard library; added some modifications to match p0f's output data) """ new_ip = [] hextet = ip.split('::') sep = len(hextet[0].split(':')) + len(hextet[1].split(':')) new_ip = hextet[0].split(':') for _ in range(8 - sep): new_ip.append('0') new_ip += hextet[1].split(':') # Now need to make sure every hextet is 4 lower case characters. # If a hextet is < 4 characters, we've got missing leading 0's. ret_ip = [] for hextet in new_ip: if hextet == '': hextet = '0' ret_ip.append(hextet.lower()) return ':'.join(ret_ip) def split_by_equals(str_): ret = str_.split('=') return ret[0], ''.join(ret[1:]) if __name__ == "__main__": try: ip = os.environ['NCAT_REMOTE_ADDR'] if os.environ['NCAT_PROTO'] != 'TCP': sys.exit("ERROR: This script works for TCP servers only!") except KeyError: sys.exit("ERROR: This script has to be run from inside of Ncat.") print("[%s] Got a request from %s" % ( datetime.datetime.now().isoformat(' '), ip), file=sys.stderr) print("Hold on, I'm collecting data on you...") sys.stdout.flush() time.sleep(3.0) if ':' in ip: # We need to expand IPv6 addresses in a specific way. ip = expand_ipv6(ip) result = {} # Reading the log backward will give us more recent results. for line in reversed(open(P0F_LOG_FILE).readlines()): without_date = line.split('] ') if without_date == ['\n']: continue without_date = ''.join(without_date[1:]) # Create a key-value dictionary out of the '|'-separated substrings. properties = dict(map(split_by_equals, without_date.split('|'))) if not properties['cli'].startswith(ip): continue # Not the IP we're looking for, check next one. for key in properties: if not key in result or result[key] == '???': result[key] = properties[key] if not result: print("Got nothing on you. Try again and I will, though.") # Now that we've finished, print out the results. for key in sorted(result): print("%s: %s" % (key, result[key].rstrip()))