📜 ⬆️ ⬇️

UFOCTF 2017: we decompile Python in the King Arthur assignment (PPC600)


Greetings to you habrayuzer! Recently, the annual information security Olympiad UFO CTF 2017 is over. This article will contain a single task assignment from the PPC section called “King Arthur” , for which you could get the maximum number of points - 600.

Let's start


In the description of the task was the following:
We received some strange attachment to the e-mail from a fan of knights. Help me figure out what the author meant.

And the file was available for download:

sword.py
#!/usr/bin/python import serpent """ ___ { _ } |/| {___} |_| |/| . |/| . (\________|w|________/) ( ___________________ ) v | | | v | | | | | | | | |PO0.HN7 | | | * TP0~~~< z| | |ON4.YH1 OP6| | | ON2| | |PO3| | |PY0 | | PY0 | | |PY0 z| | |PY0 PY0 | |z PY0| | | PY0| | |PY0| | |PH0 | | PY0 | | |PY0 z| | |PY0 PY0 | |z PY0| | | PY0| | |PY0| | |HN3 | | PY1 | | |PY0 z| | |PY0 PY0 | |z PN3| | | PT0| | |PY0| | |PN3 | | PY0 | | |PY0 z| | |TH3 PY0 | |z PY0| | | NY2| | |PY0| | |PY0 | | PN3 | | |PH0 z| | |PY0 PN4 | |z PY0| | | PY0| | |NY2| | |PT0 | | PY0 | | |YP3 z| | |PT0 PY0 | |z PO4| | | PY0| | |PY0| | |PT0 | | PN3 | | |PY0 z| | |PY0 HN2 | |z YO1| | | PO0| | |PY0| | |PY0 | | PY0 | | |TN2 z| | |YN3 YY7 | |z YY7| | | YY7| | |YY7| | |PO3 | | PY0 | | |PY0 z| | |PY0 PY0 | |z PH0| | | PY0| | |PY0| | |PY0 | | HO0 | | |PY0 z| | |PY0 PY0 | |z PO0| | | PY0| | |PY0| | |PY0 | | HN3 | | |YY4 z| | |PY0 PY0 | |z PY0| | | OP3| | |PY0| | |PY0 | | PN3 | | |PT0 z| | |PY0 PO4 | |z PT0| | | PY0| | |NO3| | |PT0 | | PY0 | | |NH3 z| | |PT0 PY0 | |z PN3| | | PY0| | |PY0| | |PN3 | | PH0 | | |PY0 z| | |PN3 PO0 | |z PY0| | | YP4| | |PO0| | |PY0 | | NP0 | | |PN3 z| | |PN0 PY0 | |z TY3| | | PO0| | |PY0| | |HO3 | | TO1 | | |PY0 z| | |PN3 YP0 | |z PY0| | | YH2| | |YO2| | |TN3 | | TN3 | | |PY0 z| | |NH3 PT0 | |z PY0| | | PN3| | |PH0| | |PY0 | | PN3 | | |PY0 z| | |PY0 PN3 | |z PO0| | | PY0| | |YP4| | |PO0 | | PY0 | | |NP0 z| | |PN3 YT0 | |z PY0| | | TY3| | |PO0| | |PY0 | | HO3 | | |HO3 z| | |PY0 PN3 | |z YP0| | | PY0| | |YH2| | |YO2 | | TN3 | | |TO2 z| | |PY0 NH3 | |z PT0| | | PY0| | |PN3| | |YH0 | | PY0 | | |TY0 z| | |PN3 YO0 | |z PY0| | | TY0| | |PN3| | |PO0 | | PY0 | | |TY0 z| | |YP4 PO0 | |z PY0| | | NP0| | |PN3| | |YN0 | | PY0 | | |TY3 z| | |PO0 PY0 | |z HO3| | | OT4| | |PY0| | |PN3 | | YP0 | | |PY0 z| | |YH2 YO2 | |z TN3| | | YN1| | |PY0| | |NH3 | | PT0 | | |PY0 z| | |PN3 TP0 | |z PY0| | | TY0| | |PN3| | |PH0 | | PY0 | | |TY0 z| | |PN3 PO0 | |z PY0| | | TY0| | |YP4| | |PO0 | | PY0 | | |NP0 z| | |PN3 TY0 | |z PY0| | | TY3| | |PO0| | |PY0 | | HO3 | | |TN2 z| | |PY0 PN3 | |z YP0| | | PY0| | |YH2| | |YO2 | | TN3 | | |YP0 z| | |PY0 PN3 | |z TH0| | | PY0| | |YH2| | |YO2 | | PN3 | | |PY0 z| | |PY0 HN2 | |z YO1| | | TO0| | |PY0| | |PY0 | | PY0 | | |TN2 z| | |HN3 TO0 | |z PY0| | | PY0| | |PY0| | |YP2 | | TN3 | | |OP3 z| | |YP3 HO3 | |z PY1| | | TH3| | |YN3| | |TN3 | | YP3 | | |NY1 z| | |PY1 TP0 | |z YN3| | | TN0| | |PY0| | |PY0 | | PY0 | | |YN3 z| | |PH0 PY0 | |z PY0| | | PY0| | |OP3| | |YH0 | | PY0 | | |PY0 z| | |PY0 ON2 | |z TO2| | | YH3| | |NP1| | |OT3 | | OT1 | | |OT1 z| | |HN3 YP0 | |z PY0| | | PY0| | |PY0| | |YT2 | | PT3 | | |YN3 z| | |TH3 PT1 | |z OP3| | | YO0| | |PY0| | |PY0 | | PY0 | | |NP3 z| | |PH2 YT3 | |z PH2| | | YH3| | |NP1| | |OT3 | | PT3 | | |YN3 z| | |HP0 PY0 | |z PY0| | | PY0| | |YN3| | |PP0 | | PY0 | | |PY0 z| | |PY0 OP3 | |z YO0| | | PY0| | |PY0| | |PY0 | | NP2 | | |HT1 z| | |HY2 ON2 | |z HT3| | | YH3| | |YH3| | |PH2 | | YN3 | | |PT0 z| | |PY0 PY0 | |z PY0| | | OP3| | |YH0| | |PY0 | | PY0 | | |PY0 z| | |HN1 OH2 | |z OH1| | | OP1| | |TY3| | |YO3 | | OH3 | | |HN3 z| | |YO0 PY0 | |z PY0| | | PY0| | |HN2| | |OY3 | | PO3 | | |PO3 z| | |YP3 HN3 | |z HN3| | | PT1| | |YO1| | |PH0 | | PY0 | | |PY0 z| | |PY0 OP3 | |z YN0| | | PY0| | |PY0| | |PY0 | | HO3 | | |PT3 z| | |OH3 YY2 | |z YN3| | | TN3| | |HY3| | |OY3 | | OP3 | | |OP3 z| | |PN0 PY0 | |z PY0| | | PY0| | |TH3| | |YN3 | | TN3 | | |YP3 z| | |YO1 PH0 | |z PY0| | | PY0| | |PY0| | |HO2 | | PN0 | | |PY0 z| | |PY0 PY0 | |z HO2| | | YP0| | |PY0| | |PY0 | | PY0 | | |YO1 z| | |PY0 PY0 | |z PY0| | | PY0| | |YO1| | |PY0 | | PY0 | | |PY0 z| | |PY0 HN3 | |z HP2| | | PY0| | |PY0| | |PY0 | | PN2 | | |NY1 z| | |NH2 PN2 | |z HP3| | | OH3| | |TN3| | |TH3 | | HP3 | | |PT3 z| | |PN3 HN3 | |z NH2| | | OY2| | |YT2| | |HP2 | | PO2 | | |OP2 z| | |YT2 NH2 | |z OP2| | | PT2| | |HN2| | |TY2 | | HN2 | | |NH2 z| | |HN3 YP3 | |z HO3| | | HY3| | |YP3| | |TN3 | | OP3 | | |NH2 z| | |HN3 HP3 | |z OY3| | | HO3| | |PO3| | |YP3 | | HN3 | | |NH2 z| | |HN2 YP3 | |z HO3| | | HY3| | |YP3| | |TN3 | | OP3 | | |TO1 z| | |TO3 PT3 | |z HN3| | | OP3| | |YP3| | |HO3 | | NH2 | | |HN2 z| | |YP3 HO3 | |z HY3| | | YP3| | |TN3| | |OP3 | | TO1 | | |TO3 z| | |PT3 HN3 | |z OP3| | | YP3| | |HO3| | |NH2 | | OP3 | | |YP3 z| | |HN3 OP3 | |z TN1| | | HY3| | |NP3| | |HN3 | | PN0 | | |PY0 z| | |PY0 PY0 | |z OP3| | | PT3| | |HN3| | |TY3 | | PN0 | | |PY0 z| | |PY0 PY0 | |z HN3| | | HY0| | |PY0| | |PY0 | | PY0 | | |PY0 z| | |PT0 TH0 | |z PT0| | | NP0| | |PT0| | |YO0 | | PT0 | | |NP0 z| | |PT0 YO0 | |z PO0| | | NH0| | |PT0| | |TH1 | | PH0 | | |YO1 z| | |PH0 PY0 | |z PY0| | | PY0| | |OP3| | |YH0 | | PY0 | | |PY0 z| | |PY0 HN3 | |z YP3| | | HO3| | |HY3| | |YP3 | | TN3 | | |OP3 z| | |OP3 PN0 | |z PY0| | | PY0| | |PY0| | |OP3 | | PT3 | | |HN3 z| | |TY3 YO1 | |z PH0| | | PY0| | |PY0| | |PY0 | | HO2 | | |YT0 z| | |PY0 PY0 | |z PY0| | | HO2| | |YH0| | |PY0 | | PY0 | | |PY0 z| | |YO1 PY0 | |z PY0| | | PY0| | |PY0| | |YO1 | | PY0 | | |PY0 z| | |PY0 PY0 | |z HN3| | | HP2| | |PY0| | |PY0 | | PY0 | | |PN2 z| | |NY1 NH2 | |z PN2| | | HP3| | |OH3| | |TN3 | | TH3 | | |HP3 z| | |PT3 PN3 | |z HN3| | | NH2| | |OY2| | |YT2 | | HP2 | | |PO2 z| | |OP2 YT2 | |z NH2| | | OP2| | |PT2| | |HN2 | | TY2 | | |HN2 z| | |NH2 HN3 | |z YP3| | | HO3| | |HY3| | |YP3 | | TN3 | | |OP3 z| | |NH2 HN3 | |z HP3| | | OY3| | |HO3| | |PO3 | | YP3 | | |HN3 z| | |NH2 HN2 | |z YP3| | | HO3| | |HY3| | |YP3 | | TN3 | | |OP3 z| | |TO1 TO3 | |z PT3| | | HN3| | |OP3| | |YP3 | | HO3 | | |NH2 z| | |HN2 YP3 | |z HO3| | | HY3| | |YP3| | |TN3 | | OP3 | | |TO1 z| | |TO3 PT3 | |z HN3| | | OP3| | |YP3| | |HO3 | | NH2 | | |OP3 z| | |YP3 HN3 | |z OP3| | | TN1| | |HY3| | |NP3 | | HN3 | | |YO0 z| | |PY0 PY0 | |z PY0| | | NH1| | |TO3| | |HP3 | | PN3 | | |OY3 z| | |TH3 YP3 | |z PP1| | | PT0| | |PY0| | |PY0 | | PY0 | | |HN3 z| | |PN0 PY0 | |z PY0| | | PY0| | |TH0| | |PO0 | | YN0 | | |TO0 z| | |zz z | | z | | | | | | | | \|/ v """ 


Immediately attracts attention string import serpent . For the “python serpent sword” request in Google, you can stumble upon a git repository , which judging by the description is just what we need.

Having studied the serpent.py code , we find there a description of the principle of "turning" the code into a sword:
')
Given the hex digit 65:
65% 32 = 1
floor (65/32) = 2
symbol for 65 is at index 1: 'PT'.
65 is also the 3rd occurrence of a 32-modulus of 1 (with 1
being the first occurrence and 33 being the second of course.)
hex code is this code for PT2

But the most interesting is located below:

 elif scriptType is _SERPENT: pyc = _serpent_sword_alphabet_to_hex(_lex_hex(sys.argv[0])) pycout = ".".join(sys.argv[0].split(".")[0:-1])+".pyc" with open(pycout, "wb") as f: for val in pyc: f.write(chr(val)) 

This code reads the converted file, and translates it back into .pyc . Rename the sword.py file to sword.ss.py and try to reverse it:

 redihi@kali:KingArthur$ python sword.ss.py RuntimeError: Bad magic number in .pyc file 

By slightly changing the code so that the sword.ss.pyc file is not deleted, we find out that the received file has a damaged header.

After a long search, we find an approximate description of the header of the .pyc file. But all attempts to change it to the faithful were not crowned with success.

In the same place in article, there is an example of compilation not of all file, but separate section of code. Probably in the same way, bypassing the header, restore the rest of the code. We throw a small script for this purpose:

unserpent.py
 #!/usr/bin/python import re import sys import marshal 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:]) print('Offset found: %d' % x) print('\targcount: %s' % code.co_argcount) print('\tcode: %s' % code.co_code.encode('hex')) print('\tconsts count: %d' % len(code.co_consts)) for item in code.co_consts: print('\t\t%s: %r' % (type(item), item)) print('\tfilename: %s' % code.co_filename) print('\tfirstlineno: %s' % code.co_firstlineno) print('\tflags: %s' % code.co_flags) print('\tname: %s' % code.co_name) print('\tnlocals: %s' % code.co_nlocals) print('\tstacksize: %s' % code.co_stacksize) print('\tvarnames count: %d' % len(code.co_varnames)) for item in code.co_varnames: print('\t\t%r' % item) break except ValueError: continue 


After starting, we get the output:

 redihi@kali:KingArthur$ ./unserpent.py sword.ss.py Offset found: 7 argcount: 0 code: 6401006400006c00005a00006402008400005a01006501008300000164000053 consts count: 3 <type 'NoneType'>: None <type 'int'>: -1 <type 'code'>: <code object task at 0x7f7e85aa9eb0, file "D:\Downloads\UFOCTF\TASKS\serpent\sources\Serpent-master\Serpent-master\test.py", line 4> filename: D:\Downloads\UFOCTF\TASKS\serpent\sources\Serpent-master\Serpent-master\test.py firstlineno: 1 flags: 0 name: <module> nlocals: 0 stacksize: 2 varnames count: 2 'serpent' 'task' 

As you can see, there is 1 more object code , and we need it. Add a couple more lines to decompile it:

 import uncompyle6 ... uncompyle6.main.uncompyle(2.7, code.co_consts[2], sys.stdout) 

Run again and get the finished script:

 # uncompyle6 version 2.9.10 # Python bytecode 2.7 # Decompiled from: Python 2.7.6 (default, Oct 26 2016, 20:30:19) # [GCC 4.8.4] # Embedded file name: D:\Downloads\UFOCTF\TASKS\serpent\sources\Serpent-master\Serpent-master\test.py line = raw_input('Enter line: \n') if line[:14:2] != 'XMg9v66': print 'Fail!' elif line[14::2] != 'yBfBg9va': print 'Fail!' elif line[-15:-30:-2] != 'Y1PXqggB': print 'Fail!' elif line[-1:-14:-2] != '3W74khw': print 'Fail!' else: print 'Success!' 

It remains the case for small, on the resulting code restore the flag:
ufoctf {XBMggg9qvX6P61yYBwfhBkg497vWa3}

Task completed! +600 rating!

Source: https://habr.com/ru/post/325580/


All Articles