diff --git a/netarch/__init__.py b/netarch/__init__.py index 2749bb4..74d8016 100644 --- a/netarch/__init__.py +++ b/netarch/__init__.py @@ -3,6 +3,7 @@ ## 2008 Massive Blowout +import md5 import sys import struct @@ -84,7 +85,7 @@ def unpack(fmt, buf): return vals + (buf[size:],) -class HexDumper: +class HexDumper(object): def __init__(self, fd=sys.stdout): self.fd = fd self.offset = 0 @@ -110,7 +111,7 @@ class HexDumper: o.append(u'%02x' % ord(c)) else: o.append(u'--') - o += ([u' '] * (16 - len(self.buf))) + o += ([u' '] * (16 - len(self.buf))) p = [self._to_printable(c) for c in self.buf] self.write(u'%08x ' % self.offset) @@ -176,7 +177,7 @@ def assert_in(a, *b): ## Binary and other base conversions ## -class BitVector: +class BitVector(object): def __init__(self, i=0, length=None): try: self._val = 0 @@ -281,11 +282,13 @@ import string b64alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + def from_b64(s, alphabet, codec='base64'): tr = string.maketrans(alphabet, b64alpha) t = s.translate(tr) return t.decode(codec) + class Esab64Codec(codecs.Codec): """Little-endian version of base64.""" @@ -296,11 +299,12 @@ class Esab64Codec(codecs.Codec): ## slow. b64_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + def decode(self, input, errors='strict'): r = [] for i in range(0, len(input), 4): v = BitVector() - for c in input[i:i+4]: + for c in input[i:i + 4]: if c in ('=', ' ', '\n'): break v += BitVector(self.b64_chars.index(c), 6) @@ -320,9 +324,11 @@ class Esab64Codec(codecs.Codec): class Esab64StreamWriter(Esab64Codec, codecs.StreamWriter): pass + class Esab64StreamReader(Esab64Codec, codecs.StreamReader): pass + def _registry(encoding): if encoding == 'esab64': c = Esab64Codec() diff --git a/netarch/crypto.py b/netarch/crypto.py index c40da5e..c6f860d 100644 --- a/netarch/crypto.py +++ b/netarch/crypto.py @@ -2,7 +2,6 @@ ## Codebreaking tools ## 2007 Massive Blowout -## I should get an LAUR for this so we can share it. from sets import Set from pprint import pprint @@ -62,11 +61,13 @@ def isPrime(number): if number - 1 == x: return False + def smallestFactor(number): for x in range(2, number): if number % x == 0: return x + def factor(number): """Return prime factors for number""" @@ -106,7 +107,7 @@ def ngrams(n, haystack, min=2, repeats=False): break if d != c: continue - if not acc.has_key(needle): + if needle not in acc: found = where(rtxt, needle) if len(found) >= min: acc[needle] = found @@ -116,9 +117,11 @@ def ngrams(n, haystack, min=2, repeats=False): def freq(txt): return ngrams(1, txt, min=0) + def bigrams(txt): return ngrams(2, txt) + def trigrams(txt): return ngrams(3, txt) @@ -134,20 +137,19 @@ def freqgraph(f): else: return 0 items = [] - for c,n in f.iteritems(): + for c, n in f.iteritems(): if type(n) != type(0): n = len(n) - items.append((c,n)) + items.append((c, n)) items.sort(cmp2) - for c,n in items: + for c, n in items: print '%s: %s' % (c, '#' * n) + def neighbors(txt): out = {} for dg, w in bigrams(txt).iteritems(): - count = len(w) - n = out.get(dg[0], Set()) n.add(dg[1]) out[dg[0]] = n @@ -181,6 +183,7 @@ def rot(n, txt): def caesar(n, txt): return [chr((ord(c) + n) % 256) for c in txt] + def caesars(txt): return [caesar(i, txt) for i in range(256)] @@ -194,6 +197,7 @@ def xor(n, txt): out = [(chr(ord(c) ^ n)) for c in txt] return ''.join(out) + def xors(txt): ret = [] for n in range(256): @@ -208,6 +212,7 @@ def add(n, txt): out += chr(o) return out + def adds(txt): ret = [] for n in range(256): @@ -215,7 +220,7 @@ def adds(txt): return ret -class XorMask: +class XorMask(object): def __init__(self, mask, stick=False): self.offset = 0 if type(mask) == type(''): @@ -259,6 +264,7 @@ def matches(str, tgt): return True + def guess(pattern): ret = [] @@ -275,6 +281,7 @@ def guess(pattern): ## Overview tools ## + def summary(txt): print "Length", len(txt) print "Factors", factor(len(txt)) diff --git a/netarch/gapstr.py b/netarch/gapstr.py index 7e9a547..6ae005d 100644 --- a/netarch/gapstr.py +++ b/netarch/gapstr.py @@ -8,10 +8,12 @@ Lists should have only byte and numeric items. """ -import __init__ +from . import HexDumper import sys +import string -class GapString: + +class GapString(object): def __init__(self, init=None, drop='?'): self.contents = [] self.length = 0 @@ -50,7 +52,6 @@ class GapString: except TypeError: self.length -= len(item) return GapString(item) - def __str__(self): ret = [] @@ -82,9 +83,7 @@ class GapString: return False def hexdump(self, fd=sys.stdout): - offset = 0 - - d = __init__.HexDumper(fd) + d = HexDumper(fd) for i in self.contents: try: for j in xrange(i): @@ -139,7 +138,7 @@ class GapString: def __getitem__(self, idx): if False: - c = self[idx:idx+1] + c = self[idx:idx + 1] if c.hasgaps(): return self.drop[0] else: @@ -213,7 +212,7 @@ class GapString: except ValueError: break ret.append(cur[:pos]) - cur = cur[pos+len(pivot):] + cur = cur[pos + len(pivot):] ret.append(cur) return ret @@ -243,4 +242,3 @@ if __name__ == '__main__': assert len(gs[:4]) == 4 assert len(gs[6:]) == 4 assert str(gs[:0]) == '' - diff --git a/netarch/ip.py b/netarch/ip.py index e4832a1..00be913 100644 --- a/netarch/ip.py +++ b/netarch/ip.py @@ -3,41 +3,49 @@ ## IP resequencing + protocol reversing skeleton ## 2008 Massive Blowout -import StringIO -import struct -import socket -import warnings -import heapq -import gapstr -import time -try: - import pcap -except ImportError: - import py_pcap as pcap -import os import cgi +import heapq +import os +import rfc822 +import socket +import struct +import StringIO +import time import urllib import UserDict -from __init__ import * +import warnings + +try: + import pcap + if "open" not in dir(pcap): + raise ImportError() +except ImportError: + import py_pcap as pcap + +from . import unpack, hexdump +import gapstr + def unpack_nybbles(byte): return (byte >> 4, byte & 0x0F) +# constants transfers = os.environ.get('TRANSFERS', 'transfers') IP = 0x0800 ARP = 0x0806 VLAN = 0x8100 - ICMP = 1 -TCP = 6 -UDP = 17 +TCP = 6 +UDP = 17 + def str_of_eth(d): return ':'.join([('%02x' % ord(x)) for x in d]) -class Frame: + +class Frame(object): """Turn an ethernet frame into relevant parts""" def __init__(self, pkt): @@ -71,7 +79,7 @@ class Frame: (self.ihlvers, self.tos, self.tot_len, - self.id, + self.ipid, self.frag_off, self.ttl, self.protocol, @@ -110,7 +118,7 @@ class Frame: (self.type, self.code, self.cheksum, - self.id, + self.ipid, self.seq, p) = unpack('!BBHHH', p) self.payload = p[:self.tot_len - 8] @@ -124,13 +132,13 @@ class Frame: self.dst = (self.daddr, self.dport) # This hash is the same for both sides of the transaction + self.iphash = self.saddr ^ self.daddr self.hash = (self.saddr ^ (self.sport or 0) ^ self.daddr ^ (self.dport or 0)) else: self.name = 'Ethernet type %d' % self.eth_type self.protocol = None - def get_src_addr(self): saddr = struct.pack('!i', self.saddr) self.src_addr = socket.inet_ntoa(saddr) @@ -152,16 +160,15 @@ class Frame: def __arp_repr__(self): return ' %s(%s)>' % (self.name, - str_of_eth(self.ar_sha), - self.src_addr, - str_of_eth(self.ar_tha), - self.dst_addr) + str_of_eth(self.ar_sha), self.src_addr, + str_of_eth(self.ar_tha), self.dst_addr) -class TCP_Recreate: + +class TCP_Recreate(object): closed = True - def __init__(self, pcap, src, dst, timestamp): - self.pcap = pcap + def __init__(self, pcapobj, src, dst, timestamp): + self.pcap = pcapobj self.src = (socket.inet_aton(src[0]), src[1]) self.dst = (socket.inet_aton(dst[0]), dst[1]) self.sid = self.did = 0 @@ -172,27 +179,27 @@ class TCP_Recreate: def write_header(self): p = '\0\0\0\0\0\0\0\0\0\0\0\0\xfe\xed' - self.pcap.write(((0,0,len(p)), p)) + self.pcap.write(((0, 0, len(p)), p)) def packet(self, cli, payload, flags=0): if cli: sip, sport = self.src dip, dport = self.dst - id = self.sid + ipid = self.sid self.sid += 1 seq = self.sseq self.sseq += len(payload) - if flags & (SYN|FIN): + if flags & (SYN | FIN): self.sseq += 1 ack = self.dseq else: sip, sport = self.dst dip, dport = self.src - id = self.did + ipid = self.did self.did += 1 seq = self.dseq self.dseq += len(payload) - if flags & (SYN|FIN): + if flags & (SYN | FIN): self.dseq += 1 ack = self.sseq if not (flags & ACK): @@ -203,33 +210,31 @@ class TCP_Recreate: IP) iphdr = struct.pack('!BBHHHBBH4s4s', - 0x45, # Version, Header length/32 - 0, # Differentiated services / ECN - 40+len(payload), # total size - id, - 0x4000, # Don't fragment, no fragment offset - 6, # TTL - TCP, # Protocol - 0, # Header checksum + 0x45, # Version, Header length/32 + 0, # Differentiated services / ECN + 40 + len(payload), # total size + ipid, + 0x4000, # Don't fragment, no fragment offset + 6, # TTL + TCP, # Protocol + 0, # Header checksum sip, dip) shorts = struct.unpack('!hhhhhhhhhh', iphdr) shsum = sum(shorts) - ipsum = struct.pack('!h', (~shsum & 0xffff) - 2) # -2? WTF? + ipsum = struct.pack('!h', (~shsum & 0xffff) - 2) # -2? WTF? iphdr = iphdr[:10] + ipsum + iphdr[12:] tcphdr = struct.pack('!HHLLBBHHH', sport, dport, - seq, # Sequence number - ack, # Acknowledgement number - 0x50, # Data offset - flags, # Flags - 0xff00, # Window size - 0, # Checksum - 0) # Urgent pointer - - + seq, # Sequence number + ack, # Acknowledgement number + 0x50, # Data offset + flags, # Flags + 0xff00, # Window size + 0, # Checksum + 0) # Urgent pointer return ethhdr + iphdr + tcphdr + str(payload) @@ -245,14 +250,14 @@ class TCP_Recreate: self.write_pkt(timestamp, cli, d, ACK) def handshake(self, timestamp): - self.write_pkt(timestamp, True, '', SYN) - self.write_pkt(timestamp, False, '', SYN|ACK) + self.write_pkt(timestamp, True, '', SYN) + self.write_pkt(timestamp, False, '', SYN | ACK) #self.write_pkt(timestamp, True, '', ACK) def close(self): - self.write_pkt(self.lastts, True, '', FIN|ACK) - self.write_pkt(self.lastts, False, '', FIN|ACK) - self.write_pkt(self.lastts, True, '', ACK) + self.write_pkt(self.lastts, True, '', FIN | ACK) + self.write_pkt(self.lastts, False, '', FIN | ACK) + self.write_pkt(self.lastts, True, '', ACK) def __del__(self): if not self.closed: @@ -264,7 +269,8 @@ RST = 4 PSH = 8 ACK = 16 -class TCP_Resequence: + +class TCP_Resequence(object): """TCP session resequencer. >>> p = pcap.open('whatever.pcap') @@ -298,7 +304,6 @@ class TCP_Resequence: self.handle = self.handle_handshake - def bundle_pending(self, xdi, pkt, seq): """Bundle up any pending packets. @@ -357,7 +362,6 @@ class TCP_Resequence: return ret - def handle(self, pkt): """Stub. @@ -367,7 +371,6 @@ class TCP_Resequence: raise NotImplementedError() - def handle_handshake(self, pkt): if not self.first: self.first = pkt @@ -395,7 +398,6 @@ class TCP_Resequence: self.handle = self.handle_packet self.handle(pkt) - def handle_packet(self, pkt): # Which way is this going? 0 == from client idx = int(pkt.src == self.srv) @@ -417,7 +419,6 @@ class TCP_Resequence: if pkt.ack > seq: return self.bundle_pending(xdi, pkt, seq) - def handle_drop(self, pkt): """Warn about any unhandled packets""" @@ -431,7 +432,7 @@ class TCP_Resequence: hexdump(pkt.payload) -class Dispatch: +class Dispatch(object): def __init__(self, *filenames): self.pcs = {} @@ -490,6 +491,7 @@ class Dispatch: class NeedMoreData(Exception): pass + class Packet(UserDict.DictMixin): """Base class for a packet from a binary protocol. @@ -520,7 +522,6 @@ class Packet(UserDict.DictMixin): r += '>' return r - ## Dict methods def __setitem__(self, k, v): self.params[k] = v @@ -535,7 +536,7 @@ class Packet(UserDict.DictMixin): return self.params.__iter__() def has_key(self, k): - return self.params.has_key(k) + return k in self.params def keys(self): return self.params.keys() @@ -600,7 +601,7 @@ class Packet(UserDict.DictMixin): """Handle data from a Session class.""" data = self.parse(data) - if self.opcode <> None: + if self.opcode != None: try: f = getattr(self, 'opcode_%s' % self.opcode) except AttributeError: @@ -713,7 +714,7 @@ class Session: def handle_packets(self, collection): """Handle a collection of packets""" - for chunk in resequence(collection): + for chunk in TCP_Resequence(collection): self.handle(chunk) self.done() @@ -739,18 +740,16 @@ class HtmlSession(Session): ''' % self.__class__.__name__) self.sessfd.write('

%s

\n' % self.__class__.__name__) self.sessfd.write('
')
-        self.srv = None
 
     def __del__(self):
         self.sessfd.write('
') + self.sessfd.close() def log(self, frame, payload, escape=True): if escape: - p = cgi.escape(str(payload)) + p = cgi.escape(unicode(payload)) else: p = payload - if not self.srv: - self.srv = frame.saddr if frame.saddr == self.srv: cls = 'server' else: @@ -763,4 +762,3 @@ class HtmlSession(Session): self.sessfd.write('%s' % (cls, ts, cls)) self.sessfd.write(p.replace('\r\n', '\n')) self.sessfd.write('') - diff --git a/netarch/py_pcap.py b/netarch/py_pcap.py old mode 100755 new mode 100644 index 44e53de..a5ffe22 --- a/netarch/py_pcap.py +++ b/netarch/py_pcap.py @@ -4,7 +4,8 @@ import struct _MAGIC = 0xA1B2C3D4 -class pcap: + +class pcap(object): def __init__(self, stream, mode='rb', snaplen=65535, linktype=1): try: self.stream = file(stream, mode) @@ -77,11 +78,11 @@ open_offline = pcap if __name__ == '__main__': - p = open('test.pcap', 'w') # Create a new file - p.write(((0, 0, 3), 'foo')) # Add a packet + p = open('test.pcap', 'w') # Create a new file + p.write(((0, 0, 3), 'foo')) # Add a packet p.write(((0, 0, 3), 'bar')) del p - p = open(file('test.pcap')) # Also takes file objects + p = open(file('test.pcap')) # Also takes file objects assert ((p.version, p.thiszone, p.sigfigs, p.snaplen, p.linktype) == ((2, 4), 0, 0, 65535, 1)) assert ([i for i in p] == [((0, 0, 3), 'foo'), ((0, 0, 3), 'bar')])