- Name - shell.php
- Category - Reverse Engineering
- Points - 1
- Binary - Download here
<?php $o__o_ = base64_decode('QAYLHhIJ ... [snip] ... kCEh8NSh4PEA4eGFsaGXoo'); $o_o = isset($_POST['o_o']) ? $_POST['o_o'] : ""; $o_o = md5($o_o) . substr(MD5(strrev($o_o)) , 0, strlen($o_o)); for ($o___o = 0; $o___o < 2268; $o___o++) { $o__o_[$o___o] = chr((ord($o__o_[$o___o]) ^ ord($o_o[$o___o])) % 256); $o_o.= $o__o_[$o___o]; } if (MD5($o__o_) == '43a141570e0c926e0e3673216a4dd73d') { if (isset($_POST['o_o'])) @setcookie('o_o', $_POST['o_o']); $o___o = create_function('', $o__o_); unset($o_o, $o__o_); $o___o(); } else { echo '<form method="post" action="shell.php"><input type="text" name="o_o" value=""/><input type="submit" value=">"/></form>'; } ?>The script is easy enough to understand. It basically does the following:
- Base64 decodes a massive string (line 2)
- Accepts a password via a POST request (line 3)
- Concatenates it's MD5 and the substring of the MD5 of the reverse string (line 4)
- Uses the result as the key to XOR the massive string (lines 6 - 10)
- Creates a new function from the decrypted text (line 15)
- Calls the function (line 17)
import base64 import string encoded = "QAYLHhIJ ... [snip] ... kCEh8NSh4PEA4eGFsaGXoo" decoded = base64.b64decode(encoded) possible_chars = "0123456789abcdef" for key_len in xrange(33, 65): print "-- Key Length: " + str (key_len) + " --" for key_pos in xrange(0, key_len): potential_sol = [] for possible_char in possible_chars: temp_possible_char = possible_char possible = True for pos in range(key_pos, len(decoded), key_len): temp_possible_char = chr((ord(decoded[pos]) ^ ord(temp_possible_char))) if temp_possible_char not in string.printable: possible = False break if possible: potential_sol.append(possible_char) if potential_sol: print key_pos, ":", potential_solRunning the script we get:
Command Prompt
C:\>python possible_solutions.py
-- Key Length: 33 --
-- Key Length: 34 --
-- Key Length: 35 --
-- Key Length: 36 --
-- Key Length: 37 --
-- Key Length: 38 --
-- Key Length: 39 --
-- Key Length: 40 --
-- Key Length: 41 --
-- Key Length: 42 --
9 : ['4', '6', '7']
-- Key Length: 43 --
-- Key Length: 44 --
-- Key Length: 45 --
-- Key Length: 46 --
-- Key Length: 47 --
-- Key Length: 48 --
-- Key Length: 49 --
-- Key Length: 50 --
-- Key Length: 51 --
31 : ['e']
-- Key Length: 52 --
-- Key Length: 53 --
-- Key Length: 54 --
-- Key Length: 55 --
49 : ['c', 'f']
-- Key Length: 56 --
39 : ['c']
-- Key Length: 57 --
-- Key Length: 58 --
-- Key Length: 59 --
16 : ['a', 'd', 'f']
-- Key Length: 60 --
-- Key Length: 61 --
-- Key Length: 62 --
-- Key Length: 63 --
-- Key Length: 64 --
0 : ['c', 'd', 'e']
1 : ['a', 'b', 'c', 'd', 'e']
2 : ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
3 : ['8', '9']
4 : ['2', '3', '4', '5', '6']
5 : ['0', '1', '2', '3', '4', '6', '7', '8']
6 : ['b', 'c', 'd', 'f']
7 : ['8', '9']
8 : ['0', '2', '4', '5']
9 : ['a', 'b', 'f']
10 : ['0', '2', '3', '4', '5', '6', '7', '8', '9']
11 : ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
12 : ['b', 'c', 'd']
13 : ['8', '9']
14 : ['0', '2', '3', '5']
15 : ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
16 : ['a', 'b', 'c', 'd', 'e']
17 : ['a', 'b', 'c', 'd', 'e', 'f']
18 : ['b', 'c', 'd', 'f']
19 : ['2', '3', '4', '5', '7']
20 : ['2', '3', '7']
21 : ['5', '6', '7']
22 : ['0', '1', '2', '4', '5', '6', '7', '8', '9']
23 : ['0', '1', '5', '6', '7']
24 : ['8', '9']
25 : ['a', 'b', 'c', 'd', 'e', 'f']
26 : ['b', 'c', 'd', 'e']
27 : ['8', '9']
28 : ['d', 'e']
29 : ['8', '9']
30 : ['0', '1', '2', '3', '4', '5', '6', '7', '9']
31 : ['a', 'b', 'c', 'd', 'e', 'f']
32 : ['0', '1', '2', '3', '5', '6', '7', '8', '9']
33 : ['0', '1', '2', '3', '4', '5', '6', '7', '9']
34 : ['0', '1', '3', '6', '7']
35 : ['b', 'c', 'd', 'e']
36 : ['d', 'e', 'f']
37 : ['0', '1', '4', '6', '7']
38 : ['2', '3', '4', '5']
39 : ['0', '1', '4', '6', '7']
40 : ['1', '2', '3', '4', '5', '6', '7', '8', '9']
41 : ['0', '3', '4', '7', '8', '9']
42 : ['a', 'e']
43 : ['a', 'f']
44 : ['b', 'c']
45 : ['0', '1', '3', '6', '7']
46 : ['8', '9']
47 : ['1', '2', '3', '5', '6', '7', '8', '9']
48 : ['d', 'e']
49 : ['0', '1', '7']
50 : ['0', '1', '5', '6', '7']
51 : ['0', '1', '2', '3', '4', '5', '6', '7', '9']
52 : ['a', 'b', 'c', 'f']
53 : ['a', 'b', 'c', 'd', 'e', 'f']
54 : ['a', 'b', 'c', 'd', 'f']
55 : ['a', 'b', 'c', 'd', 'e', 'f']
56 : ['0', '1', '2', '3', '5', '6', '7', '8', '9']
57 : ['0', '1', '3', '6', '7']
58 : ['8', '9']
59 : ['a', 'e', 'f']
60 : ['0', '1', '2', '3', '6', '7']
61 : ['a', 'b', 'c', 'e', 'f']
62 : ['a', 'e', 'f']
63 : ['b', 'c', 'd']
C:\>
Here we've hit 2 birds with 1 stone. It is obvious from the script that the the key length is 64 as it has a potential solution for each position of the key. We also have a list of potential solutions that we can use to start decrypting the text.
So how are going to further reduce the potential solutions? Well, it's a semi-manual task; and it's at this point that the challenge becomes a bit mundane. Let's try and find out the first 4 characters of the key with this script:
import base64 import itertools encoded = "QAYLHhIJ ... [snip] ... kCEh8NSh4PEA4eGFsaGXoo" decoded = base64.b64decode(encoded) pos_key = [ ['c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e'], ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], ['8', '9']] for x in itertools.product(*pos_key): key1 = ''.join(x) key = key1 + ('_' * (64 - len(key1))) decrypted = [None] * 2268 for x in range(2268): decrypted[x] = chr((ord(decoded[x]) ^ ord(key[x])) % 256) key = key + decrypted[x] print "Key :" + key1 print ''.join(decrypted)[:len(key1)] , '|', ''.join(decrypted)[64*10:(64*10)+len(key1)], '|', ''.join(decrypted)[64*31:(64*31)+len(key1)] , '|', ''.join(decrypted)[64*32:(64*32)+len(key1)] printThe script covers the first 4 characters of the 64-char key. Notice that on line 8 we put the possible solutions for the first 4 chars obtained from the previous result. For each permutation of these characters (line 10), we decrypt sections of the text (line 16), and print some parts (line 20) which we will later manually verify if they make sense or not. Running the above script:
Command Prompt
C:\>python stage1_decrypter.py
[ ... snip ... ]
Key :db68
$d=& | $kex | ost# | e="s
Key :db69
$d=' | $key | ost" | e="r
Key :db78
$d<& | $kdx | osu# | e=#s
[ ... snip ... ]
C:\>
Note the string '$key' which indicates that we're on the right track with 'db69'. Using this labour-intensive, nerve-wracking method we finally get 'db6952b84a49b934acb436418ad9d93d237df05769afc796d067bccb379f2cac and a 2nd PHP script as the decrypted text:
$d=''; $key = ""; if (isset($_POST['o_o'])) $key = $_POST['o_o']; if (isset($_POST['hint'])) $d = "www.p01.org"; if (isset($_POST['t'])) { if ($_POST['t'] == 'c') { $d = base64_decode('SDcGHg1feVUIEhsbDxFhIBIYFQY+VwMWTyAcOhEYAw4VLVBaXRsKADMXTWxrSH4ZS1IiAgA3GxYUQVMvBFdVTysRMQAaQUxZYTlsTg0MECZSGgVcNn9AAwobXgcxHQRBAxMcWwodHV5EfxQfAAYrMlsCQlJBAAAAAAAAAAAAAAAAAFZhf3ldEQY6FBIbGw8RYlAxGEE5PkAOGwoWVHgCQ1BGVBdRCAAGQVQ2Fk4RX0gsVxQbHxdKMU8ABBU9MUADABkCGHdQFQ4TXDEfW0VDCkk0XiNcRjJxaDocSFgdck9CTgpPDx9bIjQKUW1NWwhERnVeSxhEDVs0LBlIR0VlBjtbBV4fcBtIEU8dMVoDACc3ORNPI08SGDZXA1pbSlZzGU5XVV1jGxURHQoEK0x+a11bPVsCC1FufmNdGxUMGGE='); $key = preg_replace('/(.)../', '$1', $key); } if ($_POST['t'] == 's') { $d = base64_decode('VBArMg1HYn1XGAwaAw1GDCsACwkeDgABUkAcESszBEdifVdNSENPJRkrNwgcGldMHFVfSEgwOjETEE9aRlJoZFMKFzsmQRALSilMEQsXHEUrPg9ZDRAoAwkBHVVIfzkNGAgaBAhUU00AAAAAAAAAAAAAAAAASkZSVV0KDAUCHBFQHA0MFjEVHB0BCgBNTAJVX3hkAkQiFh8ESw0AG0M5MBNRGkpdWV4bVEEVdGJGRR9XGBgcAgpVCDAsCA0GGAVWBAwcBxQqKwRCGxgbVkJFR11IdHcbRFxOUkNNV0RAVXIKSgxCWk1aVkdGQVI8dxRTVl5CR0JLVAQdOStbXkRfXlxOFEULUCp2SFJIUlVGQlUtRhExMQQLJyMmIFgDTUQtYmZIRUAECB4MHhtWRHA9Dh0WSWZmWUEHHBUzYQ=='); $key = preg_replace('/.(.)./', '$1', $key); } if ($_POST['t'] == 'w') { $d = base64_decode('DycdGg1hYjl8FURaAVZxPhgNOQpdMxVIRwNKc0YDCCsDVn5sJxJMHmJJOgArB1olFA0JHQN+TlcpOgFBKUEAA1M+RVUVDjsWEy8PQUEMV3IsSgJxCFY0IkJAGVY3HV9DbQsRaU1eSxl6IR0SEykOX2gnEAwZGHJHRU0OUn4hFUUADlw8UhRPNwpaJwlZE14Df1IRDi1HS30JFlZAHnRAEQ4tR0p9CRZXQB50LFkHNgNfEgROWkVLZV1bGHVbHyJMSRFZCQtGRU0bQAFpSEtBHxsLVEdaeEEUfCd2akdKYAFaJXBdT3BeHBRFV3IdXCV1PhsUXFUBBR5hXFwwdxsab1kECFoaM0FET2pEd2owBXpAC2ZAS11sMhVmJREWVlFyDV4ldFIdcUMBWlBbcl5CSGFTUCEPW08eEyYNSgJhYjl8Tk9BCUpvDxsAODBeLwUfE08AAAAAAAAAAAAAAAAAEXFkfV1wB0ctDRM='); $key = preg_replace('/..(.)/', '$1', $key); } while(strlen($key) < strlen($d)) $key = $key.$key; $d = $d ^ $key; } if (strlen($d)) echo $d; else echo '<form action="shell.php" method="post"><input type="hidden" name="o_o" value="'.$key.'"><input type="radio" name="t" value="c"> Raytraced Checkboard<br> <input type="radio" name="t" value="s"> p01 256b Starfield<br> <input type="radio" name="t" value="w"> Wolfensteiny<br><input type="submit" value="Show"/></form>';Alas, another 3 decryption exercises. This time the key is split into 3 parts by taking every other 3rd char, and each one decrypts a different string. At this point I was completely lost as to how I'm going to decrypt these texts or obtain the key so I made a leap of faith which, luckily for me, turned out to be correct. I assumed that the decryption key was the key to the challenge, i.e. the final email which, just like in all the challenges, ends with '@flare-on.com'. If we make this assumption then the 3 partial keys in question should end with '@a-.m', 'froc' and 'leno'. The plan now is to try each of these partial keys with each of the encrypted text and hopefully get something that makes sense in one of the combinations. The following script tries '@a-.m' against the 3rd ciphertext at each position and prints out the resultant decrypted text if it is printable:
import base64 import string cb = "DycdGg1hYjl8FURaAVZxPhgNOQpdMxVIRwNKc0YDCCsDVn5sJxJMHmJJOgArB1olFA0JHQN+TlcpOgFBKUEAA1M+RVUVDjsWEy8PQUEMV3IsSgJxCFY0IkJAGVY3HV9DbQsRaU1eSxl6IR0SEykOX2gnEAwZGHJHRU0OUn4hFUUADlw8UhRPNwpaJwlZE14Df1IRDi1HS30JFlZAHnRAEQ4tR0p9CRZXQB50LFkHNgNfEgROWkVLZV1bGHVbHyJMSRFZCQtGRU0bQAFpSEtBHxsLVEdaeEEUfCd2akdKYAFaJXBdT3BeHBRFV3IdXCV1PhsUXFUBBR5hXFwwdxsab1kECFoaM0FET2pEd2owBXpAC2ZAS11sMhVmJREWVlFyDV4ldFIdcUMBWlBbcl5CSGFTUCEPW08eEyYNSgJhYjl8Tk9BCUpvDxsAODBeLwUfE08AAAAAAAAAAAAAAAAAEXFkfV1wB0ctDRM=" c = base64.b64decode(cb) key = "@a-.m" for x in range(len(c)-len(key)): temp = ''.join(chr(ord(x) ^ ord(y)) for x,y in zip(key,c[x:])) printable = True for y in temp: if y not in string.printable: printable = False break if printable: print x, tempRunning the script:
Command Prompt
C:\>python xor_cracker.py
0 OF04`
1 g|7#
3 ZlLLT
6 "XQ;)
8 <titl
9 U%w/;
14 1_5#T
17 MX's^
21 stein
[ ... snip ... ]
318 "XQ`"
320 </bod
324 I+B!v
[ ... snip ... ]
C:\>
We start noticing some HTML code at positions 8 and 320. At position 21 we also get 'stein' which is part of 'Wolfensteiny' from the PHP script. Using this information we can find the rest of the partial key which turns out to be '3Oiwa_o3@a-.m'. Using the same method we get the other 2 partial keys: 't_rsaat_4froc' and 'hx__ayowkleno'
Combining the 3 partial keys we get: th3_xOr_is_waaaay_too_w34k@flare-on.com
No comments:
Post a Comment