All pastes #430039 Raw Edit

Anonymous

public text v1 · immutable
·published 2007-04-08 17:57 UTC
rendered paste body
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> - 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 :)"