code hacking, zen coding

NDH2k12 Public Wargame – Break Me Like Your Sister – zomb_crypt

$ ls -la
total 64
-rw-r–r– 1 francois francois 38120 Jun 30 01:29 crypto-1.jpg
-rw-r–r– 1 francois francois 3226 Jun 13 20:50 zomb_crypt.pyc

$ file *
crypto-1.jpg: JPEG image data, JFIF standard 1.01
zomb_crypt.pyc: python 2.6 byte-compiled

$ python
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40)
[GCC 4.4.5] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import zomb_crypt
>>> import dis
>>> dir(zomb_crypt)
[‘Blowfish’, ‘PasswordError’, ‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘__package__’, ‘decode’, ‘decrypt’, ‘encrypt’, ‘getbf’, ‘hash’, ‘sys’]
>>> dis.dis(zomb_crypt.decrypt)
52 0 SETUP_EXCEPT 190 (to 193)

53 3 LOAD_GLOBAL 0 (open)
6 LOAD_FAST 0 (filename_in)
9 LOAD_CONST 1 (‘rb’)
12 CALL_FUNCTION 2
15 LOAD_ATTR 1 (read)
18 CALL_FUNCTION 0
21 STORE_FAST 3 (content)

read file content to content variable

54 24 LOAD_GLOBAL 2 (len)
27 LOAD_FAST 3 (content)
30 CALL_FUNCTION 1
33 LOAD_CONST 2 (16)
36 COMPARE_OP 0 (<) 39 JUMP_IF_FALSE 5 (to 47) 42 POP_TOP goodbye if len(content) < 16 55 43 LOAD_GLOBAL 3 (False) 46 RETURN_VALUE >> 47 POP_TOP

56 48 LOAD_FAST 3 (content)
51 LOAD_CONST 2 (16)
54 SLICE+2
55 STORE_FAST 4 (_hash)

First 16 bytes of file is a hash, store it in _hash

57 58 LOAD_GLOBAL 4 (hash)
61 LOAD_FAST 2 (password)
64 CALL_FUNCTION 1

hash password entered by user on command-line

67 LOAD_FAST 4 (_hash)
70 COMPARE_OP 3 (!=)
73 JUMP_IF_FALSE 13 (to 89)

if hash(user password) != stored _hash, goodbye. And we don’t care about the rest of the disassembly because we know we must have a password that match the file stored hash.

Which kind of hash ?

>>> dis.dis(zomb_crypt.hash)
26 0 LOAD_CONST 1 (‘ahky’)
3 STORE_FAST 1 (a)

27 6 LOAD_CONST 2 (’12bqb’)
9 STORE_FAST 2 (b)

28 12 LOAD_GLOBAL 0 (__import__)
15 LOAD_GLOBAL 1 (decode)
18 LOAD_FAST 1 (a)
21 CALL_FUNCTION 1
24 CALL_FUNCTION 1
27 STORE_FAST 3 (x)

29 30 LOAD_GLOBAL 2 (getattr)
33 LOAD_FAST 3 (x)
36 LOAD_GLOBAL 1 (decode)
39 LOAD_FAST 2 (b)
42 CALL_FUNCTION 1
45 CALL_FUNCTION 2
48 STORE_FAST 4 (y)

Obfuscated import and method name. What does decode do ? We don’t care.

>>> zomb_crypt.decode(‘ahky’)
‘zlib’
>>> zomb_crypt.decode(’12bqb’)
‘crc32’

so x = zlib, y = crc32

Nice. CRC32 is easy to bruteforce.

32 >> 83 LOAD_FAST 0 (s)
86 LOAD_CONST 4 (‘_’)
89 LOAD_CONST 3 (8)
92 LOAD_GLOBAL 3 (len)
95 LOAD_FAST 0 (s)
98 CALL_FUNCTION 1
101 BINARY_SUBTRACT
102 BINARY_MULTIPLY
103 BINARY_ADD
104 STORE_FAST 0 (s)

Pad password to length of 8 with ‘_’ (toto -> toto____)

33 107 LOAD_FAST 0 (s)
110 LOAD_CONST 5 (0)
113 LOAD_CONST 6 (4)
116 SLICE+3
117 LOAD_FAST 0 (s)
120 LOAD_CONST 6 (4)
123 LOAD_CONST 3 (8)
126 SLICE+3
127 ROT_TWO
128 STORE_FAST 1 (a)
131 STORE_FAST 2 (b)

a = password[0:4]
b = password[4:8]

34 134 LOAD_CONST 7 (‘%08X%08X’)
137 LOAD_FAST 4 (y)
140 LOAD_FAST 1 (a)
143 CALL_FUNCTION 1
146 LOAD_CONST 8 (4294967295L)
149 BINARY_AND
150 LOAD_FAST 4 (y)
153 LOAD_FAST 2 (b)
156 CALL_FUNCTION 1
159 LOAD_CONST 8 (4294967295L)
162 BINARY_AND

Convert to a and b to CRC32

>>> import zlib
>>> zlib.crc32(“toto”)
281847025

$ hexdump -C crypto-1.jpg | head -1
00000000 31 44 34 34 38 31 45 31 41 32 32 43 38 43 33 42 |1D4481E1A22C8C3B|

a = 1D4481E1
b = A22C8C3B

We need to find a CRC32 value that match a and b. Using the best hash cracker: Google

http://rulus.com/tool/hash/His4
http://rulus.com/tool/hash/n00b

password is His4n00b

$ python zomb_crypt.pyc d crypto-1.jpg His4n00b
[i] Decrypting crypto-1.jpg …
[i] OK

Share