Saturday, September 11, 2010

LEET MORE CTF 2010 write up - Lottery

This is the second and last challenge that I had time to play. I solved it :).

The challenge random 39 digits and give you a number of participant. You have to put the correct random number to win this lottery. When you put a wrong number, you get the correct random number.

I had put a lot of wrong number to see random numbers.
Here is the result when a number of participant is 391441 - 391447
756883670921640125823051707628843433985
756982681967192314311352115314173149185
757081693012744351683925071170856026113
757180704058296540172225478856185741313
757279715103848577544798434712868618241
757378726149400614917371390569551495169
757477737194952803405671798254881210369
Here is the result when a number of participant is 391449 - 391455
757675759286057029266545161796893802497
757774770331609066639118117653576679425
757873781377161104011691073510259556353
757972792422713745847173836681529786369
758071803468265329872564437052272148481
758170814513817971708047200223542378497
758269825559370009080620156080225255425
With these numbers, I saw a pattern. Let me added some white-spaces.
7568 83 670921640125823051707628843433985
7569 82 681967192314311352115314173149185
7570 81 693012744351683925071170856026113
7571 80 704058296540172225478856185741313
7572 79 715103848577544798434712868618241
7573 78 726149400614917371390569551495169
7574 77 737194952803405671798254881210369
See it? The first part (4 digits) is decreased by one. The second part (next 2 digits) is increased by one.

I also tried to make the next 2 digits as another part that is increased by one. But I saw
7576 75 759286057029266545161796893802497
7577 74 770331609066639118117653576679425
It is increased by 2.

Then I tried the diff of each digits in last part (last 33 digits). I found they (first 5 digits of last part) are changed like "(prev + x[i]) mod 10" or "(prev + x[i] +1) mod 10". It looks like a sum up of previous number. Then I tried to diff them.
681967192314311352115314173149185 - 670921640125823051707628843433985 = 11045552188488300407685329715200
693012744351683925071170856026113 - 681967192314311352115314173149185 = 11045552037372572955856682876928
704058296540172225478856185741313 - 693012744351683925071170856026113 = 11045552188488300407685329715200
715103848577544798434712868618241 - 704058296540172225478856185741313 = 11045552037372572955856682876928
...
I got about 4 numbers from diffing them. But there are only 2 that I got very often. They are
11045552188488300407685329715200 
and
11045552037372572955856682876928
.

Then, I used
11045552188488300407685329715200
as my magic number and used the pattern I found for guessing. After a few tries, I got
You are realy lucky!!
Congratulations!! You win, send this WMcode to your bank: "C988EC4DC91EA4864FAA6B7D65030961B218D19CD96CF29DE28166F59B606158"
I won the lottery ;)

When the game end, hellman told the solution in IRC. Here is what he said
"in lottery random number generator was seeded with number of participants, and word 'uniform' points to erlangs random uniform, so just use erlang to guess the number"

LEET MORE CTF 2010 write up - Oh Those Admins!

This challenge is SQL injection. The line of problem is (I cannot remember the exact column and table name)
$r = mysql_query("SELECT login FROM admin WHERE password='" . md5($_GET['password'], true) . "'");
Normally, web sites keep the password hash as hex string. But this challenge keep raw hash (binary 16 bytes) in database. Binary can be string. So To bypass login, the output of md5 has to look like
' or 1=1#
The above string is what I thought first. But it is too long. To make the brute forcing fast, the required output string should be short. After checking from MySQL doc, I could make it shorter. Here is the list what I found
'or 1#    <== no need for space after single quote, any non-zero number is TRUE
'||1#     <== || is same as OR, no need for space after ||
Before writing the code for brute forcing, I remembered I can put non-printable characters in password using '%XX'. So 1 byte can be 256 values. No charset.

My code for brute forcing is http://pastebin.com/2xMG9rKi.

Ran it about 20 minutes on my slow windows pc, then got it.

password: 34b854c8
password: %34%b8%54%c8
result: c13e807082277c7c36231ed0dd34a863
result: ม>€p‚'||6# ะ4จc

Note: on linux, compile with "gcc -O2 -lssl -o prog prog.c" Note: If you want to see result from my program quick, run it with "./prog 4 4 200"

Submit it from url bar
url?password=%34%b8%54%c8
,then got the real admin hash. It is "071CC0720D0ABD73F61A291224F248D6". But I could not reverse admin hash :( so poor me. When searched in google, I found it in hashkiller but it was not solved.

Below is not my solution

Before finished this post, I found other 2 writeups of this challenge. Very nice solutions. They found shorter SQL injection string.

First is http://cvk.posterous.com/sql-injection-with-raw-md5-hashes. The SQL injection string is
'||'
Here is the modification of my code: http://pastebin.com/ThxBESPs. Got the result in a few minutes.
password: 2c55c819
password: %2c%55%c8%19
result: 3157e727097c7c27342e7dc2729f75ed
result: 1W็'    ||'4.}ยrŸuํ
Second is http://blog.nibbles.fr/?p=2039. The SQL injection string is
'='
Here is the modification of my code: http://pastebin.com/w5E54PNz. Got the result in a second.
password: 22a80f
password: %22%a8%0f
result: 047f1f9ed77f467a273d279d8e521422
result:   žืFz'='ŽR "