2016-07-24 81 views
2

目前我正在試圖通過一個老蟒蛇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() 

編輯

我明白了,是怎麼回事到如此地步,一個validate_password功能通過使用CODETYPE和函數類型對象創建。我也明白,如果validate_password(user_input)評估爲True,該標誌將被髮送。這意味着返回類型必須是布爾值。 CodeType的文檔以及服務器腳本也顯示validate_password只有一個參數。

我的實際問題

源包含編譯蟒蛇字節碼。例如,b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'。我嘗試了許多方法來解碼/編碼這些字符串以獲取一些有意義的數據,我設法提取的唯一數據是十六進制數據。

如何將此數據轉換爲實際代碼,因此能夠重建validate_password函數。

我曾嘗試

- 我試圖基本上做這樣的回答表明,但在倒車時,我要麼不理解正確的話,還是這不起作用

binascii。 b2a_hex() - 這是我如何設法將字符串轉換爲十六進制,就像我之前說過的那樣,我不能從這個十六進制產生utf-8數據。

struct.unpack() - 這個方法已經取得了一些成功,但是在validate_password函數的上下文中數據意味着什麼,我只能用這個方法獲得整數。 (除非我誤解)

回答

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.
+0

謝謝你幫助我解決這個問題。沒有必要道歉,很高興有一個有價值的工具仍然保持,通過點成功更新,所以一切都已完成,以保持包最新:) @ das-g提供了豐富的答案,有大量的證據等,但是,這方法基本上自動化了我爲其方法執行的步驟。 – RandomHash

+0

爲了澄清,上述方法奏效。我不會破壞它爲通過這個CTF的其他人。但仔細看看PEP文檔也會給你密碼:) – RandomHash

3

開始交互式Python 3會話。如果您如果您使用IPython的使用普通的Python解釋器,鍵入

import types 
help(types.CodeType) 

,你可以寫

import types 
types.CodeType? 

你會了解到types.CodeType是那裏

Create a code object. Not for the faint of heart.

呃胡。什麼是代碼對象?我們來看看Python documentation

The type for code objects such as returned by compile() .

所以字節字符串參數可能,至少部分是二進制數據(或二進制指令),而不是(文字)串莫名其妙編碼。

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。)

+0

組件的第一行是等效爲:b = [1,2,3,4,5,6,5,7,8,9 ,8(換行)10,1,...]; c = []和for循環累積到c然後e =''.join(c),並且如果a == e則返回true或false。 (A先前被傳入或設置?) – rocky

+0

@rocky你是怎麼找到這個的?可能值得自己回答。 –

+0

快速檢查代碼。看更多的c是通過chr(ord(d))構建的,它是循環迭代器的地方。您可以讓uncompyle6完成這項工作如果您提供了一個Python版本號,例如3.5或2.7。請參閱https://github.com/rocky/python-uncompyle6/blob/master/uncompyle6/main.py#L12 – rocky