【wp】2021强网杯-ExtremelySlow

继续填坑ing,是强网杯的一道Misc题ExtremelySlow,跟npy合力做的一道杂项题(双双转行Misc手就离谱x),当时捞了个七血,可惜这个题最后被打穿了(

赛中的大概思路就是把传的一个一个字节按顺序提取出来并复原出传输的文件,因为两个工具都不兼容python3.10所以直接手逆pyc+手抠隐写字节码,最后拿到flag。

这里还进行了一点赛后改进,包括魔改stegosaurus兼容到3.10。

【Misc】ExtremelySlow

赛中思路

流量包中提取复原出文件

查看流量包,注意到HTTP/1.1 206 Partial Content的包都是对get包的回答,并且都是/latest文件的一个字节。

(一字节一字节地传,难怪叫ExtremelySlow= =)

image-20210712160129393

双击HTTP/1.1 206 Partial Content包查看(以No.10这个包为例):

image-20210712160224633

image-20210712160239511

可以知道这个包返回的是文件的第0字节0x6f,其余包同理。

所以选中所有这样的回复包,然后导出为纯文本,保存在out.txt中。

image-20210712155918386

然后写脚本从txt里提取这些字节并按顺序还原出源文件(直接把npy脚本搬过来了):

import json
import re

with open('./out.txt', 'r') as f:
    data = f.read()

data = data.split('\n')
r1 = []
r2 = []
for d in data:
    if 'content-range:' in d:
        r1.append(d)
    if '0000  ' in d and not '0.290470000' in d:
        r2.append(d)

# print(len(r1))
# print(len(r2))

data = []
for i in range(len(r1)):
    data.append((re.findall(r"\d+\.?\d*",r1[i])[0], '0x'+r2[i][6:8]))

data = sorted(data, key=lambda t: int(t[0]))
# for d in data:
#     print(d)
result = [int(d[1],16) for d in data]

# print(len(result))
with open('./res', 'wb') as f:
    f.write(bytes(result))

pyc逆向

拿到这个文件,用010打开看到经典第二行E3000000..., 逆向手dna狂喜, 直接猜测是pyc文件,加上pyc后缀。

image-20210614152120204

用uncompyle6和pycdc反编译,但是都由于魔数不对报错,于是把第一个字节改成0x55,假装这是3.8的pyc,反编译依然失败,于是只能用pycdas(zrax/pycdc: C++ python bytecode disassembler and decompiler)反汇编出字节码。

res.pyc (Python 3.8)
[Code]
    File Name: main.py
    Object Name: <module>
    Arg Count: 0
    Pos Only Arg Count: 0
    KW Only Arg Count: 0
    Locals: 0
    Stack Size: 7
    Flags: 0x00000040 (CO_NOFREE)
    [Names]
        'sys'
        'hashlib'
        'sha256'
        'KSA'
        'PRGA'
        'RC4'
        'xor'
        '__name__'
        'w'
        'e'
        'b'
        's'
        't'
        'm'
        'n'
        'list'
        'map'
        'sorted'
        'items'
        'stream'
        'print'
        'decode'
        'stdin'
        'buffer'
        'read'
        'p'
        'c'
        'digest'
    [Var Names]
    [Free Vars]
    [Cell Vars]
    [Constants]
        0
        None
        (
            'sha256'
        )
        [Code]
            File Name: main.py
            Object Name: KSA
            Arg Count: 1
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 5
            Stack Size: 5
            Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
            [Names]
                'len'
                'list'
                'range'
            [Var Names]
                'key'
                'keylength'
                'S'
                'j'
                'i'
            [Free Vars]
            [Cell Vars]
            [Constants]
                None
                256
                0
            [Disassembly]
                0       LOAD_GLOBAL             0: len
                2       LOAD_FAST               0: key
                4       CALL_FUNCTION           1
                6       STORE_FAST              1: keylength
                8       LOAD_GLOBAL             1: list
                10      LOAD_GLOBAL             2: range
                12      LOAD_CONST              1: 256
                14      CALL_FUNCTION           1
                16      CALL_FUNCTION           1
                18      STORE_FAST              2: S
                20      LOAD_CONST              2: 0
                22      STORE_FAST              3: j
                24      LOAD_GLOBAL             2: range
                26      LOAD_CONST              1: 256
                28      CALL_FUNCTION           1
                30      GET_ITER                
                32      FOR_ITER                29 (to 63)
                34      STORE_FAST              4: i
                36      LOAD_FAST               3: j
                38      LOAD_FAST               2: S
                40      LOAD_FAST               4: i
                42      BINARY_SUBSCR           
                44      BINARY_ADD              
                46      LOAD_FAST               0: key
                48      LOAD_FAST               4: i
                50      LOAD_FAST               1: keylength
                52      BINARY_MODULO           
                54      BINARY_SUBSCR           
                56      BINARY_ADD              
                58      LOAD_CONST              1: 256
                60      BINARY_MODULO           
                62      STORE_FAST              3: j
                64      LOAD_FAST               2: S
                66      LOAD_FAST               3: j
                68      BINARY_SUBSCR           
                70      LOAD_FAST               2: S
                72      LOAD_FAST               4: i
                74      BINARY_SUBSCR           
                76      ROT_TWO                 
                78      LOAD_FAST               2: S
                80      LOAD_FAST               4: i
                82      STORE_SUBSCR            
                84      LOAD_FAST               2: S
                86      LOAD_FAST               3: j
                88      STORE_SUBSCR            
                90      JUMP_ABSOLUTE           16
                92      LOAD_FAST               2: S
                94      RETURN_VALUE            
        'KSA'
        [Code]
            File Name: main.py
            Object Name: PRGA
            Arg Count: 1
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 4
            Stack Size: 4
            Flags: 0x00000063 (CO_OPTIMIZED | CO_NEWLOCALS | CO_GENERATOR | CO_NOFREE)
            [Names]
            [Var Names]
                'S'
                'i'
                'j'
                'K'
            [Free Vars]
            [Cell Vars]
            [Constants]
                None
                0
                True
                1
                256
            [Disassembly]
                0       <INVALID>               
                2       LOAD_CONST              1: 0
                4       STORE_FAST              1: i
                6       LOAD_CONST              1: 0
                8       STORE_FAST              2: j
                10      NOP                     
                12      LOAD_FAST               1: i
                14      LOAD_CONST              3: 1
                16      BINARY_ADD              
                18      LOAD_CONST              4: 256
                20      BINARY_MODULO           
                22      STORE_FAST              1: i
                24      LOAD_FAST               2: j
                26      LOAD_FAST               0: S
                28      LOAD_FAST               1: i
                30      BINARY_SUBSCR           
                32      BINARY_ADD              
                34      LOAD_CONST              4: 256
                36      BINARY_MODULO           
                38      STORE_FAST              2: j
                40      LOAD_FAST               0: S
                42      LOAD_FAST               2: j
                44      BINARY_SUBSCR           
                46      LOAD_FAST               0: S
                48      LOAD_FAST               1: i
                50      BINARY_SUBSCR           
                52      ROT_TWO                 
                54      LOAD_FAST               0: S
                56      LOAD_FAST               1: i
                58      STORE_SUBSCR            
                60      LOAD_FAST               0: S
                62      LOAD_FAST               2: j
                64      STORE_SUBSCR            
                66      LOAD_FAST               0: S
                68      LOAD_FAST               0: S
                70      LOAD_FAST               1: i
                72      BINARY_SUBSCR           
                74      LOAD_FAST               0: S
                76      LOAD_FAST               2: j
                78      BINARY_SUBSCR           
                80      BINARY_ADD              
                82      LOAD_CONST              4: 256
                84      BINARY_MODULO           
                86      BINARY_SUBSCR           
                88      STORE_FAST              3: K
                90      LOAD_FAST               3: K
                92      YIELD_VALUE             
                94      POP_TOP                 
                96      JUMP_ABSOLUTE           6
        'PRGA'
        [Code]
            File Name: main.py
            Object Name: RC4
            Arg Count: 1
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 2
            Stack Size: 2
            Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
            [Names]
                'KSA'
                'PRGA'
            [Var Names]
                'key'
                'S'
            [Free Vars]
            [Cell Vars]
            [Constants]
                None
            [Disassembly]
                0       LOAD_GLOBAL             0: KSA
                2       LOAD_FAST               0: key
                4       CALL_FUNCTION           1
                6       STORE_FAST              1: S
                8       LOAD_GLOBAL             1: PRGA
                10      LOAD_FAST               1: S
                12      CALL_FUNCTION           1
                14      RETURN_VALUE            
        'RC4'
        [Code]
            File Name: main.py
            Object Name: xor
            Arg Count: 2
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 2
            Stack Size: 5
            Flags: 0x00000003 (CO_OPTIMIZED | CO_NEWLOCALS)
            [Names]
                'bytes'
                'map'
            [Var Names]
                'p'
                'stream'
            [Free Vars]
            [Cell Vars]
                'stream'
            [Constants]
                None
                [Code]
                    File Name: main.py
                    Object Name: <lambda>
                    Arg Count: 1
                    Pos Only Arg Count: 0
                    KW Only Arg Count: 0
                    Locals: 1
                    Stack Size: 3
                    Flags: 0x00000013 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NESTED)
                    [Names]
                        '__next__'
                    [Var Names]
                        'x'
                    [Free Vars]
                        'stream'
                    [Cell Vars]
                    [Constants]
                        None
                    [Disassembly]
                        0       LOAD_FAST               0: x
                        2       LOAD_DEREF              0: stream
                        4       LOAD_METHOD             0: __next__
                        6       CALL_METHOD             0
                        8       BINARY_XOR              
                        10      RETURN_VALUE            
                'xor.<locals>.<lambda>'
            [Disassembly]
                0       LOAD_GLOBAL             0: bytes
                2       LOAD_GLOBAL             1: map
                4       LOAD_CLOSURE            0: stream
                6       BUILD_TUPLE             1
                8       LOAD_CONST              1: <CODE> <lambda>
                10      LOAD_CONST              2: 'xor.<locals>.<lambda>'
                12      MAKE_FUNCTION           8
                14      LOAD_FAST               0: p
                16      CALL_FUNCTION           2
                18      CALL_FUNCTION           1
                20      RETURN_VALUE            
        'xor'
        '__main__'
        b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
        b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
        b'geo'
        b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
        b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
        115
        97
        117
        114
        (
            2
            8
            11
            10
        )
        119
        116
        124
        127
        (
            3
            7
            9
            12
        )
        [Code]
            File Name: main.py
            Object Name: <dictcomp>
            Arg Count: 1
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 2
            Stack Size: 6
            Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
            [Names]
                'n'
            [Var Names]
                '.0'
                'x'
            [Free Vars]
            [Cell Vars]
            [Constants]
            [Disassembly]
                0       BUILD_MAP               0
                2       LOAD_FAST               0: .0
                4       FOR_ITER                9 (to 15)
                6       STORE_FAST              1: x
                8       LOAD_FAST               1: x
                10      LOAD_FAST               1: x
                12      LOAD_GLOBAL             0: n
                14      LOAD_FAST               1: x
                16      BINARY_SUBSCR           
                18      BINARY_XOR              
                20      MAP_ADD                 2
                22      JUMP_ABSOLUTE           2
                24      RETURN_VALUE            
        '<dictcomp>'
        [Code]
            File Name: main.py
            Object Name: <genexpr>
            Arg Count: 1
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 2
            Stack Size: 3
            Flags: 0x00000063 (CO_OPTIMIZED | CO_NEWLOCALS | CO_GENERATOR | CO_NOFREE)
            [Names]
                'bit_count'
            [Var Names]
                '.0'
                'i'
            [Free Vars]
            [Cell Vars]
            [Constants]
                None
            [Disassembly]
                0       <INVALID>               
                2       LOAD_FAST               0: .0
                4       FOR_ITER                9 (to 15)
                6       STORE_FAST              1: i
                8       LOAD_FAST               1: i
                10      LOAD_METHOD             0: bit_count
                12      CALL_METHOD             0
                14      LOAD_FAST               1: i
                16      BUILD_TUPLE             2
                18      YIELD_VALUE             
                20      POP_TOP                 
                22      JUMP_ABSOLUTE           2
                24      LOAD_CONST              0: None
                26      RETURN_VALUE            
        '<genexpr>'
        [Code]
            File Name: main.py
            Object Name: <lambda>
            Arg Count: 1
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Locals: 1
            Stack Size: 2
            Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
            [Names]
            [Var Names]
                'x'
            [Free Vars]
            [Cell Vars]
            [Constants]
                None
                1
            [Disassembly]
                0       LOAD_FAST               0: x
                2       LOAD_CONST              1: 1
                4       BINARY_SUBSCR           
                6       RETURN_VALUE            
        '<lambda>'
    [Disassembly]
        0       LOAD_CONST              0: 0
        2       LOAD_CONST              1: None
        4       IMPORT_NAME             0: sys
        6       STORE_NAME              0: sys
        8       LOAD_CONST              0: 0
        10      LOAD_CONST              2: ('sha256',)
        12      IMPORT_NAME             1: hashlib
        14      IMPORT_FROM             2: sha256
        16      STORE_NAME              2: sha256
        18      POP_TOP                 
        20      LOAD_CONST              3: <CODE> KSA
        22      LOAD_CONST              4: 'KSA'
        24      MAKE_FUNCTION           0
        26      STORE_NAME              3: KSA
        28      LOAD_CONST              5: <CODE> PRGA
        30      LOAD_CONST              6: 'PRGA'
        32      MAKE_FUNCTION           0
        34      STORE_NAME              4: PRGA
        36      LOAD_CONST              7: <CODE> RC4
        38      LOAD_CONST              8: 'RC4'
        40      MAKE_FUNCTION           0
        42      STORE_NAME              5: RC4
        44      LOAD_CONST              9: <CODE> xor
        46      LOAD_CONST              10: 'xor'
        48      MAKE_FUNCTION           0
        50      STORE_NAME              6: xor
        52      LOAD_NAME               7: __name__
        54      LOAD_CONST              11: '__main__'
        56      COMPARE_OP              2 (==)
        58      POP_JUMP_IF_FALSE       139
        60      LOAD_CONST              12: b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
        62      STORE_NAME              8: w
        64      LOAD_CONST              13: b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
        66      STORE_NAME              9: e
        68      LOAD_CONST              14: b'geo'
        70      STORE_NAME              10: b
        72      LOAD_CONST              15: b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
        74      STORE_NAME              11: s
        76      LOAD_CONST              16: b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
        78      STORE_NAME              12: t
        80      LOAD_CONST              17: 115
        82      LOAD_CONST              18: 97
        84      LOAD_CONST              19: 117
        86      LOAD_CONST              20: 114
        88      LOAD_CONST              21: (2, 8, 11, 10)
        90      BUILD_CONST_KEY_MAP     4
        92      STORE_NAME              13: m
        94      LOAD_CONST              22: 119
        96      LOAD_CONST              23: 116
        98      LOAD_CONST              24: 124
        100     LOAD_CONST              25: 127
        102     LOAD_CONST              26: (3, 7, 9, 12)
        104     BUILD_CONST_KEY_MAP     4
        106     STORE_NAME              14: n
        108     LOAD_NAME               13: m
        110     LOAD_CONST              27: <CODE> <dictcomp>
        112     LOAD_CONST              28: '<dictcomp>'
        114     MAKE_FUNCTION           0
        116     LOAD_NAME               14: n
        118     GET_ITER                
        120     CALL_FUNCTION           1
        122     INPLACE_OR              
        124     STORE_NAME              13: m
        126     LOAD_NAME               13: m
        128     LOAD_CONST              29: <CODE> <genexpr>
        130     LOAD_CONST              30: '<genexpr>'
        132     MAKE_FUNCTION           0
        134     LOAD_NAME               10: b
        136     GET_ITER                
        138     CALL_FUNCTION           1
        140     INPLACE_OR              
        142     STORE_NAME              13: m
        144     LOAD_NAME               5: RC4
        146     LOAD_NAME               15: list
        148     LOAD_NAME               16: map
        150     LOAD_CONST              31: <CODE> <lambda>
        152     LOAD_CONST              32: '<lambda>'
        154     MAKE_FUNCTION           0
        156     LOAD_NAME               17: sorted
        158     LOAD_NAME               13: m
        160     LOAD_METHOD             18: items
        162     CALL_METHOD             0
        164     CALL_FUNCTION           1
        166     CALL_FUNCTION           2
        168     CALL_FUNCTION           1
        170     CALL_FUNCTION           1
        172     STORE_NAME              19: stream
        174     LOAD_NAME               20: print
        176     LOAD_NAME               6: xor
        178     LOAD_NAME               8: w
        180     LOAD_NAME               19: stream
        182     CALL_FUNCTION           2
        184     LOAD_METHOD             21: decode
        186     CALL_METHOD             0
        188     CALL_FUNCTION           1
        190     POP_TOP                 
        192     LOAD_NAME               0: sys
        194     LOAD_ATTR               22: stdin
        196     LOAD_ATTR               23: buffer
        198     LOAD_METHOD             24: read
        200     CALL_METHOD             0
        202     STORE_NAME              25: p
        204     LOAD_NAME               6: xor
        206     LOAD_NAME               9: e
        208     LOAD_NAME               19: stream
        210     CALL_FUNCTION           2
        212     STORE_NAME              9: e
        214     LOAD_NAME               6: xor
        216     LOAD_NAME               25: p
        218     LOAD_NAME               19: stream
        220     CALL_FUNCTION           2
        222     STORE_NAME              26: c
        224     LOAD_NAME               2: sha256
        226     LOAD_NAME               26: c
        228     CALL_FUNCTION           1
        230     LOAD_METHOD             27: digest
        232     CALL_METHOD             0
        234     LOAD_NAME               11: s
        236     COMPARE_OP              2 (==)
        238     POP_JUMP_IF_FALSE       131
        240     LOAD_NAME               20: print
        242     LOAD_NAME               6: xor
        244     LOAD_NAME               12: t
        246     LOAD_NAME               19: stream
        248     CALL_FUNCTION           2
        250     LOAD_METHOD             21: decode
        252     CALL_METHOD             0
        254     CALL_FUNCTION           1
        256     POP_TOP                 
        258     LOAD_CONST              1: None
        260     RETURN_VALUE            
        262     LOAD_NAME               20: print
        264     LOAD_NAME               9: e
        266     LOAD_METHOD             21: decode
        268     CALL_METHOD             0
        270     CALL_FUNCTION           1
        272     POP_TOP                 
        274     LOAD_CONST              1: None
        276     RETURN_VALUE            
        278     LOAD_CONST              1: None
        280     RETURN_VALUE            

看到行数不算太多,而且有很多都是赋值操作,比较容易逆,干脆直接手逆出源码

逆出来的main.py

import sys
from hashlib import sha256

def KSA(key):
    keylength=len(key)
    S=list(range(256))
    j=0
    for i in range(256):
        j=(S[i]+j+key[i%keylength])%256
        S[i],S[j]=S[j],S[i]
    return S

def PRGA(S):
    i=0
    j=0
    while True:
        i=(i+1)%256
        j=(j+S[i])%256
        S[j],S[i]=S[i],S[j]
        K=S[(S[i]+S[j])%256]
        yield K

def RC4(key):
    S=KSA(key)
    return PRGA(S)

def xor(p,stream):
    return bytes(map(lambda x:x^stream.__next__(),p))

if __name__=='__main__':
    w=b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
    e=b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
    b=b'geo'
    s=b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
    t=b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
    m={2:115,8:97,11:117,10:114}
    n={3:119,7:116,9:124,12:127}
    m|={x:x^n[x] for x in n}
    m|=((i.bit_count(),i) for i in b)
    stream=RC4(list(map(lambda x:x[1],sorted(m.items()))))
    print(xor(w,stream).decode())
    p=sys.stdin.buffer.read()
    e=xor(e,stream)
    c=xor(p,stream)
    if sha256(c).digest()==s:
        print(xor(t,stream).decode())
    else:
        print(e.decode())

逆的过程中发现bit_count()是python 3.10的新方法,一查才发现6f 0d 0d 0a是3.10版本的魔数(还以为第一字节被魔改了x

这里python文件的逻辑是用m、n、b生成了一个key,给rc4初始化密钥流,然后xor加密数据(其实就是把rc4加密拆开了),最后验证密文的sha256值是否等于所给的值即可。

由于yield的特性,我们可以爆破出p是26位(其他长度的输入都不能正常输出xor(t,stream).decode()

pyc隐写

爆破sha256显然是不可行的,于是猜测到有pyc隐写,把key打印出来也能看到有提示:

image-20210712161834340

stegosaurus是一个pyc隐写工具(AngelKitty/stegosaurus: A steganography tool for embedding payloads within Python bytecode.),拿工具来用发现又报错,查了一下发现是工具不兼容高版本的问题。

研究了一下这个工具的隐写原理,然后直接手抠隐写payload(

用自己逆出来的main.py生成pyc文件,来跟题目提出来的pyc文件在010里做对比,题目中有值且自己的pyc文件中为00的部分很大可能是隐写的字节,比如这种:(其他以此类推)

image-20210614153719020

拿到一串乱序的payload:b'\xf0\xb4\x55\x16\x36\xc5\x6f\xdb\xc9\xea\x64\x04\x15\x62\x11\xa2\xb0\xcd\xf0\x7d\x49\x32\xd6\x22\xe5\x0a'

因为顺序问题无从下手,只好用stegosaurus工具自己生成了一个隐写版本的两个pyc做对比,为了方便看顺序,payload设置成”ABCDEFGHIJKLMNOPQRSTUVWXYZ“

image-20210614154407137

拿到两个pyc文件,很容易就对比出这26个字母的顺序,比如:

image-20210614154535502

最后拿到顺序

img

按顺序排列payload填入p中,由rc4的特性加密和解密流程相同,所以可以直接拿源码改出exp:

import sys
from hashlib import sha256
def KSA(key):
    keylength=len(key)
    S=list(range(256))
    j=0
    for i in range(256):
        j=(S[i]+j+key[i%keylength])%256
        S[i],S[j]=S[j],S[i]
    return S
def PRGA(S):
    i=0
    j=0
    while True:
        i=(i+1)%256
        j=(j+S[i])%256
        S[j],S[i]=S[i],S[j]
        K=S[(S[i]+S[j])%256]
        yield K
def RC4(key):
    S=KSA(key)
    return PRGA(S)
def xor(p,stream):
    return bytes(map(lambda x:x^stream.__next__(),p))
if __name__=='__main__':
    w=b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
    e=b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
    b=b'geo'
    s=b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
    t=b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
    m={2:115,8:97,11:117,10:114}
    n={3:119,7:116,9:124,12:127}
    m|={x:x^n[x] for x in n}
    m|=((i.bit_count(),i) for i in b)
    stream=RC4(list(map(lambda x:x[1],sorted(m.items()))))
    print(xor(w,stream).decode())
    # p=sys.stdin.buffer.read()
    p=b'\xe5\x0a\x32\xd6\x22\xf0\x7d\x49\xb0\xcd\xa2\x11\xf0\xb4\x55\x16\x36\xc5\x6f\xdb\xc9\xea\x64\x04\x15\x62'
    e=xor(e,stream)
    c=xor(p,stream)
    print(c)
    if sha256(c).digest()==s:
        print(xor(t,stream).decode())
    else:
        print(e.decode())

image-20210614154912394

拿到flag:flag{P0w5rFu1_0pEn_50urcE}

赛后改进

用python提取pcapng

比赛的时候是直接硬提取的流量包里的纯文本的,写脚本比较麻烦XD

后来看到Nu1l的wp调用了一个库python-pcapng,感觉可行,来学着写一下脚本试试。

再后来报错搞不定,找了另一个包pyshark写脚本有:

import pyshark
import re

cap=pyshark.FileCapture('./ExtremelySlow.pcapng',display_filter="data")
data=[]
for packet in cap:
    content=packet['HTTP'].get_field_by_showname('content-range').showname_value
    key=int(re.findall(r"\d+",content)[0])
    try:
        val=packet['DATA'].data.binary_value
    except AttributeError:
        val=bytes(chr(packet['DATA'].tcp_reassembled_data.binary_value[-1]),encoding='utf-8')
    finally:
        data.append((key,val))

data=sorted(data,key=lambda t:t[0])
with open('./res','wb') as f:
    for t in data:
        f.write(t[1])

反汇编pyc文件

反汇编pyc还可以用以下的小脚本(来自python - How can I understand a .pyc file content - Stack Overflow):

import dis, marshal, sys

header_sizes = [
    # (size, first version this applies to)
    # pyc files were introduced in 0.9.2 way, way back in June 1991.
    (8,  (0, 9, 2)),  # 2 bytes magic number, \r\n, 4 bytes UNIX timestamp
    (12, (3, 6)),     # added 4 bytes file size
    # bytes 4-8 are flags, meaning of 9-16 depends on what flags are set
    # bit 0 not set: 9-12 timestamp, 13-16 file size
    # bit 0 set: 9-16 file hash (SipHash-2-4, k0 = 4 bytes of the file, k1 = 0)
    (16, (3, 7)),     # inserted 4 bytes bit flag field at 4-8 
    # future version may add more bytes still, at which point we can extend
    # this table. It is correct for Python versions up to 3.9
]
header_size = next(s for s, v in reversed(header_sizes) if sys.version_info >= v)

with open(pycfile, "rb") as f:
    metadata = f.read(header_size)  # first header_size bytes are metadata
    code = marshal.load(f)          # rest is a marshalled code object

dis.dis(code)

魔改stegosaurus

反编译器魔改估计得写很长,有空专门开一篇文章(咕咕咕)。

这里魔改一下stegosaurus,让它支持3.10版本。

(仓库指路:c10udlnk/stegosaurus: 添加python3.10支持。A steganography tool for embedding payloads within Python bytecode.

首先执行python3.10 stegosaurus.py res.pyc -x,报错:

image-20210714110022076

stegosaurus.py定位到出错代码:

image-20210714110050500

从这里(Python代码保护 | pyc 混淆从入门到工具实现 - 知乎)可以知道,3.5和3.6的header有12字节,而3.7开始支持校验hash值,又多了4字节出来,所以header这里要加一行版本的判断。

image-20210714111942133

然后继续报错:

image-20210714112041335

这里可以知道是编码的问题

image-20210714112123741

而payload里有不可见字符,所以干脆就直接把转码去掉就好。

image-20210714112401389

魔改get √

posted @ 2021-07-14 16:49  c10udlnk  阅读(322)  评论(0编辑  收藏  举报