- Name - khaki
- Category - Reverse Engineering
- Points - 6
- Description - n/a
- Binary - Download here
Command Prompt
C:\>khaki.exe
(Guesses: 1) Pick a number between 1 and 100:50
Too high, try again
(Guesses: 2) Pick a number between 1 and 100:25
Too low, try again
(Guesses: 3) Pick a number between 1 and 100:37
Too high, try again
(Guesses: 4) Pick a number between 1 and 100:30
Wahoo, you guessed it with 4 guesses
Status: 4 guesses
C:\>
Running strings on the binary reveals a lot of python functions and files. More specifically, the program has been compiled using py2exe:
root@kali: ~/Desktop
root@kali:~/Desktop# strings khaki.exe | grep -i py2exe
PY2EXE_VERBOSE
PY2EXE_VERBOSE
C:\Python27\lib\site-packages\py2exe\boot_common.pyR
C:\Python27\lib\site-packages\py2exe\boot_common.pyR
C:\Python27\lib\site-packages\py2exe\boot_common.pyR
C:\Python27\lib\site-packages\py2exe\boot_common.pyR
C:\Python27\lib\site-packages\py2exe\boot_common.pyR
C:\Python27\lib\site-packages\py2exe\boot_common.pyR
C:\Python27\lib\site-packages\py2exe\boot_common.pyt
C:\Python27\lib\site-packages\py2exe\boot_common.pyt
root@kali:~/Desktop#
The next step is to decompile the program and hopefully get the original python file back. We first use unpy2exe to get back the compiled python files (.pyc):
root@kali: ~/Desktop
root@kali:~/Desktop# python unpy2exe.py -o OUTPUT khaki.exe
Magic value: 78563412
Code bytes length: 4386
Archive name: -
Extracting C:\Python27\lib\site-packages\py2exe\boot_common.py.pyc
Extracting poc.py.pyc
root@kali:~/Desktop#
Then we try and decompile the pyc file back to it's original python code:
root@kali: ~/Desktop
root@kali:~/Desktop# python uncompyler.py OUTPUT\poc.py.pyc
# 2016.09.30 23:29:57 GMT Daylight Time
--- This code section failed: ---
0 LOAD_CONST -1
3 LOAD_CONST ''
[ ... snip ... ]
900 ROT_THREE ''
901 ROT_THREE ''
902 ROT_THREE ''
Syntax error at or near `POP_TOP' token at offset 18
# decompiled 0 files: 0 okay, 1 failed, 0 verify failed
# 2016.09.30 23:29:57 GMT Daylight Time
root@kali:~/Desktop#
The decompilation fails but we still get back some of the successfully-decompiled bytecode which is enough to complete the challenge. The bytecode contains a lot of NOPs which makes it difficult to read such as NOP, double ROT_TWO, triple ROT_THREE and LOAD_CONST -1; POP_TOP.
The following is the entire NOP-free python bytecode:
0 LOAD_CONST -1 3 LOAD_CONST '' 6 IMPORT_NAME 'sys' 9 STORE_NAME 'sys' 12 LOAD_CONST -1 19 LOAD_CONST '' 24 IMPORT_NAME 'random' 28 STORE_NAME 'random' 31 LOAD_CONST 'Flare-On ultra python obfuscater 2000' 34 STORE_NAME '__version__' 39 LOAD_NAME 'random' 46 LOAD_ATTR 'randint' 49 LOAD_CONST 1 52 LOAD_CONST 101 55 CALL_FUNCTION_2 '' 58 STORE_NAME 'target' 61 LOAD_CONST 1 64 STORE_NAME 'count' 70 LOAD_CONST '' 79 STORE_NAME 'error_input' 82 SETUP_LOOP '288' 88 LOAD_NAME 'True' 97 POP_JUMP_IF_FALSE '287' 100 LOAD_CONST '(Guesses: %d) Pick a number between 1 and 100:' 108 LOAD_NAME 'count' 111 BINARY_MODULO '' 112 PRINT_ITEM '' 113 LOAD_NAME 'sys' 116 LOAD_ATTR 'stdin' 119 LOAD_ATTR 'readline' 122 CALL_FUNCTION_0 '' 125 STORE_NAME 'input' 128 SETUP_EXCEPT '154' 131 LOAD_NAME 'int' 134 LOAD_NAME 'input' 140 LOAD_CONST '' 143 CALL_FUNCTION_2 '' 146 STORE_NAME 'input' 150 POP_BLOCK '' 151 JUMP_FORWARD '197' 154_0 COME_FROM '128' 154 POP_TOP '' 159 POP_TOP '' 160 POP_TOP '' 161 LOAD_NAME 'input' 167 STORE_NAME 'error_input' 174 LOAD_CONST 'Invalid input: %s' 178 LOAD_NAME 'error_input' 181 BINARY_MODULO '' 182 PRINT_ITEM '' 183 PRINT_NEWLINE '' 184 JUMP_BACK '88' 189 JUMP_FORWARD '197' 194 END_FINALLY '' 197_0 COME_FROM '151' 197_1 COME_FROM '189' 197 LOAD_NAME 'target' 200 LOAD_NAME 'input' 207 COMPARE_OP '==' 211 POP_JUMP_IF_FALSE '221' 214 BREAK_LOOP '' 218 JUMP_FORWARD '221' 221_0 COME_FROM '218' 221 LOAD_NAME 'input' 224 LOAD_NAME 'target' 227 COMPARE_OP '<' 234 POP_JUMP_IF_FALSE '253' 241 LOAD_CONST 'Too low, try again' 244 PRINT_ITEM '' 245 PRINT_NEWLINE '' 246 JUMP_FORWARD '262' 253 LOAD_CONST 'Too high, try again' 256 PRINT_ITEM '' 257 PRINT_NEWLINE '' 262_0 COME_FROM '246' 262 LOAD_NAME 'count' 265 LOAD_CONST 1 271 INPLACE_ADD '' 279 STORE_NAME 'count' 284 JUMP_BACK '88' 287 POP_BLOCK '' 288_0 COME_FROM '82' 288 LOAD_NAME 'target' 291 LOAD_NAME 'input' 294 COMPARE_OP '==' 297 POP_JUMP_IF_FALSE '342' 305 LOAD_CONST 'Wahoo, you guessed it with %d guesses\n' 309 LOAD_NAME 'count' 312 BINARY_MODULO '' 313 STORE_NAME 'win_msg' 316 LOAD_NAME 'sys' 319 LOAD_ATTR 'stdout' 322 LOAD_ATTR 'write' 331 LOAD_NAME 'win_msg' 334 CALL_FUNCTION_1 '' 338 POP_TOP '' 339 JUMP_FORWARD '342' 342_0 COME_FROM '339' 342 LOAD_NAME 'count' 347 LOAD_CONST 1 352 COMPARE_OP '==' 355 POP_JUMP_IF_FALSE '391' 358 LOAD_CONST 'Status: super guesser %d' 361 LOAD_NAME 'count' 364 BINARY_MODULO '' 366 PRINT_ITEM '' 367 PRINT_NEWLINE '' 372 LOAD_NAME 'sys' 378 LOAD_ATTR 'exit' 381 LOAD_CONST 1 384 CALL_FUNCTION_1 '' 387 POP_TOP '' 388 JUMP_FORWARD '391' 391_0 COME_FROM '388' 391 LOAD_NAME 'count' 396 LOAD_CONST 25 401 COMPARE_OP '>' 413 POP_JUMP_IF_FALSE '451' 419 LOAD_CONST 'Status: took too long %d' 425 LOAD_NAME 'count' 429 BINARY_MODULO '' 430 PRINT_ITEM '' 431 PRINT_NEWLINE '' 432 LOAD_NAME 'sys' 435 LOAD_ATTR 'exit' 438 LOAD_CONST 1 444 CALL_FUNCTION_1 '' 447 POP_TOP '' 448 JUMP_FORWARD '468' 451 LOAD_CONST 'Status: %d guesses' 455 LOAD_NAME 'count' 458 BINARY_MODULO '' 459 PRINT_ITEM '' 464 PRINT_NEWLINE '' 468_0 COME_FROM '448' 468 LOAD_NAME 'error_input' 474 LOAD_CONST '' 477 COMPARE_OP '!=' 486 POP_JUMP_IF_FALSE '896' 489 LOAD_CONST '' 492 LOAD_ATTR 'join' 495 LOAD_GENEXPR '<code_object <genexpr>&lgt;' 498 MAKE_FUNCTION_0 '' 504 LOAD_NAME 'error_input' 511 GET_ITER '' 515 CALL_FUNCTION_1 '' 518 CALL_FUNCTION_1 '' 521 LOAD_ATTR 'encode' 524 LOAD_CONST 'hex' 530 CALL_FUNCTION_1 '' 536 STORE_NAME 'tmp' 544 LOAD_NAME 'tmp' 549 LOAD_CONST '312a232f272e27313162322e372548' 552 COMPARE_OP '!=' 557 POP_JUMP_IF_FALSE '590' 560 LOAD_NAME 'sys' 565 LOAD_ATTR 'exit' 568 LOAD_CONST '' 571 CALL_FUNCTION_1 '' 576 POP_TOP '' 587 JUMP_FORWARD '590' 590_0 COME_FROM '587' 590 LOAD_CONST 67 593 LOAD_CONST 139 598 LOAD_CONST 119 602 LOAD_CONST 165 608 LOAD_CONST 232 611 LOAD_CONST 86 614 LOAD_CONST 207 618 LOAD_CONST 61 624 LOAD_CONST 79 628 LOAD_CONST 67 631 LOAD_CONST 45 637 LOAD_CONST 58 640 LOAD_CONST 230 647 LOAD_CONST 190 650 LOAD_CONST 181 654 LOAD_CONST 74 657 LOAD_CONST 65 660 LOAD_CONST 148 663 LOAD_CONST 71 669 LOAD_CONST 243 676 LOAD_CONST 246 683 LOAD_CONST 67 686 LOAD_CONST 142 690 LOAD_CONST 60 693 LOAD_CONST 61 702 LOAD_CONST 92 711 LOAD_CONST 58 722 LOAD_CONST 115 725 LOAD_CONST 240 728 LOAD_CONST 226 733 LOAD_CONST 171 738 BUILD_LIST_31 '' 741 STORE_NAME 'stuffs' 750 IMPORT_NAME 'hashlib' 753 STORE_NAME 'hashlib' 756 LOAD_NAME 'hashlib' 762 LOAD_ATTR 'md5' 765 LOAD_NAME 'win_msg' 768 LOAD_NAME 'tmp' 771 BINARY_ADD '' 772 CALL_FUNCTION_1 '' 779 LOAD_ATTR 'digest' 782 CALL_FUNCTION_0 '' 785 STORE_NAME 'stuffer' 788 SETUP_LOOP '890' 791 LOAD_NAME 'range' 794 LOAD_NAME 'len' 797 LOAD_NAME 'stuffs' 800 CALL_FUNCTION_1 '' 803 CALL_FUNCTION_1 '' 808 GET_ITER '' 809 FOR_ITER '889' 816 STORE_NAME 'x' 819 LOAD_NAME 'chr' 822 LOAD_NAME 'stuffs' 829 LOAD_NAME 'x' 832 BINARY_SUBSCR '' 837 LOAD_NAME 'ord' 840 LOAD_NAME 'stuffer' 843 LOAD_NAME 'x' 847 LOAD_NAME 'len' 850 LOAD_NAME 'stuffer' 853 CALL_FUNCTION_1 '' 856 BINARY_MODULO '' 861 BINARY_SUBSCR '' 866 CALL_FUNCTION_1 '' 876 BINARY_XOR '' 878 CALL_FUNCTION_1 '' 885 PRINT_ITEM '' 886 JUMP_BACK '809' 889 POP_BLOCK '' 890_0 COME_FROM '788' 890 PRINT_NEWLINE '' 893 JUMP_FORWARD '896' 896_0 COME_FROM '893' 896 LOAD_CONST '' 899 RETURN_VALUE ''Filtering the unnecessary parts, we get the following desired control flow:
- Line 313 - Set win_msg to 'Wahoo, you guessed it with %d guesses\n'
- where %d is a number between 1 and 26 (Lines 396 - 419)
- Lines 536 - 552 - tmp has to be equal to '312a232f272e27313162322e372548'
- Lines 590 - 741 - Set stuffs to [67, 139, ..., 226, 171]
- Lines 750 - 785 - Set stuffer to the MD5 of win_msg + tmp
- Lines 788 - 890 - XOR stuffs with stuffer as the key, and print each value
import hashlib import sys stuffs = [67, 139, 119, 165, 232, 86, 207, 61, 79, 67, 45, 58, 230, 190, 181, 74, 65, 148, 71, 243, 246, 67, 142, 60, 61, 92, 58, 115, 240, 226, 171] tmp = "312a232f272e27313162322e372548" for y in range (26): win_msg = "Wahoo, you guessed it with " + str(y) + " guesses\n" bin_add = win_msg + tmp stuffer = hashlib.md5(bin_add).digest() for x in range(len(stuffs)): sys.stdout.write((chr(stuffs[x] ^ ord(stuffer[x % len(stuffer)])))) print '\r'Running the program:
root@kali: ~/Desktop
root@kali:~/Desktop# python solution.py
[ .. snip .. ]
1mp0rt3d_pygu3ss3r@flare-on.com
[ .. snip .. ]
root@kali:~/Desktop#
No comments:
Post a Comment