Sisniff: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
Sigi (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
Sigi (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
||
| Zeile 2: | Zeile 2: | ||
Ein Netzwerk-Sniffer der für jedes Packet nebst Adresse und Port die lokal verbundene Anwendung und deren PID ermittelt und anzeigt. | Ein Netzwerk-Sniffer der für jedes Packet nebst Adresse und Port die lokal verbundene Anwendung und deren PID ermittelt und anzeigt. | ||
Es wird TCP und UDP unterstützt. | Es wird TCP und UDP unterstützt. | ||
Zusätzlich kann ein Filter definiert und die Requests/Responses von HTTP Verbindungen angezeigt werden. | Zusätzlich kann ein Filter definiert und die Requests/Responses von HTTP Verbindungen angezeigt werden. | ||
[[Datei:Terminal_059.png|400px|thumb| | [[Datei:Terminal_059.png|400px|thumb|right|sisniff Image]] | ||
Download der aktuellen Version: [https://www.zweiernet.ch/download/sisniff-0.7.tar.gz sisniff-0.7.tar.gz]<br /> | |||
Python2 Code of sisniff.py: | |||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
#!/usr/bin/python2 | |||
# (c) 2017 by Siegrist(SystemLoesungen) <PSS@ZweierNet.ch> | |||
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.7" | |||
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 = str(packet[0][1].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 | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Version vom 14. Juni 2017, 13:17 Uhr
Ein Netzwerk-Sniffer der für jedes Packet nebst Adresse und Port die lokal verbundene Anwendung und deren PID ermittelt und anzeigt.
Es wird TCP und UDP unterstützt.
Zusätzlich kann ein Filter definiert und die Requests/Responses von HTTP Verbindungen angezeigt werden.
Download der aktuellen Version: sisniff-0.7.tar.gz
Python2 Code of sisniff.py:
#!/usr/bin/python2
# (c) 2017 by Siegrist(SystemLoesungen) <PSS@ZweierNet.ch>
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.7"
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 = str(packet[0][1].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