2016-07-24 4 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() 

EDIT

Я понимаю, что происходит до того, что функция validate_password создается используя CodeType и FunctionType объектов. Я также понимаю, что если 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

Спасибо, что помогли мне в этом. Не нужно извиняться, рад, что ценный инструмент все еще поддерживается, успешно обновляется через pip, поэтому все сделано, чтобы обновить пакет. @ @ Das-g предоставил богатый ответ с большим количеством доказательств, однако это метод в основном автоматизирует шаги, которые я прошел для их метода. – RandomHash

+0

Чтобы уточнить, описанный выше метод работал. Я не испорчу его для кого-либо еще, проходящего через этот CTF. Но более пристальный взгляд на документы PEP даст вам пароль также :) – RandomHash

3

Запустить интерактивную сессию Python 3. Если вы используете обычный интерпретатор Python, тип

import types 
help(types.CodeType) 

Если вы используете IPython, вы могли бы вместо того, чтобы написать

import types 
types.CodeType? 

Вы узнаете, что types.CodeType тут

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

У hu. Что такое объекты кода? Давайте посмотрим на 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   

См dis документацию для the meaning of the bytecode operations (LOAD_CONST, BUILD_LIST и т.д.).

Чтобы лучше понять, что делает функция, можно попытаться декомпилировать ее обратно в код Python. Однако мне этого не удалось. (Пробовал с uncompyle6.)

+0

Первая линия сборки эквивалентна: б = [1,2,3,4,5,6,5,7,8,9 , 8 (новая строка) 10, 1, ...]; c = [] и цикл for, который накапливается до c, а затем e = '' .join (c) и возвращает true или false, если a == e. (A передан или установлен ранее?) – rocky

+0

@rocky, как вы это узнали? Возможно, стоит ответить самостоятельно. –

+0

- быстрая проверка кода. Глядя больше на то, что происходит с помощью chr (ord (d)), где d's итератор цикла. Вы можете позволить uncompyle6 выполнить работу. Если вы укажете номер версии Python, например 3.5 или 2.7. См. Https://github.com/rocky/python-uncompyle6/blob/master/uncompyle6/main.py#L12 – rocky