rendered paste bodyimport 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> - 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 :)"