(51) pwnable.kr passcode 문제 풀이
문제 설명
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?
문제 풀이
파일은 위와 같이 존재 하네요. passcode.c부터 열어 보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#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;
}
일단 코드를 보면 이상한 부분이 있습니다. 바로 로그인 함수의 scanf부분입니다. 보통은 주소를 넘겨주고 해당 주소에 값을 받아오는데 &기호가 없이 그냥 변수를 적었습니다.
그래서 그냥 실행하면 초기화 되지 않은 변수에 들어 있는 값의 주소에 접근을 시도하기에 
이렇게 Segmentation fault에러가 납니다.
이제 c언어 코드만으로 얻을 수 있는 정보는 더 없는듯 합니다. 이제 실행파일의 어셈블리를 보도록 합시다.
개인적으론 radare2가 더 좋은데 없는 관계로 gdb를 쓰도록 하겠습니다. 먼저 main입니다. 
c코드도 그렇듯이 별건 없고 함수 호출과 텍스트 출력이 전부입니다.
입력받는 name은 ebp-0x70(ebp-112)에서 부터 ebp-0xc(ebp-12)까지 100바이트 크기로 존재합니다.
passcode1는 ebp-0x10(ebp-16)에 존재하고, passcode2는 ebp-0xc(ebp-12)에 존재하고 있네요.
여기서 welcome의 name의 범위를 생각해보면 마지막 4바이트가 passcode1과 같은 주소를 쓰고 있네요. 그렇다면 96바이트의 더미 데이터와 조작을 원하는 주소 4바이트를 name의 입력으로 사용한다면 passcode1입력을 받을때 원하는 데이터(4바이트)를 원하는 주소에 넣을 수 있게 됩니다.
그렇다면 어디에 뭘 넣어야 할까요?
flag를 얻으려면 system함수가 실행되도록 해야합니다. 그렇다면 해당 명령을 실행하는 0x080485e3코드로 이동할 수 있으면 됩니다.
이걸 이해하려면 PLT와 GOT에 대해 알아야 합니다.
간단하게만 말하면 외부 프로시저를 이용할 때 PLT를 타고 가서 GOT테이블에서 주소를 찾아서 실행하는데 만약 GOT테이블의 값을 바꿔버린다면 함수를 실행할때 이상한 주소로 jmp하게 만들 수 있습니다.
0x8048430주소를 확인해보니 0x804a004의 값으로 jmp하는것을 확인할 수 있습니다.
따라서 passcode1에 0x804a004를 넣은 상태로 scanf에서 주소를 입력받으면 scanf가 끝나고 fflush함수가 실행되면서 입력받은 주소의 코드로 jmp하게 됩니다.
당연히 이때는 scanf가 10진 정수를 받고 있으므로 주소를 10진수로 바꾸어 넣어줘야 합니다. 0x080485e3로 이동해야 하므로 134514147를 scanf의 입력으로 사용합니다.
조금 복잡했네요.. 결과적으로 다음과 같이 익스플로잇하면 
Sorry mom.. I got confused about scanf usage :(라는 flag를 얻을 수 있습니다.



