Skip to content

Instantly share code, notes, and snippets.

@Redict
Created October 13, 2019 13:24
Show Gist options
  • Save Redict/a0d58c9e98117095540ab7cd2141a8f0 to your computer and use it in GitHub Desktop.
Save Redict/a0d58c9e98117095540ab7cd2141a8f0 to your computer and use it in GitHub Desktop.
Messaging Tool Writeup

Messaging Tool


  • Открываем msg.py и видим что-то наподобии меча, а так же импорт serpent модуля.
  • Гуглим serpent python github: link
  • Открываем код проекта и смотрим, как создаётся меч и что он значит.
  • Копируем часть кода:
alphabet = [
    "PY", "PT", "PH", "PO", "PN", "YP", "YT", "YH", "YO", "YN", "TP", "TY", "TH", "TO", "TN",
    "HP", "HY", "HT", "HO", "HN", "OP", "OY", "OT", "OH", "ON", "NP", "NY", "NT", "NH", 	"NO", "PP", "YY"
]


def _serpent_sword_alphabet_to_hex(sentence):
    "Convert the serpent alphabet string back to python bytecode"
    return [alphabet.index(symbol[0:-1]) + int(symbol[-1]) * 32 for symbol in sentence]


def _lex_hex(infile):
    "Extract the serpent string from the ss file"
    with open(infile, 'r') as source:
        regex = re.compile(r'[PYTHON][PYTHON][0-9]')
        tokens = []
        for line in source:
            pos = 0
            while(pos < len(line)):
                match = regex.match(line, pos)
                if match:
                    tokens.append(match.group(0))
                pos += 1
        return tokens


def convert_to_pyc(fname):
    pyc = _serpent_sword_alphabet_to_hex(_lex_hex(fname))
    pycout = ".".join(fname.split(".")[0:-1]) + ".pyc"
    with open(pycout, "wb") as f:
        for val in pyc:
            f.write(chr(val))
    f.close()
    return pycout
  • Конвертируем файл с помощью:
fname = sys.argv[1]
pycout = convert_to_pyc(fname)
f = open(pycout, "rb").read()
  • Далее смотрим код через:
for x in range(len(f)):
    try:
        code = marshal.loads(f[x:])
        for item in code.co_consts:
            print('\t\t%s: %r' % (type(item), item))
            if str(type(item)) == "<type 'code'>":
                uncompyle6.main.decompile(2.7, item, sys.stdout)

и вытаскиваем оттуда переменные mod_fix, KEY, функции get_next_key и decrypt, а так же длинный массив байт: flag = [62, 125, 128, 30, 59, 77, 9, 125, 32, 40, 187, 190, 227, 207, 120, 195, 88, 210, 27, 20, 147, 218, 153, 83, 197]

  • Скрипт по дешифровке флага будет выглядеть так:
import struct

mod_fix = 0xFFFFFFFF
KEY = "SAFE"
flag = [62, 125, 128, 30, 59, 77, 9, 125, 32, 40, 187, 190, 227, 207, 120, 195, 88, 210, 27, 20, 147, 218, 153, 83, 197]

def get_next_key(current_key, current_byte):
    a = current_byte + current_key
    a = ((a << 12) + a + 0x7ED55D16) & mod_fix
    a = ((a >> 19) ^ a ^ 0xC761C23C)
    a = ((a << 5) + a + 0x165667B1) & mod_fix
    a = ((a << 9) ^ (a - 0x2C5D9B94))
    a = ((a << 3) + a - 0x28FB93B) & mod_fix
    a = ((a >> 16) ^ a ^ 0xB55A4F09)
    return a



def decrypt(data, bytes_key):
    key = struct.unpack('=L', bytes_key)[0]
    data = bytearray(data)
    for i in range(len(data)):
        old_byte = data[i]
        data[i] ^= key & 255
        key = get_next_key(key, old_byte)
    return bytes(data)


if __name__ == "__main__":
    print(decrypt(flag, KEY.encode("utf-8")))
  • Запускаем и получаем флаг: mctf{pyc_d3c0mp1l4710n!!}
@Defend2505
Copy link

можешь объяснить подробнее, как ты вытаскивал код из бинарника?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment