Esempio n. 1
0
def handleStream(tcp):
    def decrypt_packed_string(__src):
        global key
        global src
        global size
        src = __src
        key = unpack("<I", __src[0:4])[0]
        if key == 0x54534f50 or key == 0x50545448:
            return src, 0xffff, ''
        #chop.tsprnt(hex(key))
        size = 16
        stage1 = decrypt()
        #chop.tsprnt(repr(hex(unpack("<I", stage1[0:4])[0])),repr(hex(unpack("<I",stage1[4:8])[0])),repr(hex(unpack("H",stage1[8:10])[0])),repr(hex(unpack("H",stage1[10:12])[0])))
        flags = unpack("<I", stage1[4:8])[0]
        #chop.tsprnt(hex(flags))
        #chop.tsprnt(repr(stage1[8:10]))
    
        if flags & 0x2000000:      #do not decrypt payload separately
            if tcp.module_data['verbose']:
                chop.tsprnt("do not decrypt separately")
            size = len(src)
            stage1 = decrypt()
            # consider removing the verbosity filter here if you're seeing the do not decrypt message and not data.
            if tcp.module_data['verbose']:
                chop.tsprnt(unpack("H",stage1[8:10])[0])
        else:
            size = len(src[16:])
            src = __src[16:]
            stage1 = stage1 + decrypt()
        
        if flags & 0x1000000:      #do not decompress payload
            if tcp.module_data['verbose']:
                chop.tsprnt("do not decompress")
            return stage1, flags, ''
        else:
            if flags in module_data['flags'].keys():
                comp = stage1[16:] 
                if tcp.module_data['verbose']:
                    chop.tsprnt("len of payload: %d   len in header: %d" % (len(comp), unpack("H",stage1[8:10])[0]))
                if len(comp) == unpack("H",stage1[8:10]):
                    return stage1[:16], flags, comp
                return stage1[:16], flags, comp[:unpack("H",stage1[8:10])[0]]
    
            decomp = ''
            #chop.tsprnt(repr(stage1[:16]),repr(stage1[16:]))
    
        return stage1[:16]+decomp, flags, ''
    
    def decrypt():
        global key
        global new_key
        global key0
        global key1
        global key2
        global key3
        global src
        global dst
        global res
        global i
        global size
        key0 = key
        key1 = key
        key2 = key
        key3 = key
        dst = b''
        i = 0

        if size > 0:
            while i < size:

                if tcp.module_data['protocol'] == 0:
                    key0 = (key0 + (((key0 >> 3)&0xFFFFFFFF) - 0x11111111)&0xFFFFFFFF)&0xFFFFFFFF
                    key1 = (key1 + (((key1 >> 5)&0xFFFFFFFF) - 0x22222222)&0xFFFFFFFF)&0xFFFFFFFF
                    key2 = (key2 + (0x44444444 - ((key2 << 9)&0xFFFFFFFF))&0xFFFFFFFF)&0xFFFFFFFF
                    key3 = (key3 + (0x33333333 - ((key3 << 7)&0xFFFFFFFF))&0xFFFFFFFF)&0xFFFFFFFF
                    new_key = (((key2&0xFF) + (key3&0xFF) + (key1&0xFF) + (key0&0xFF))&0xFF)

                elif tcp.module_data['protocol'] == 1:
                    key0 = (key0 + ((key0 >> 3) + 3)&0xFFFFFFFF)&0xFFFFFFFF
                    key1 = (key1 + (((key1 >> 5)&0xFFFFFFFF) + 5)&0xFFFFFFFF)&0xFFFFFFFF
                    key2 = (0xFFFFFF81 * (key2 & 0xFFFFFFFF)-7)&0xFFFFFFFF
                    key3 = (0xFFFFFE01 * (key3 & 0xFFFFFFFF)-9)&0xFFFFFFFF
                    new_key = (((key2&0xFF) + (key3&0xFF) + (key1&0xFF) + (key0&0xFF))&0xFF)

                else:
                    new_key = 0xFF

                if tcp.module_data['verbose']:
                    chop.tsprnt(hex(new_key),hex(key0),hex(key1),hex(key2),hex(key3))

                res = unpack("<B", src[i:i+1])[0] ^ new_key
                dst = dst + pack("<B", res)
                i = i + 1
        
        return dst

    data = ''

    # collect time and IP metadata
    ((src, sport), (dst, dport)) = tcp.addr
    # handle client system packets
    if tcp.server.count_new > 0:
        data = tcp.server.data[:tcp.server.count_new]
        if not data[:6] == 'POST /' and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted,flags, comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt("c2_side - precrypt - key:%s flag:%s szComp:%s szDeComp:%s" % (repr(hex(unpack("<I", data[0:4])[0])),repr(hex(unpack("<I",data[4:8])[0])),repr(hex(unpack("H",data[8:10])[0])),repr(hex(unpack("H",data[10:12])[0]))))
            chop.tsprnt("c2_side - postcrypt - key:%s flag:%s szComp:%s szDeComp:%s" % (repr(hex(unpack("<I", decrypted[0:4])[0])),repr(hex(unpack("<I",decrypted[4:8])[0])),repr(hex(unpack("H",decrypted[8:10])[0])),repr(hex(unpack("H",decrypted[10:12])[0]))))
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("c2 decrypted header: %s   flag: %s" % (repr(decrypted),hex(flags)))
            if comp: 
                chop.tsprnt("printable chars sent to c2",repr(lznt1.dCompressBuf(comp).replace("\x00","")),module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to c2 %s" % repr(lznt1.dCompressBuf(comp)))

        tcp.discard(tcp.server.count_new)
    # handle server system packets
    if tcp.client.count_new > 0:
        data = tcp.client.data[:tcp.client.count_new]
        if not data[:6] == 'POST /'  and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted,flags,comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt("bot_side - precrypt: %s %s %s %s" % (repr(hex(unpack("<I", data[0:4])[0])),repr(hex(unpack("<I",data[4:8])[0])),repr(hex(unpack("H",data[8:10])[0])),repr(hex(unpack("H",data[10:12])[0]))))
            chop.tsprnt("bot_side - postcrypt: %s %s %s %s" % (repr(hex(unpack("<I", decrypted[0:4])[0])),repr(hex(unpack("<I",decrypted[4:8])[0])),repr(hex(unpack("H",decrypted[8:10])[0])),repr(hex(unpack("H",decrypted[10:12])[0]))))
            chop.tsprnt(comp)
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("bot decrypted header: %s   flag: %s" % (repr(decrypted),hex(flags)))
            if comp: 
                chop.tsprnt("printable chars sent to bot",repr(lznt1.dCompressBuf(comp).replace("\x00","")),module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to bot message %s" % repr(lznt1.dCompressBuf(comp)))
        tcp.discard(tcp.client.count_new)

    if tcp.stream_data['flag']:
        while data:
            #stuff!
            break

        #chop.tsprnt("Finding flag: %s:%i->%s:%i (%i)" % (src, sport, dst, dport, len(data)))
        # Sometimes our data isn't all in one packet? I'm not sure why I am fighting this bug
        #if not tcp.stream_data['flag']:
            #chop.tsprnt("No flag found, skipping stream.")
            #tcp.stop()
    return
Esempio n. 2
0
def handleStream(tcp):

    data = ''

    # collect time and IP metadata
    ((src, sport), (dst, dport)) = tcp.addr
    # handle client system packets
    if tcp.server.count_new > 0:
        data = tcp.server.data[:tcp.server.count_new]
        if not data[:6] == 'POST /' and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted,flags, comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt("c2_side - precrypt - key:%s flag:%s szComp:%s szDeComp:%s" % (repr(hex(unpack("<I", data[0:4])[0])),repr(hex(unpack("<I",data[4:8])[0])),repr(hex(unpack("H",data[8:10])[0])),repr(hex(unpack("H",data[10:12])[0]))))
            chop.tsprnt("c2_side - postcrypt - key:%s flag:%s szComp:%s szDeComp:%s" % (repr(hex(unpack("<I", decrypted[0:4])[0])),repr(hex(unpack("<I",decrypted[4:8])[0])),repr(hex(unpack("H",decrypted[8:10])[0])),repr(hex(unpack("H",decrypted[10:12])[0]))))
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("c2 decrypted header: %s   flag: %s" % (repr(decrypted),hex(flags)))
            if comp: 
                chop.tsprnt("printable chars sent to c2",repr(lznt1.dCompressBuf(comp).replace("\x00","")),module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to c2 %s" % repr(lznt1.dCompressBuf(comp)))

        tcp.discard(tcp.server.count_new)
    # handle server system packets
    if tcp.client.count_new > 0:
        data = tcp.client.data[:tcp.client.count_new]
        if not data[:6] == 'POST /'  and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted,flags,comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt("bot_side - precrypt: %s %s %s %s" % (repr(hex(unpack("<I", data[0:4])[0])),repr(hex(unpack("<I",data[4:8])[0])),repr(hex(unpack("H",data[8:10])[0])),repr(hex(unpack("H",data[10:12])[0]))))
            chop.tsprnt("bot_side - postcrypt: %s %s %s %s" % (repr(hex(unpack("<I", decrypted[0:4])[0])),repr(hex(unpack("<I",decrypted[4:8])[0])),repr(hex(unpack("H",decrypted[8:10])[0])),repr(hex(unpack("H",decrypted[10:12])[0]))))
            chop.tsprnt(comp)
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("bot decrypted header: %s   flag: %s" % (repr(decrypted),hex(flags)))
            if comp: 
                chop.tsprnt("printable chars sent to bot",repr(lznt1.dCompressBuf(comp).replace("\x00","")),module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to bot message %s" % repr(lznt1.dCompressBuf(comp)))
        tcp.discard(tcp.client.count_new)

    if tcp.stream_data['flag']:
        while data:
            #stuff!
            break

        #chop.tsprnt("Finding flag: %s:%i->%s:%i (%i)" % (src, sport, dst, dport, len(data)))
        # Sometimes our data isn't all in one packet? I'm not sure why I am fighting this bug
        #if not tcp.stream_data['flag']:
            #chop.tsprnt("No flag found, skipping stream.")
            #tcp.stop()
    return
Esempio n. 3
0
def handleStream(tcp):
    sd = tcp.stream_data
    md = tcp.module_data

    if tcp.client.count_new > 0:
        sd['client_buffer'] += tcp.client.data[:tcp.client.count_new]
        if sd['client_state'] == "challenged":
            if len(sd['client_buffer']) >= 256:
                challenge_resp = sd['client_buffer'][:256]
                sd['client_buffer'] = sd['client_buffer'][256:]
                if md['pwlist']:
                    if TryKeyList(md['pwlist'], sd['challenge'],
                                  challenge_resp, md['camcrypt']):
                        if md['verbose'] or md['debug']:
                            chop.tsprnt("PI challenge response accepted..")
                        sd['client_state'] = "challenge_accepted"
                        tcp.discard(tcp.client.count_new)
                        return
                if challenge_resp == CamelliaEncrypt(sd['challenge'],
                                                     md['camcrypt']):
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI challenge response accepted..")
                    sd['client_state'] = "challenge_accepted"
                    tcp.discard(tcp.client.count_new)
                    return
                else:
                    sd['client_state'] = "challenge_failed"
                    if md['verbose'] or md['debug']:
                        chop.tsprnt(
                            "PI challenge response not valid for supplied passwords(s), skipping stream.."
                        )
                    #sd['challenge_accepted'] = True
                    tcp.stop()
                    return

        if sd['client_state'] == "double_challenged":
            if len(sd['client_buffer']) >= 260:
                challenge_resp = sd['client_buffer'][:256]
                sd['client_buffer'] = sd['client_buffer'][256:]
                (a, b) = struct.unpack('>HH', tcp.client.data[:4])
                a ^= 0xd015
                if a != b:
                    sd['client_state'] = "challenge_failed"
                    if md['verbose'] or md['debug']:
                        chop.tsprnt(
                            "PI challenge not valid, skipping stream..")
                    tcp.stop()
                    return
                sd['xor'] = a & 0xFF
                chop.tsprnt("PI double nonce xor variant, xor key: %02X" %
                            sd['xor'])
                if md['pwlist']:
                    if TryKeyList(md['pwlist'], sd['challenge'],
                                  challenge_resp, md['camcrypt'], sd['xor']):
                        if md['verbose'] or md['debug']:
                            chop.tsprnt("PI challenge response accepted..")
                        sd['client_state'] = "challenge_accepted"
                        tcp.discard(tcp.client.count_new)
                        return
                if challenge_resp == CamelliaEncrypt(
                        one_byte_xor(sd['challenge'], sd['xor']),
                        md['camcrypt'], sd['xor']):
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI challenge response accepted..")
                    sd['client_state'] = "challenge_accepted"
                    tcp.discard(tcp.client.count_new)
                    return
                else:
                    sd['client_state'] = "challenge_failed"
                    if md['verbose'] or md['debug']:
                        chop.tsprnt(
                            "PI double challenge response not valid for supplied passwords(s), skipping stream.."
                        )
                    #sd['challenge_accepted'] = True
                    tcp.stop()
                    return

        if sd['client_state'] == "challenge_accepted":
            if len(sd['client_buffer']) >= 4:
                if 'xor' in sd:
                    sd['init_size'] = unpack(
                        "<I", one_byte_xor(sd['client_buffer'][:4],
                                           sd['xor']))[0]
                else:
                    sd['init_size'] = unpack("<I", sd['client_buffer'][:4])[0]
                sd['client_state'] = "init_code_collection"
                sd['client_buffer'] = sd['client_buffer'][4:]

        if sd['client_state'] == "init_code_collection":
            if sd['init_size'] <= len(sd['client_buffer']):
                sd['client_state'] = "init_code_collected"
                #decrypted = CamelliaDecrypt(sd['client_buffer'][:sd['init_size']], md['camcrypt'])
                if md['debug']:
                    chop.tsprnt("init code size: %08X" % sd['init_size'])
                sd['client_buffer'] = sd['client_buffer'][sd['init_size']:]

        if sd['client_state'] == "init_code_collected":
            if len(sd['client_buffer']) >= 4:
                if 'xor' in sd:
                    sd['version'] = unpack(
                        "<I", one_byte_xor(sd['client_buffer'][:4],
                                           sd['xor']))[0]
                else:
                    sd['version'] = unpack("<I", sd['client_buffer'][:4])[0]
                sd['client_buffer'] = sd['client_buffer'][4:]
                sd['client_state'] = "version_collected"
                chop.tsprnt("Poison Ivy Version: %0.2f" %
                            (sd['version'] / 100.00))

        if sd['client_state'] == "version_collected":
            if len(sd['client_buffer']) >= 4:
                if 'xor' in sd:
                    sd['init_size'] = unpack(
                        "<I", one_byte_xor(sd['client_buffer'][:4],
                                           sd['xor']))[0]
                else:
                    sd['init_size'] = unpack("<I", sd['client_buffer'][:4])[0]
                sd['client_buffer'] = sd['client_buffer'][4:]
                sd['client_state'] = "stub_code_collection"
                if md['debug']:
                    chop.tsprnt("stub code size: %08X" % sd['init_size'])

        if sd['client_state'] == "stub_code_collection":
            if sd['init_size'] <= len(sd['client_buffer']):
                sd['client_state'] = "stub_code_collected"
                if md['debug']:
                    chop.tsprnt("stub code collected..")
                sd['client_buffer'] = sd['client_buffer'][sd['init_size']:]

        if sd['client_state'] == "stub_code_collected":
            #initialization complete
            if md['debug']:
                chop.tsprnt("init complete..")
            sd['client_state'] = "read_header"
            sd['server_state'] = "read_header"
            sd['server_buffer'] = ""

        if sd['client_state'] == "read_header":
            listid = sd['client_cur_listid']
            if len(sd['client_buffer']) >= 32:
                (sd['client_cur_listid'],
                 newstream) = getHeaders("in", sd['client_buffer'][:32], tcp)
                listid = sd['client_cur_listid']
                sd['client_state'] = "recv_chunk"
                sd['client_buffer'] = sd['client_buffer'][32:]
                if newstream:
                    if sd['inbound_type'].get(listid) == 6:
                        #handle file data
                        decrypted = CamelliaDecrypt(
                            sd['client_buffer']
                            [:sd['inbound_chunk_size'].get(listid)],
                            md['camcrypt'], sd.get('xor', None))
                        sd['client_buffer'] = sd['client_buffer'][
                            sd['inbound_chunk_size'].get(listid):]
                        if sd['inbound_unpadded_chunk_size'].get(listid) != sd[
                                'inbound_decompressed_chunk_size'].get(listid):
                            buf = lznt1.dCompressBuf(
                                decrypted[:sd['inbound_unpadded_chunk_size'].
                                          get(listid)])
                            if buf == None:
                                chop.tsprnt("decompression error:\n%s" %
                                            hexdump(decrypted))
                                tcp.stop()
                        else:
                            buf = decrypted[:sd['inbound_unpadded_chunk_size'].
                                            get(listid)]
                        #decompressed = lznt1.dCompressBuf(decrypted[:sd['inbound_unpadded_chunk_size']])
                        filename = string.strip(buf, "\x00")
                        sd['inbound_filename'][
                            listid] = "PI-extracted-inbound-file-%d-%s" % (
                                md['filecount'],
                                filename[string.rfind(filename, "\\") + 1:])
                        md['filecount'] += 1
                        chop.tsprnt("inbound file %s " % filename)

                        sd['client_state'] = "read_header"

                    sd['inbound_size_left'][listid] = sd[
                        'inbound_total_size'].get(listid)

            if sd['inbound_size_left'].get(listid) == 0:
                sd['inbound_size_left'][listid] = sd['inbound_total_size'].get(
                    listid)

        if sd['client_state'] == "recv_chunk":
            listid = sd['client_cur_listid']
            if sd['inbound_chunk_size'].get(listid) <= len(
                    sd['client_buffer']):
                if md['debug']:
                    chop.tsprnt("handling inbound chunk.. %d bytes to go" %
                                sd['inbound_size_left'].get(listid))
                sd['client_state'] = "read_header"
                decrypted = CamelliaDecrypt(
                    sd['client_buffer'][:sd['inbound_chunk_size'].get(listid)],
                    md['camcrypt'], sd.get('xor', None))
                decrypted = decrypted[:sd['inbound_unpadded_chunk_size'].
                                      get(listid)]
                buf = decrypted
                if sd['inbound_unpadded_chunk_size'].get(listid) != sd[
                        'inbound_decompressed_chunk_size'].get(listid):
                    buf = lznt1.dCompressBuf(decrypted)
                    if buf == None:
                        chop.tsprnt("decompression error:\n%s" %
                                    hexdump(decrypted))
                        tcp.stop()
                sd['client_collect_buffer'][listid] += buf
                sd['client_buffer'] = sd['client_buffer'][
                    sd['inbound_chunk_size'].get(listid):]
                sd['inbound_size_left'][listid] -= sd[
                    'inbound_decompressed_chunk_size'].get(listid)
                if sd['inbound_type'].get(listid) == 6 and md['savefiles']:
                    #inbound file
                    chop.savefile(sd['inbound_filename'].get(listid), buf,
                                  False)

                if sd['inbound_size_left'].get(listid) == 0:
                    if sd['inbound_type'].get(listid) == 6:
                        if md['savefiles']:
                            #inbound file
                            chop.finalizefile(
                                sd['inbound_filename'].get(listid))
                            chop.tsprnt("saved %s.." %
                                        sd['inbound_filename'].get(listid))
                    else:
                        analyzeCode(sd['client_collect_buffer'].get(listid),
                                    sd['inbound_type'].get(listid), tcp)
                        if md['debug']:
                            chop.tsprnt("analyzing code..")

                    sd['client_collect_buffer'][listid] = ""

        #chop.tsprnt("to client:%d" % tcp.client.count_new)
        tcp.discard(tcp.client.count_new)
        return

    elif tcp.server.count_new > 0:
        sd['server_buffer'] += tcp.server.data[:tcp.server.count_new]
        if sd['client_state'] == "unauthenticated":
            if len(sd['server_buffer']) >= 256:
                sd['client_state'] = "challenged"
                #chop.tsprnt(hexdump(tcp.server.data[:tcp.server.count_new]))
                sd['challenge'] = sd['server_buffer'][:256]
                sd['server_buffer'] = sd['server_buffer'][256:]
                #chop.tsprnt(hexdump(sd['challenge']))
        elif sd['client_state'] == "challenged":
            if len(sd['server_buffer']) >= 256:
                sd['client_state'] = "double_challenged"
                sd['challenge'] = sd['server_buffer'][:256]
                sd['server_buffer'] = sd['server_buffer'][256:]
        elif sd['client_state'] == "double_challenged":
            if md['verbose'] or md['debug']:
                chop.tsprnt("PI challenge not found, skipping stream..")
            tcp.stop()

        if sd['server_state'] == "read_header":
            listid = sd['server_cur_listid']
            if len(sd['server_buffer']) >= 32:
                (sd['server_cur_listid'],
                 newstream) = getHeaders("out", sd['server_buffer'][:32], tcp)
                listid = sd['server_cur_listid']
                sd['server_state'] = "recv_chunk"
                sd['server_buffer'] = sd['server_buffer'][32:]
                if newstream:
                    if sd['outbound_type'].get(listid) == 4:
                        #handle file data
                        decrypted = CamelliaDecrypt(
                            sd['server_buffer']
                            [:sd['outbound_chunk_size'].get(listid)],
                            md['camcrypt'], sd.get('xor', None))
                        if sd['outbound_unpadded_chunk_size'].get(
                                listid
                        ) != sd['outbound_decompressed_chunk_size'].get(
                                listid):
                            buf = lznt1.dCompressBuf(
                                decrypted[:sd['outbound_unpadded_chunk_size'].
                                          get(listid)])
                            if buf == None:
                                chop.tsprnt("decompression error:\n%s" %
                                            hexdump(decrypted))
                                tcp.stop()
                        else:
                            buf = decrypted[:sd['outbound_unpadded_chunk_size']
                                            .get(listid)]

                        sd['server_buffer'] = sd['server_buffer'][
                            sd['outbound_chunk_size'].get(listid):]
                        filename = string.strip(buf, "\x00")
                        sd['outbound_filename'][
                            listid] = "PI-extracted-outbound-file-%d-%s" % (
                                md['filecount'],
                                filename[string.rfind(filename, "\\") + 1:])
                        md['filecount'] += 1
                        chop.tsprnt("outbound file %s " % filename)

                        sd['server_state'] = "read_header"

                    sd['outbound_size_left'][listid] = sd[
                        'outbound_total_size'].get(listid)

                if sd['outbound_size_left'].get(listid) == 0:
                    sd['outbound_size_left'][listid] = sd[
                        'outbound_total_size'].get(listid)

        if sd['server_state'] == "recv_chunk":
            listid = sd['server_cur_listid']
            if sd['outbound_chunk_size'].get(listid) <= len(
                    sd['server_buffer']):
                if md['debug']:
                    chop.tsprnt("handling outbound chunk.. %d bytes to go" %
                                sd['outbound_size_left'].get(listid))
                sd['server_state'] = "read_header"
                decrypted = CamelliaDecrypt(
                    sd['server_buffer']
                    [:sd['outbound_chunk_size'].get(listid)], md['camcrypt'],
                    sd.get('xor', None))
                decrypted = decrypted[:sd['outbound_unpadded_chunk_size'].
                                      get(listid)]
                buf = decrypted
                if sd['outbound_unpadded_chunk_size'].get(listid) != sd[
                        'outbound_decompressed_chunk_size'].get(listid):
                    buf = lznt1.dCompressBuf(decrypted)
                    if buf == None:
                        chop.tsprnt("decompression error:\n%s" %
                                    hexdump(decrypted))
                        tcp.stop()
                sd['server_collect_buffer'][listid] += buf
                sd['server_buffer'] = sd['server_buffer'][
                    sd['outbound_chunk_size'].get(listid):]
                sd['outbound_size_left'][listid] -= sd[
                    'outbound_decompressed_chunk_size'].get(listid)
                if sd['outbound_type'].get(listid) == 4 and md['savefiles']:
                    #outbound file
                    chop.savefile(sd['outbound_filename'].get(listid), buf,
                                  False)

                if sd['outbound_size_left'].get(listid) == 0:
                    if sd['outbound_type'].get(listid) == 4:
                        if md['savefiles']:
                            #outbound file
                            chop.finalizefile(
                                sd['outbound_filename'].get(listid))
                            chop.tsprnt("saved %s.." %
                                        sd['outbound_filename'].get(listid))
                    else:
                        if md['debug']:
                            chop.tsprnt("outbound data:\n%s" % hexdump(
                                sd['server_collect_buffer'].get(listid)))

                        try:
                            if sd['outbound_type'].get(listid) == 0x5c:
                                md['cmdhandler'][sd['outbound_type'].get(
                                    listid)](sd['server_collect_buffer'].get(
                                        listid), tcp)
                            else:
                                md['cmdhandler'][sd['outbound_type'].get(
                                    listid)](sd['server_collect_buffer'].get(
                                        listid))
                        except:
                            if md['verbose'] or md['debug']:
                                chop.tsprnt("unrecognized command..")

                    sd['server_collect_buffer'][listid] = ""

        tcp.discard(tcp.server.count_new)
        return

    tcp.discard(tcp.server.count_new)
    return
Esempio n. 4
0
def handleStream(tcp):
    def decrypt_packed_string(__src):
        global key
        global src
        global size
        src = __src
        key = unpack("<I", __src[0:4])[0]
        if key == 0x54534f50 or key == 0x50545448:
            return src, 0xffff, ''
        #chop.tsprnt(hex(key))
        size = 16
        stage1 = decrypt()
        #chop.tsprnt(repr(hex(unpack("<I", stage1[0:4])[0])),repr(hex(unpack("<I",stage1[4:8])[0])),repr(hex(unpack("H",stage1[8:10])[0])),repr(hex(unpack("H",stage1[10:12])[0])))
        flags = unpack("<I", stage1[4:8])[0]
        #chop.tsprnt(hex(flags))
        #chop.tsprnt(repr(stage1[8:10]))

        if flags & 0x2000000:  #do not decrypt payload separately
            if tcp.module_data['verbose']:
                chop.tsprnt("do not decrypt separately")
            size = len(src)
            stage1 = decrypt()
            # consider removing the verbosity filter here if you're seeing the do not decrypt message and not data.
            if tcp.module_data['verbose']:
                chop.tsprnt(unpack("H", stage1[8:10])[0])
        else:
            size = len(src[16:])
            src = __src[16:]
            stage1 = stage1 + decrypt()

        if flags & 0x1000000:  #do not decompress payload
            if tcp.module_data['verbose']:
                chop.tsprnt("do not decompress")
            return stage1, flags, ''
        else:
            if flags in module_data['flags'].keys():
                comp = stage1[16:]
                if tcp.module_data['verbose']:
                    chop.tsprnt("len of payload: %d   len in header: %d" %
                                (len(comp), unpack("H", stage1[8:10])[0]))
                if len(comp) == unpack("H", stage1[8:10]):
                    return stage1[:16], flags, comp
                return stage1[:16], flags, comp[:unpack("H", stage1[8:10])[0]]

            decomp = ''
            #chop.tsprnt(repr(stage1[:16]),repr(stage1[16:]))

        return stage1[:16] + decomp, flags, ''

    def decrypt():
        global key
        global new_key
        global key0
        global key1
        global key2
        global key3
        global src
        global dst
        global res
        global i
        global size
        key0 = key
        key1 = key
        key2 = key
        key3 = key
        dst = b''
        i = 0

        if size > 0:
            while i < size:

                if tcp.module_data['protocol'] == 0:
                    key0 = (key0 + (((key0 >> 3) & 0xFFFFFFFF) - 0x11111111)
                            & 0xFFFFFFFF) & 0xFFFFFFFF
                    key1 = (key1 + (((key1 >> 5) & 0xFFFFFFFF) - 0x22222222)
                            & 0xFFFFFFFF) & 0xFFFFFFFF
                    key2 = (key2 + (0x44444444 - (
                        (key2 << 9) & 0xFFFFFFFF)) & 0xFFFFFFFF) & 0xFFFFFFFF
                    key3 = (key3 + (0x33333333 - (
                        (key3 << 7) & 0xFFFFFFFF)) & 0xFFFFFFFF) & 0xFFFFFFFF
                    new_key = (((key2 & 0xFF) + (key3 & 0xFF) + (key1 & 0xFF) +
                                (key0 & 0xFF)) & 0xFF)

                elif tcp.module_data['protocol'] == 1:
                    key0 = (key0 + ((key0 >> 3) + 3) & 0xFFFFFFFF) & 0xFFFFFFFF
                    key1 = (key1 + (((key1 >> 5) & 0xFFFFFFFF) + 5)
                            & 0xFFFFFFFF) & 0xFFFFFFFF
                    key2 = (0xFFFFFF81 * (key2 & 0xFFFFFFFF) - 7) & 0xFFFFFFFF
                    key3 = (0xFFFFFE01 * (key3 & 0xFFFFFFFF) - 9) & 0xFFFFFFFF
                    new_key = (((key2 & 0xFF) + (key3 & 0xFF) + (key1 & 0xFF) +
                                (key0 & 0xFF)) & 0xFF)

                else:
                    new_key = 0xFF

                if tcp.module_data['verbose']:
                    chop.tsprnt(hex(new_key), hex(key0), hex(key1), hex(key2),
                                hex(key3))

                res = unpack("<B", src[i:i + 1])[0] ^ new_key
                dst = dst + pack("<B", res)
                i = i + 1

        return dst

    data = ''

    # collect time and IP metadata
    ((src, sport), (dst, dport)) = tcp.addr
    # handle client system packets
    if tcp.server.count_new > 0:
        data = tcp.server.data[:tcp.server.count_new]
        if not data[:6] == 'POST /' and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted, flags, comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt(
                "c2_side - precrypt - key:%s flag:%s szComp:%s szDeComp:%s" %
                (repr(hex(unpack("<I", data[0:4])[0])),
                 repr(hex(unpack("<I", data[4:8])[0])),
                 repr(hex(unpack("H", data[8:10])[0])),
                 repr(hex(unpack("H", data[10:12])[0]))))
            chop.tsprnt(
                "c2_side - postcrypt - key:%s flag:%s szComp:%s szDeComp:%s" %
                (repr(hex(unpack("<I", decrypted[0:4])[0])),
                 repr(hex(unpack("<I", decrypted[4:8])[0])),
                 repr(hex(unpack("H", decrypted[8:10])[0])),
                 repr(hex(unpack("H", decrypted[10:12])[0]))))
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("c2 decrypted header: %s   flag: %s" %
                            (repr(decrypted), hex(flags)))
            if comp:
                chop.tsprnt("printable chars sent to c2",
                            repr(lznt1.dCompressBuf(comp).replace("\x00", "")),
                            module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to c2 %s" %
                                repr(lznt1.dCompressBuf(comp)))

        tcp.discard(tcp.server.count_new)
    # handle server system packets
    if tcp.client.count_new > 0:
        data = tcp.client.data[:tcp.client.count_new]
        if not data[:6] == 'POST /' and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted, flags, comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt("bot_side - precrypt: %s %s %s %s" %
                        (repr(hex(unpack("<I", data[0:4])[0])),
                         repr(hex(unpack("<I", data[4:8])[0])),
                         repr(hex(unpack("H", data[8:10])[0])),
                         repr(hex(unpack("H", data[10:12])[0]))))
            chop.tsprnt("bot_side - postcrypt: %s %s %s %s" %
                        (repr(hex(unpack("<I", decrypted[0:4])[0])),
                         repr(hex(unpack("<I", decrypted[4:8])[0])),
                         repr(hex(unpack("H", decrypted[8:10])[0])),
                         repr(hex(unpack("H", decrypted[10:12])[0]))))
            chop.tsprnt(comp)
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("bot decrypted header: %s   flag: %s" %
                            (repr(decrypted), hex(flags)))
            if comp:
                chop.tsprnt("printable chars sent to bot",
                            repr(lznt1.dCompressBuf(comp).replace("\x00", "")),
                            module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to bot message %s" %
                                repr(lznt1.dCompressBuf(comp)))
        tcp.discard(tcp.client.count_new)

    if tcp.stream_data['flag']:
        while data:
            #stuff!
            break

        #chop.tsprnt("Finding flag: %s:%i->%s:%i (%i)" % (src, sport, dst, dport, len(data)))
        # Sometimes our data isn't all in one packet? I'm not sure why I am fighting this bug
        #if not tcp.stream_data['flag']:
        #chop.tsprnt("No flag found, skipping stream.")
        #tcp.stop()
    return
Esempio n. 5
0
def handleStream(tcp):

    data = ''

    # collect time and IP metadata
    ((src, sport), (dst, dport)) = tcp.addr
    # handle client system packets
    if tcp.server.count_new > 0:
        data = tcp.server.data[:tcp.server.count_new]
        if not data[:6] == 'POST /' and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted, flags, comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt(
                "c2_side - precrypt - key:%s flag:%s szComp:%s szDeComp:%s" %
                (repr(hex(unpack("<I", data[0:4])[0])),
                 repr(hex(unpack("<I", data[4:8])[0])),
                 repr(hex(unpack("H", data[8:10])[0])),
                 repr(hex(unpack("H", data[10:12])[0]))))
            chop.tsprnt(
                "c2_side - postcrypt - key:%s flag:%s szComp:%s szDeComp:%s" %
                (repr(hex(unpack("<I", decrypted[0:4])[0])),
                 repr(hex(unpack("<I", decrypted[4:8])[0])),
                 repr(hex(unpack("H", decrypted[8:10])[0])),
                 repr(hex(unpack("H", decrypted[10:12])[0]))))
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("c2 decrypted header: %s   flag: %s" %
                            (repr(decrypted), hex(flags)))
            if comp:
                chop.tsprnt("printable chars sent to c2",
                            repr(lznt1.dCompressBuf(comp).replace("\x00", "")),
                            module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to c2 %s" %
                                repr(lznt1.dCompressBuf(comp)))

        tcp.discard(tcp.server.count_new)
    # handle server system packets
    if tcp.client.count_new > 0:
        data = tcp.client.data[:tcp.client.count_new]
        if not data[:6] == 'POST /' and not data[:6] == 'HTTP/1':
            if tcp.module_data['verbose']:
                chop.tsprnt(repr(data[:16]))
        if len(data) < 16:
            #wtf, but it happens
            tcp.stream_data['server_buf'] += data
            return

        (decrypted, flags, comp) = decrypt_packed_string(data)
        if tcp.module_data['verbose']:
            chop.tsprnt("bot_side - precrypt: %s %s %s %s" %
                        (repr(hex(unpack("<I", data[0:4])[0])),
                         repr(hex(unpack("<I", data[4:8])[0])),
                         repr(hex(unpack("H", data[8:10])[0])),
                         repr(hex(unpack("H", data[10:12])[0]))))
            chop.tsprnt("bot_side - postcrypt: %s %s %s %s" %
                        (repr(hex(unpack("<I", decrypted[0:4])[0])),
                         repr(hex(unpack("<I", decrypted[4:8])[0])),
                         repr(hex(unpack("H", decrypted[8:10])[0])),
                         repr(hex(unpack("H", decrypted[10:12])[0]))))
            chop.tsprnt(comp)
        if flags != 0xffff:
            if tcp.module_data['verbose']:
                chop.tsprnt("bot decrypted header: %s   flag: %s" %
                            (repr(decrypted), hex(flags)))
            if comp:
                chop.tsprnt("printable chars sent to bot",
                            repr(lznt1.dCompressBuf(comp).replace("\x00", "")),
                            module_data['flags'][flags])
                if tcp.module_data['verbose']:
                    chop.tsprnt("full dump of data sent to bot message %s" %
                                repr(lznt1.dCompressBuf(comp)))
        tcp.discard(tcp.client.count_new)

    if tcp.stream_data['flag']:
        while data:
            #stuff!
            break

        #chop.tsprnt("Finding flag: %s:%i->%s:%i (%i)" % (src, sport, dst, dport, len(data)))
        # Sometimes our data isn't all in one packet? I'm not sure why I am fighting this bug
        #if not tcp.stream_data['flag']:
        #chop.tsprnt("No flag found, skipping stream.")
        #tcp.stop()
    return
Esempio n. 6
0
def handleStream(tcp):
    sd = tcp.stream_data
    md = tcp.module_data

    if tcp.client.count_new > 0:
        sd['client_buffer'] += tcp.client.data[:tcp.client.count_new]
        if sd['client_state'] == "challenged":
            if len(sd['client_buffer']) >= 256:
                challenge_resp = sd['client_buffer'][:256]
                sd['client_buffer'] = sd['client_buffer'][256:]
                if md['pwlist']:
                    if TryKeyList(md['pwlist'], sd['challenge'], challenge_resp, md['camcrypt']):
                        if md['verbose'] or md['debug']:
                            chop.tsprnt("PI challenge response accepted..")
                        sd['client_state'] = "challenge_accepted"
                        tcp.discard(tcp.client.count_new)
                        return
                if challenge_resp == CamelliaEncrypt(sd['challenge'], md['camcrypt']):
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI challenge response accepted..")
                    sd['client_state'] = "challenge_accepted"
                    tcp.discard(tcp.client.count_new)
                    return
                else:
                    sd['client_state'] = "challenge_failed"
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI challenge response not valid for supplied passwords(s), skipping stream..")
                    #sd['challenge_accepted'] = True
                    tcp.stop()
                    return

        if sd['client_state'] == "double_challenged":
            if len(sd['client_buffer']) >= 260:
                challenge_resp = sd['client_buffer'][:256]
                sd['client_buffer'] = sd['client_buffer'][256:]
                (a, b) = struct.unpack('>HH', tcp.client.data[:4])
                a ^= 0xd015
                if a != b:
                    sd['client_state'] = "challenge_failed"
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI challenge not valid, skipping stream..")
                    tcp.stop()
                    return
                sd['xor'] = a & 0xFF
                chop.tsprnt("PI double nonce xor variant, xor key: %02X" % sd['xor'])
                if md['pwlist']:
                    if TryKeyList(md['pwlist'], sd['challenge'], challenge_resp, md['camcrypt'], sd['xor']):
                        if md['verbose'] or md['debug']:
                            chop.tsprnt("PI challenge response accepted..")
                        sd['client_state'] = "challenge_accepted"
                        tcp.discard(tcp.client.count_new)
                        return
                if challenge_resp == CamelliaEncrypt(one_byte_xor(sd['challenge'], sd['xor']), md['camcrypt'], sd['xor']):
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI challenge response accepted..")
                    sd['client_state'] = "challenge_accepted"
                    tcp.discard(tcp.client.count_new)
                    return
                else:
                    sd['client_state'] = "challenge_failed"
                    if md['verbose'] or md['debug']:
                        chop.tsprnt("PI double challenge response not valid for supplied passwords(s), skipping stream..")
                    #sd['challenge_accepted'] = True
                    tcp.stop()
                    return

        if sd['client_state'] == "challenge_accepted":
            if len(sd['client_buffer']) >= 4:
                if 'xor' in sd:
                    sd['init_size'] = unpack("<I", one_byte_xor(sd['client_buffer'][:4], sd['xor']))[0]
                else:
                    sd['init_size'] = unpack("<I", sd['client_buffer'][:4])[0]
                sd['client_state'] = "init_code_collection"
                sd['client_buffer'] = sd['client_buffer'][4:]


        if sd['client_state'] == "init_code_collection":
            if sd['init_size'] <= len(sd['client_buffer']):
                sd['client_state'] = "init_code_collected"
                #decrypted = CamelliaDecrypt(sd['client_buffer'][:sd['init_size']], md['camcrypt'])
                if md['debug']:
                    chop.tsprnt("init code size: %08X" % sd['init_size'])
                sd['client_buffer'] = sd['client_buffer'][sd['init_size']:]

        if sd['client_state'] == "init_code_collected":
            if len(sd['client_buffer']) >= 4:
                if 'xor' in sd:
                    sd['version'] = unpack("<I", one_byte_xor(sd['client_buffer'][:4], sd['xor']))[0]
                else:
                    sd['version'] = unpack("<I", sd['client_buffer'][:4])[0]
                sd['client_buffer'] = sd['client_buffer'][4:]
                sd['client_state'] = "version_collected"
                chop.tsprnt("Poison Ivy Version: %0.2f" % (sd['version'] / 100.00))

        if sd['client_state'] == "version_collected":
            if len(sd['client_buffer']) >= 4:
                if 'xor' in sd:
                    sd['init_size'] = unpack("<I", one_byte_xor(sd['client_buffer'][:4], sd['xor']))[0]
                else:
                    sd['init_size'] = unpack("<I", sd['client_buffer'][:4])[0]
                sd['client_buffer'] = sd['client_buffer'][4:]
                sd['client_state'] = "stub_code_collection"
                if md['debug']:
                    chop.tsprnt("stub code size: %08X" % sd['init_size'])

        if sd['client_state'] == "stub_code_collection":
            if sd['init_size'] <= len(sd['client_buffer']):
                sd['client_state'] = "stub_code_collected"
                if md['debug']:
                    chop.tsprnt("stub code collected..")
                sd['client_buffer'] = sd['client_buffer'][sd['init_size']:]

        if sd['client_state'] == "stub_code_collected":
            #initialization complete
            if md['debug']:
                chop.tsprnt("init complete..")
            sd['client_state'] = "read_header"
            sd['server_state'] = "read_header"
            sd['server_buffer'] = ""


        if sd['client_state'] == "read_header":
            listid = sd['client_cur_listid']
            if len(sd['client_buffer']) >= 32:
                (sd['client_cur_listid'], newstream) = getHeaders("in", sd['client_buffer'][:32], tcp)
                listid = sd['client_cur_listid']
                sd['client_state'] = "recv_chunk"
                sd['client_buffer'] = sd['client_buffer'][32:]
                if newstream:
                    if sd['inbound_type'].get(listid) == 6:
                        #handle file data
                        decrypted = CamelliaDecrypt(sd['client_buffer'][:sd['inbound_chunk_size'].get(listid)], md['camcrypt'], sd.get('xor', None))
                        sd['client_buffer'] = sd['client_buffer'][sd['inbound_chunk_size'].get(listid):]
                        if sd['inbound_unpadded_chunk_size'].get(listid) != sd['inbound_decompressed_chunk_size'].get(listid):
                            buf = lznt1.dCompressBuf(decrypted[:sd['inbound_unpadded_chunk_size'].get(listid)])
                            if buf == None:
                                chop.tsprnt("decompression error:\n%s" % hexdump(decrypted))
                                tcp.stop()
                        else:
                            buf = decrypted[:sd['inbound_unpadded_chunk_size'].get(listid)]
                        #decompressed = lznt1.dCompressBuf(decrypted[:sd['inbound_unpadded_chunk_size']])
                        filename = string.strip(buf, "\x00")
                        sd['inbound_filename'][listid] = "PI-extracted-inbound-file-%d-%s" % (md['filecount'], filename[string.rfind(filename, "\\")+1:])
                        md['filecount'] += 1
                        chop.tsprnt("inbound file %s " % filename)

                        sd['client_state'] = "read_header"

                    sd['inbound_size_left'][listid] = sd['inbound_total_size'].get(listid)

            if sd['inbound_size_left'].get(listid) == 0:
                    sd['inbound_size_left'][listid] = sd['inbound_total_size'].get(listid)


        if sd['client_state'] == "recv_chunk":
            listid = sd['client_cur_listid']
            if sd['inbound_chunk_size'].get(listid) <= len(sd['client_buffer']):
                if md['debug']:
                    chop.tsprnt("handling inbound chunk.. %d bytes to go" % sd['inbound_size_left'].get(listid))
                sd['client_state'] = "read_header"
                decrypted = CamelliaDecrypt(sd['client_buffer'][:sd['inbound_chunk_size'].get(listid)], md['camcrypt'], sd.get('xor', None))
                decrypted = decrypted[:sd['inbound_unpadded_chunk_size'].get(listid)]
                buf = decrypted
                if sd['inbound_unpadded_chunk_size'].get(listid) != sd['inbound_decompressed_chunk_size'].get(listid):
                    buf = lznt1.dCompressBuf(decrypted)
                    if buf == None:
                        chop.tsprnt("decompression error:\n%s" % hexdump(decrypted))
                        tcp.stop()
                sd['client_collect_buffer'][listid] += buf
                sd['client_buffer'] = sd['client_buffer'][sd['inbound_chunk_size'].get(listid):]
                sd['inbound_size_left'][listid] -= sd['inbound_decompressed_chunk_size'].get(listid)
                if sd['inbound_type'].get(listid) == 6 and md['savefiles']:
                        #inbound file
                        chop.savefile(sd['inbound_filename'].get(listid), buf, False)

                if sd['inbound_size_left'].get(listid) == 0:
                    if sd['inbound_type'].get(listid) == 6:
                        if md['savefiles']:
                            #inbound file
                            chop.finalizefile(sd['inbound_filename'].get(listid))
                            chop.tsprnt("saved %s.." % sd['inbound_filename'].get(listid))
                    else:
                        analyzeCode(sd['client_collect_buffer'].get(listid), sd['inbound_type'].get(listid), tcp)
                        if md['debug']:
                            chop.tsprnt("analyzing code..")

                    sd['client_collect_buffer'][listid] = ""


        #chop.tsprnt("to client:%d" % tcp.client.count_new)
        tcp.discard(tcp.client.count_new)
        return

    elif tcp.server.count_new > 0:
        sd['server_buffer'] += tcp.server.data[:tcp.server.count_new]
        if sd['client_state'] == "unauthenticated":
            if len(sd['server_buffer']) >= 256:
                sd['client_state'] = "challenged"
                #chop.tsprnt(hexdump(tcp.server.data[:tcp.server.count_new]))
                sd['challenge'] = sd['server_buffer'][:256]
                sd['server_buffer'] = sd['server_buffer'][256:]
                #chop.tsprnt(hexdump(sd['challenge']))
        elif sd['client_state'] == "challenged":
            if len(sd['server_buffer']) >= 256:
                sd['client_state'] = "double_challenged"
                sd['challenge'] = sd['server_buffer'][:256]
                sd['server_buffer'] = sd['server_buffer'][256:]
        elif sd['client_state'] == "double_challenged":
            if md['verbose'] or md['debug']:
                chop.tsprnt("PI challenge not found, skipping stream..")
            tcp.stop()

        if sd['server_state'] == "read_header":
            listid = sd['server_cur_listid']
            if len(sd['server_buffer']) >= 32:
                (sd['server_cur_listid'], newstream) = getHeaders("out", sd['server_buffer'][:32], tcp)
                listid = sd['server_cur_listid']
                sd['server_state'] = "recv_chunk"
                sd['server_buffer'] = sd['server_buffer'][32:]
                if newstream:
                    if sd['outbound_type'].get(listid) == 4:
                        #handle file data
                        decrypted = CamelliaDecrypt(sd['server_buffer'][:sd['outbound_chunk_size'].get(listid)], md['camcrypt'], sd.get('xor', None))
                        if sd['outbound_unpadded_chunk_size'].get(listid) != sd['outbound_decompressed_chunk_size'].get(listid):
                            buf = lznt1.dCompressBuf(decrypted[:sd['outbound_unpadded_chunk_size'].get(listid)])
                            if buf == None:
                                chop.tsprnt("decompression error:\n%s" % hexdump(decrypted))
                                tcp.stop()
                        else:
                            buf = decrypted[:sd['outbound_unpadded_chunk_size'].get(listid)]

                        sd['server_buffer'] = sd['server_buffer'][sd['outbound_chunk_size'].get(listid):]
                        filename = string.strip(buf, "\x00")
                        sd['outbound_filename'][listid] = "PI-extracted-outbound-file-%d-%s" % (md['filecount'], filename[string.rfind(filename, "\\")+1:])
                        md['filecount'] += 1
                        chop.tsprnt("outbound file %s " % filename)

                        sd['server_state'] = "read_header"

                    sd['outbound_size_left'][listid] = sd['outbound_total_size'].get(listid)


                if sd['outbound_size_left'].get(listid) == 0:
                    sd['outbound_size_left'][listid] = sd['outbound_total_size'].get(listid)

        if sd['server_state'] == "recv_chunk":
            listid = sd['server_cur_listid']
            if sd['outbound_chunk_size'].get(listid) <= len(sd['server_buffer']):
                if md['debug']:
                    chop.tsprnt("handling outbound chunk.. %d bytes to go" % sd['outbound_size_left'].get(listid))
                sd['server_state'] = "read_header"
                decrypted = CamelliaDecrypt(sd['server_buffer'][:sd['outbound_chunk_size'].get(listid)], md['camcrypt'], sd.get('xor', None))
                decrypted = decrypted[:sd['outbound_unpadded_chunk_size'].get(listid)]
                buf = decrypted
                if sd['outbound_unpadded_chunk_size'].get(listid) != sd['outbound_decompressed_chunk_size'].get(listid):
                    buf = lznt1.dCompressBuf(decrypted)
                    if buf == None:
                        chop.tsprnt("decompression error:\n%s" % hexdump(decrypted))
                        tcp.stop()
                sd['server_collect_buffer'][listid] += buf
                sd['server_buffer'] = sd['server_buffer'][sd['outbound_chunk_size'].get(listid):]
                sd['outbound_size_left'][listid] -= sd['outbound_decompressed_chunk_size'].get(listid)
                if sd['outbound_type'].get(listid) == 4 and md['savefiles']:
                        #outbound file
                        chop.savefile(sd['outbound_filename'].get(listid), buf, False)

                if sd['outbound_size_left'].get(listid) == 0:
                    if sd['outbound_type'].get(listid) == 4:
                        if md['savefiles']:
                            #outbound file
                            chop.finalizefile(sd['outbound_filename'].get(listid))
                            chop.tsprnt("saved %s.." % sd['outbound_filename'].get(listid))
                    else:
                        if md['debug']:
                            chop.tsprnt("outbound data:\n%s" % hexdump(sd['server_collect_buffer'].get(listid)))

                        try:
                            md['cmdhandler'][sd['outbound_type'].get(listid)](sd['server_collect_buffer'].get(listid), tcp)
                        except:
                            if md['verbose'] or md['debug']:
                                chop.tsprnt("unrecognized command..")

                    sd['server_collect_buffer'][listid] = ""

        tcp.discard(tcp.server.count_new)
        return

    tcp.discard(tcp.server.count_new)
    return