我应该如何解码这些数据/这些字符串

时间:2016-07-24 15:13:55

标签: python string decompiling

我目前正在尝试通过OLD python CTF挑战,提供服务器的脚本,并且想法是将正确的数据发送到此服务器,

#!/usr/bin/env python3
# from dis import dis
import socketserver
import types


class RequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        self.request.sendall(b'PyDRM Proof of Concept version 0.7\n')
        self.request.sendall(
            b'Submit the secret password to retrieve the flag:\n')
        user_input_bytes = self.request.recv(4096).strip()
        user_input = user_input_bytes.decode('utf-8', 'ignore')
        if validate_password(user_input):
            self.request.sendall(read_flag())
        else:
            self.request.sendall(b'Invalid password\n')


class RequestServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass


def read_flag():
    with open('flag.txt', 'rb') as fh:
        return fh.read()


def generate_validation_function():
    code_obj = types.CodeType(
        1,
        0,
        5,
        32,
        67,
        b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        ('append', 'chr', 'ord', 'join'),
        ('a', 'b', 'c', 'd', 'e'),
        'drm.py',
        'validate_password',
        5,
        b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        (),
        ()
    )
    func_obj = types.FunctionType(code_obj, globals())
    return func_obj


def main():
    setattr(__import__(__name__), 'validate_password',
            generate_validation_function())
    server = RequestServer(('0.0.0.0', 8765), RequestHandler)
    try:
        server.serve_forever()
    except (SystemExit, KeyboardInterrupt):
        server.shutdown()
        server.server_close()

if __name__ == '__main__':
    main()

修改

我理解,通过使用CodeType和FunctionType对象创建validate_password函数的原因是什么。我也明白,如果validate_password(user_input)的计算结果为True,则会发送该标志。意味着返回类型必须是布尔值。 CodeType的文档以及服务器脚本还显示validate_password只有一个参数。

我的实际问题

源包含已编译的python字节码。例如b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'。我已经尝试了很多方法来解码/编码这些字符串以获得一些有意义的数据,我设法提取的唯一数据是十六进制。

如何将此数据转换为实际代码,从而能够重建validate_password函数。

我尝试过什么

SO - Python: convert string to packed hex ( '01020304' -> '\x01\x02\x03\x04' ) - 我试图基本上做这个答案所暗示的内容,但相反,我要么没有正确理解它,要么这不起作用

binascii.b2a_hex() - 这就是我设法将字符串转换为十六进制的方式,就像我之前所说的那样,但我不能从这个十六进制中产生utf-8数据。

struct.unpack() - 使用这个方法取得了一些成功,但是在validate_password函数的上下文中我不知道数据意味着什么,我只能用这个方法得到整数。 (除非我误解了)

2 个答案:

答案 0 :(得分:3)

启动交互式Python 3会话。如果使用普通的python解释器,请键入

import types
help(types.CodeType)

如果您正在使用IPython,则可以改为编写

import types
types.CodeType?

您将了解types.CodeType是否适合

  

创建代码对象。不适合胆小的人。

你好。什么是代码对象?我们来看看Python documentation

  

compile()返回的代码对象的类型。

所以bytestring参数可能至少部分是二进制数据(或二进制指令),而不是以某种方式编码的(文本)字符串。

help?调用也告诉我们此类初始化程序的签名:

code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,
      constants, names, varnames, filename, name, firstlineno,
      lnotab[, freevars[, cellvars]])

有了这个,我们可以更自我描述地编写构造:

    code_obj = types.CodeType(
        argcount=1,
        kwonlyargcount=0,
        nlocals=5,
        stacksize=32,
        flags=67,
        codestring=b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        constants=(None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        names=('append', 'chr', 'ord', 'join'),
        varnames=('a', 'b', 'c', 'd', 'e'),
        filename='drm.py',
        name='validate_password',
        firstlineno=5,
        lnotab=b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        freevars=(),
        cellvars=()
    )

(这只是为了说明。它实际上不是这样执行的,因为types.CodeType()期望所有参数都是位置传递而不是关键字参数。)

现在这意味着什么?

您可以反汇编代码对象以更接近该问题:

import dis
dis.dis(code_obj)

(输出:)

  6           0 LOAD_CONST               1 ('\x87') 
              3 LOAD_CONST               2 ('\x9a') 
              6 LOAD_CONST               3 ('\x92') 
              9 LOAD_CONST               4 ('\x8e') 
             12 LOAD_CONST               5 ('\x8b') 
             15 LOAD_CONST               6 ('\x85') 
             18 LOAD_CONST               5 ('\x8b') 
             21 LOAD_CONST               7 ('\x96') 
             24 LOAD_CONST               8 ('\x81') 
             27 LOAD_CONST               5 ('\x8b') 
             30 LOAD_CONST               9 ('\x95') 
             33 LOAD_CONST               8 ('\x81') 

  7          36 LOAD_CONST              10 ('\x84') 
             39 LOAD_CONST               1 ('\x87') 
             42 LOAD_CONST               7 ('\x96') 
             45 LOAD_CONST               7 ('\x96') 
             48 LOAD_CONST               1 ('\x87') 
             51 LOAD_CONST              11 ('\x94') 
             54 LOAD_CONST               8 ('\x81') 
             57 LOAD_CONST               7 ('\x96') 
             60 LOAD_CONST              12 ('\x8a') 
             63 LOAD_CONST              13 ('\x83') 
             66 LOAD_CONST              14 ('\x90') 
             69 LOAD_CONST               8 ('\x81') 

  8          72 LOAD_CONST               5 ('\x8b') 
             75 LOAD_CONST              15 ('\x8f') 
             78 LOAD_CONST               3 ('\x92') 
             81 LOAD_CONST               4 ('\x8e') 
             84 LOAD_CONST               5 ('\x8b') 
             87 LOAD_CONST               6 ('\x85') 
             90 LOAD_CONST               5 ('\x8b') 
             93 LOAD_CONST               7 ('\x96') 
             96 BUILD_LIST              32 
             99 STORE_FAST               1 (b) 

  9         102 BUILD_LIST               0 
            105 STORE_FAST               2 (c) 

 10         108 SETUP_LOOP              43 (to 154) 
            111 LOAD_FAST                1 (b) 
            114 GET_ITER             
        >>  115 FOR_ITER                35 (to 153) 
            118 STORE_FAST               3 (d) 

 11         121 LOAD_FAST                2 (c) 
            124 LOAD_ATTR                0 (append) 
            127 LOAD_GLOBAL              1 (chr) 
            130 LOAD_GLOBAL              2 (ord) 
            133 LOAD_FAST                3 (d) 
            136 CALL_FUNCTION            1 
            139 LOAD_CONST              16 (34) 
            142 BINARY_SUBTRACT      
            143 CALL_FUNCTION            1 
            146 CALL_FUNCTION            1 
            149 POP_TOP              
            150 JUMP_ABSOLUTE          115 
        >>  153 POP_BLOCK            

 12     >>  154 LOAD_CONST              17 ('') 
            157 LOAD_ATTR                3 (join) 
            160 LOAD_FAST                2 (c) 
            163 CALL_FUNCTION            1 
            166 STORE_FAST               4 (e) 

 13         169 LOAD_FAST                0 (a) 
            172 LOAD_FAST                4 (e) 
            175 COMPARE_OP               2 (==) 
            178 POP_JUMP_IF_FALSE      185 

 14         181 LOAD_CONST              18 (True) 
            184 RETURN_VALUE         

 15     >>  185 LOAD_CONST              19 (False) 
            188 RETURN_VALUE         

请参阅the meaning of the bytecode operationsdis文档(LOAD_CONSTBUILD_LIST等。)

为了更好地掌握函数的功能,我们会尝试将其反编译回Python代码。不过,我无法做到这一点。 (试过uncompyle6。)

答案 1 :(得分:1)

对于das-g的回答,这段代码很有效。八九不离十。

import uncompyle6
import types
code_obj = types.CodeType(
        1, 0, 5, 32, 67, b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        ('append', 'chr', 'ord', 'join'),
        ('a', 'b', 'c', 'd', 'e'),
        'drm.py',
        'validate_password',
        5,
        b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        freevars=(),
        cellvars=()
    )

import sys
uncompyle6.main.uncompyle(3.5, code_obj, sys.stdout)

这里缺少的是这段代码真的包含在一个带有" a"参数。

我不会破坏给出答案的乐趣。代替:

  1. 运行上述程序。
  2. 将输出换行为:
    def drm(a): # Output from run above.