import struct import copy import sys def xors(a,b): return "".join([chr(ord(x1)^ord(x2)) for x1,x2 in zip(a,b)]) class PCAPPacket: def __init__(self,pheader): pheader = struct.unpack("IIII",pheader) self.ts_sec = pheader[0] self.ts_usec = pheader[1] self.incl_len = pheader[2] self.orig_len = pheader[3] class PCAPReader: def __init__(self,fname): f = open(fname,"rb") buf = f.read(4+2+2+4+4+4+4) header = struct.unpack("IHHiIII",buf) self.magic = header[0] self.version_major = header[1] self.version_minor = header[2] self.thiszone = header[3] self.sigfigs = header[4] self.snaplen = header[5] self.network = header[6] self.packets = [] buf = f.read(4+4+4+4) while len(buf) > 0: pkt = PCAPPacket(buf) pkt.data = f.read(pkt.incl_len) self.packets.append(pkt) buf = f.read(4+4+4+4) class EthPacket: def __init__(self,data): headlen = 6+6+2 head = struct.unpack("!6s6sH",data[:headlen]) self.dst = head[0] self.src = head[1] self.type = head[2] self.data = data[headlen:] class IPPacket: def __init__(self,data): headlen = 1+1+2+2+2+1+1+2+4+4 head = struct.unpack("!BBHHHBBH4s4s",data[:headlen]) self.version = head[0] >> 4 self.hlen = head[0] & 0xF self.TOS = head[1] self.len = head[2] self.id = head[3] self.flags_fragment = head[4] self.TTL = head[5] self.protocol = head[6] self.checksum = head[7] self.src = head[8] self.dst = head[9] optsend = self.hlen*4 self.opts = data[headlen:optsend] self.data = data[optsend:self.len] self.trailer = data[self.len:] class TCPPacket: def __init__(self,data): headlen = 2+2+4+4+1+1+2+2+2 head = struct.unpack("!HHIIBBHhH",data[:headlen]) self.srcport = head[0] self.dstport = head[1] self.seq = head[2] self.ack = head[3] self.hlen = head[4] >> 4 self.flags = head[5] self.window = head[6] self.checksum = head[7] self.urgent = head[8] optsend = self.hlen * 4 self.opts = data[headlen:optsend] self.data = data[optsend:] def filter_tcp_packets_only(packets): out = [] for p in packets: e = EthPacket(p.data) if e.type != 0x800: continue e.data = IPPacket(e.data) if e.data.protocol != 6: continue e.data.data = TCPPacket(e.data.data) out.append(e) return out def make_constr(srcip,srcport,dstip,dstport): return struct.pack("4sH4sH",srcip,srcport,dstip,dstport) def make_constr_from_packet(e,reverse = False): if not reverse: return make_constr(e.data.src,e.data.data.srcport,e.data.dst,e.data.data.dstport) else: return make_constr(e.data.dst,e.data.data.dstport,e.data.src,e.data.data.srcport) def split_constr(str): return struct.unpack("4sH4sH",str) def split_into_streams(pkts): streams = {} for p in pkts: connstr1 = make_constr_from_packet(p) connstr2 = make_constr_from_packet(p,True) if connstr1 in streams: connstr = connstr1 elif connstr2 in streams: connstr = connstr2 else: connstr = connstr1 streams[connstr] = [] streams[connstr].append(p) return streams def produce_data_stream(tcpstrm): fstr = make_constr_from_packet(tcpstrm[0]) return [(make_constr_from_packet(x) == fstr,x.data.data.data) for x in tcpstrm if len(x.data.data.data) != 0] def find_wow_streams(streams): wowstreams = [] realmlists = [(12,129,232,116),(80,239,180,116),(211,115,104,109)] realmlists = ["".join([chr(x) for x in y]) for y in realmlists] for k in streams.keys(): data = split_constr(k) if data[1] != 3724 and data[3] != 3724: continue dstrm = produce_data_stream(streams[k]) if len(dstrm) < 5: continue if len(dstrm[0][1]) != 8: continue wowstreams.append(dstrm) return wowstreams def split_streams(dstrm): ins = [] insizes = [] outs = [] outsizes = [] in_inpkt = False in_tsize = 0 out_inpkt = False out_tsize = 0 for d in dstrm: size = len(d[1])-2 if d[0]: data = d[1][:6] if not out_inpkt: outs.append(data) out_inpkt = True out_tsize += size if size != 1458: outsizes.append(out_tsize) out_inpkt = False out_tsize = 0 else: data = d[1][:4] if not in_inpkt: ins.append(data) in_inpkt = True in_tsize += size if size != 1458: insizes.append(in_tsize) in_inpkt = False in_tsize = 0 # Remove first unencrypted packet from each part outs = outs[1:] ins = ins[1:] outsizes = outsizes[1:] insizes = insizes[1:] return [("".join(outs),outsizes),("".join(ins),insizes)] def remove_j_part(stream,j=0): out = [] for i in range(len(stream)): x = (ord(stream[i]) - j) % 256 j = ord(stream[i]) out.append(chr(x)) return "".join(out) def remove_js(ss): return [(remove_j_part(ss[0][0]),ss[0][1]),(remove_j_part(ss[1][0]),ss[1][1])] def assume0s(data): out = [] for i in range(40): out.append([]) i = 0 for x in range(0,len(data),6): i += 4 i %= 40 out[i].append(data[x+4]) i += 1 i %= 40 out[i].append(data[x+5]) i += 1 i %= 40 return out def decrypt(buf,k,i=0): out = [] for c in buf: i %= len(k) out.append(chr(ord(c)^ord(k[i]))) i += 1 return "".join(out) def make_straight_datastream(dstrm): outx = [] inx = [] for pkt in dstrm: if pkt[0]: outx.append(pkt[1]) else: inx.append(pkt[1]) return ("".join(outx),"".join(inx)) def try_decrypt_data(dstrm,k,sz): i = 0 j = 0 pkts = [] curr = 0 while curr < len(dstrm): header = decrypt(remove_j_part(dstrm[curr:curr+sz],j),k,i) i += sz i %= 40 j = ord(dstrm[curr+sz-1]) size = struct.unpack("!H",header[:2])[0] data = dstrm[curr+2:curr+2+size] pkts.append(data) curr += size + 2 return pkts if len(sys.argv) != 2: print "Useage: %s - capfile is the path to the cap file."%sys.argv[0] sys.exit(1) print "Reading cap file..." reader = PCAPReader(sys.argv[1]) print "Filtering for TCP packets..." tcp = filter_tcp_packets_only(reader.packets) print "Splitting into streams..." strms = split_into_streams(tcp) print "Finding WoW streams..." wstrm = find_wow_streams(strms) print "%u streams found."%len(wstrm) for i in range(len(wstrm)): print "Stream %u:"%i print "Removing J part..." sj = remove_js(split_streams(wstrm[i])) print "Getting K from 0s..." kx = assume0s(sj[0][0]) k = "".join([x[0] for x in kx]) print "Getting data for decryption..." data = make_straight_datastream(wstrm[0][2:])[0] print "Decrypting..." dc = try_decrypt_data(data,k,6) if sum([len(x) for x in dc]) + 2 * len(dc) == len(data): print "Success!" print [hex(ord(x)) for x in k] else: print "Failure :(" print "Done :)"