- 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