#!/usr/bin/python2 # (c) 2017 by Siegrist(SystemLoesungen) from scapy.all import * import pwd import os import re import glob import sys import string import fcntl import struct import commands import argparse VERSION = "0.71" PROC_TCP4 = "/proc/net/tcp" PROC_UDP4 = "/proc/net/udp" PROC_TCP6 = "/proc/net/tcp6" PROC_UDP6 = "/proc/net/udp6" PROC_PACKET = "/proc/net/packet" TSERV = dict((TCP_SERVICES[k], k) for k in TCP_SERVICES.keys()) USERV = dict((UDP_SERVICES[k], k) for k in UDP_SERVICES.keys()) tcp_payload_hdrs = ['GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT'] numeric = False payloadH = False fillter = "" def get_conn_info(proto,hosts,ports): ''' returns: pid, exe, uid ''' line_array = _proc4load(proto,hosts,ports) if line_array == 0: return ['?','?','?'] ''' try: uid = pwd.getpwuid(int(line_array[7]))[0] # Get user from UID. except: uid = line_array[7] ''' uid = 0 inode = line_array[9] # Need the inode to get process pid. if inode == 0: return ['?','-','?'] pid = _get_pid_of_inode(inode) if pid == "NoPid": return ["NoPid", "NoExe", uid] try: # try read the process name. exe = os.readlink('/proc/'+pid+'/exe').split('/')[-1] except: exe = None #print str(lhost) +" "+ str(lport) +" "+ inode +" "+ pid return [pid, exe, uid] def _proc4load(proto,hosts,ports): ''' Read the table of tcp/udp connections tcp/udp: "sl, local_address, rem_address, st, tx_queue rx_queue, tr tm->when, retrnsmt, uid , timeout, inode ,..." ---- TCP states enum { TCP_ESTABLISHED = 1, TCP_SYN_SENT, TCP_SYN_RECV, TCP_FIN_WAIT1, TCP_FIN_WAIT2, TCP_TIME_WAIT, TCP_CLOSE, TCP_CLOSE_WAIT, TCP_LAST_ACK, TCP_LISTEN, TCP_CLOSING, /* Now a valid state */ TCP_NEW_SYN_RECV, TCP_MAX_STATES /* Leave at the end! */ }; ---------- ''' content = [] if proto == 6: try: with open(PROC_TCP4,'r') as f: content = f.readlines() f.close() content.pop(0) except: print "open proc_tcp4 error" return 0 if proto == 17: try: with open(PROC_UDP4,'r') as f: content = f.readlines() f.close() content.pop(0) except: print "open proc_udp4 error" return 0 for line in content: # src line_array = _remove_empty(line.split(' ')) if line_array[3] in ['04','05','06''07','08','09','0C','0D']: # not some state continue l_host,l_port = _convert_ipv4_port(line_array[1]) # alt if l_host == '127.0.0.1' or l_host not in MYADDRS: if l_host not in MYADDRS: continue if str(l_port) == str(ports): #print l_host+" "+str(l_port)+" // "+host+" "+str(port) return line_array #print "no entry in procfile found!" return 0 def _convert_ipv4_port(array): host,port = array.split(':') return _ip(host),_hex2dec(port) def _hex2dec(s): return str(int(s,16)) def _ip(s): ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))] return '.'.join(ip) def _ip6(s): ip = [s[6:8],s[4:6],s[2:4],s[0:2],s[12:14],s[14:16],s[10:12],s[8:10],s[22:24],s[20:22],s[18:20],s[16:18],s[30:32],s[28:30],s[26:28],s[24:26]] #print '66666:', ':'.join(ip), s return ':'.join(ip) def _remove_empty(array): return [x for x in array if x !=''] def _get_pid_of_inode(inode): for item in glob.glob('/proc/[0-9]*/fd/[0-9]*'): try: if re.search(inode,os.readlink(item)): return item.split('/')[2] except: pass return "NoPid" def _resolve_ip(host): """ resolve ip und update dictionary res_cache {'ip': 'name'}. If resolution for a ip failed, 'name' is n_try ... 0. """ try: hname = socket.gethostbyaddr(host)[0] res_cache[host] = str(hname) return str(hname) except: res_cache[host] = str(host) return str(host) def check_root(): if os.getuid() == 0: return True else: return False ## Define our Custom Action function def doPackets(packet): program = "-" pid = "-" uid = "-" o_proto = "" o_dport = "none" o_sport = "none" flags = "" # only local addresses if packet[0][1].src in MYADDRS: conn_addr = packet[0][1].src if packet.haslayer(TCP) or packet.haslayer(UDP): conn_port = packet[0][2].sport o_dir = 1 else: conn_addr = packet[0][1].dst if packet.haslayer(TCP) or packet.haslayer(UDP): conn_port = packet[0][2].dport o_dir = 0 if packet.haslayer(TCP) or packet.haslayer(UDP): # logemol casch c_hash = conn_addr+'.'+str(conn_port) if not any(x[0] == c_hash for x in conn_cache): # get the connection info from packet spid,sexe,suid = get_conn_info(packet[0][1].proto, conn_addr, conn_port) if re.match("^[0-9]+$", spid): program = sexe pid = spid uid = suid # update cache if len(conn_cache) > cc_maxlen: conn_cache.pop(0) conn_cache.append([c_hash,program,pid]) #print conn_cache else: program = "-" pid = "-" uid = "-" else: # me honds fom casch indx = [x[0] for x in conn_cache].index(c_hash) program = conn_cache[indx][1] pid = conn_cache[indx][2] uid = 0 # cache aktualisieren renew = conn_cache.pop(indx) conn_cache.append(renew) o_payload = "" if packet.haslayer(UDP): o_proto = "UDP" try: o_dport = "\033[1m"+USERV[packet[0][2].dport]+"\033[0m" except: o_dport = str(packet[0][2].dport) try: o_sport = "\033[1m"+USERV[packet[0][2].sport]+"\033[0m" except: o_sport = str(packet[0][2].sport) flags = "" #o_payload = packet[0].sprintf('%10s,UDP.payload%') if packet.haslayer(TCP): o_proto = "TCP" try: o_dport = "\033[1m"+TSERV[packet[0][2].dport]+"\033[0m" except: o_dport = str(packet[0][2].dport) try: o_sport = "\033[1m"+TSERV[packet[0][2].sport]+"\033[0m" except: o_sport = str(packet[0][2].sport) flags = packet[0].sprintf('%3s,TCP.flags%') if payloadH == True: if packet.haslayer(Raw): tpld = packet[0].sprintf('%TCP.payload%') if re.match("^GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT.*", tpld[0:8]): request_line, gaga = tpld.split('\r\n', 1) o_payload = str(request_line) #o_payload = tpld[0:20] if o_dir == 1: if numeric == False: if res_cache.has_key(packet[0][1].dst): rem_name = res_cache[packet[0][1].dst] else: rem_name = _resolve_ip(packet[0][1].dst) else: rem_name = packet[0][1].dst return "\033[1m"+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].src + ":" + o_sport + "\033[1m\033[31m ->>> \033[0m" + rem_name + ":" + o_dport + " " + flags + " Len:" + str(packet[0][1].len) + " : " + o_payload else: if numeric == False: if res_cache.has_key(packet[0][1].src): rem_name = res_cache[packet[0][1].src] else: rem_name = _resolve_ip(packet[0][1].src) else: rem_name = packet[0][1].src return "\033[1m"+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].dst + ":" + o_dport + "\033[1m\033[36m <<<- \033[0m" + rem_name + ":" + o_sport + " " + flags + " Len:" + str(packet[0][1].len) + " : " + o_payload ## -- Ond denn s'Hooptprogramm # root check if not check_root(): print("This program needs root privileges !\nThats because of reading the /proc filesystem and using libpcap functions.\nSo I give up\n") conf.sniff_promisc=0 conf.sniff_promisc=0 print conf #sys.exit() # get the interfaces ifaces = commands.getoutput("ls /sys/class/net") iface_list = ifaces.split('\n') print # commandline params parser = argparse.ArgumentParser(description='sisniff V'+VERSION) parser.add_argument('-i', help="Interface (mandatory)", choices=iface_list, required=True) parser.add_argument('-n', help="Do not resolve IP-Addresses", action="store_true") parser.add_argument('-pH', help="Show HTTP Payload", action="store_true") parser.add_argument('filter', nargs='?', help="Filter (BPF syntax) on top of IP (in dbl-quotes \"...\")", type=str) args = parser.parse_args() iface = args.i if args.n: numeric = True if args.pH: payloadH = True if args.filter: fillter = " and (" + args.filter + ")" print "> Applying Filter: \"ip" + fillter + "\"" # local addresses MYADDRS = _remove_empty(commands.getoutput("hostname -I").split(' ')) MYADDRS.append('0.0.0.0') MYADDRS.append('127.0.0.1') print "> My IP-Addresses: " + str(MYADDRS) # confirmed connections cache (ringboffer) conn_cache = [] cc_maxlen = 20 # resolver cache res_cache = {} n_try = 3 print print "Program/PID: Local addr:port <<->> Remote addr:port [Flags] Len:length : [Payload]" print "-------------------------------------------------------------------------------" # sniff, filtering for IP traffic sniff(filter="ip"+fillter,iface=iface,prn=doPackets) ## -- oond denn isch schloss