문제를 보니 c코드를 이용하는 듯하다다.
파일을 확인해 봤는데 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;
}
위와 같은 코드를 확인할 수 있다.
코드를 분석해보니 먼저 이름을 입력받고 passcode를 두개 입력받는데 각각 338150, 13371337일 경우 flag를 확인할 수 있다.
그런데 login 함수의 scanf 에서 passcode1과 passcode2 앞에 '&'기호가 빠진 것을 확인할 수 있다.
따라서 passcode1과 passcode2에 값을 할당하는 것이 아니라 그 변수가 가리키는 주소에 입력값을 저장한다고 생각할 수 있다.
gdb로 welcome 함수를 먼저 분석했더니 0x0804862f에서 [ebp-0x70]에 입력값을 저장하는 것을 알 수 있다.
다음은 login 함수를 분석했다.
0x0804857c에서 [ebp-0x10]이 passcode1의 주소라는 것을 알 수 있다.
주소값을 계산해보면, 0x70-0x10 = 0x60 = 96바이트 이므로 name에서 할당받은 100바이트 중 4바이트를 이용하여 passcode1의 값을 조작할 수 있다.
passcode1에 무슨 값을 넣어야 할까? 여기서 GOT overwrite를 사용할 수 있다.
GOT overwrite란 dynamic link 방식으로 컴파일된 바이너리가 공유 라이브러리를 호출할 때 사용되는 PLT와 GOT를 이용하는 공격 기법이다.
PLT(Procedure Linkage Table)는 외부 프로시저를 연결시켜주는 테이블이다. 이를 통해 다른 라이브러리에 있는 프로시저를 호출하여 사용할 수 있다.
GOT(Global Offset Table)는 PLT가 참조하는 테이블로 프로시저들의 주소가 들어있다.
GOT overwrite를 통해 주소를 변조하면 원래의 함수가 아닌 변조한 함수가 호출된다.
이 문제에서는 passcode1에 fflush의 GOT 주소를 넣어줄 수 있다. 그리고 fllush의 GOT 주소를 c코드에 있는 system("/bin/cat flag")부분으로 바꿔 overwrite 해주면 flag를 열 수 있다.
fflush의 GOT 주소를 먼저 확인해보았다.
login 함수의 0x08048593에서 0x8048430가 fllush 함수의 시작이라는 것을 알 수 있다.
0x804a004가 fflush의 GOT 주소라는 것을 확인하였다.
system("/bin/cat flag")의 주소는 login 함수를 gdb로 분석한 사진에서 0x080485e3이라는 것을 알 수 있다.
즉, 0x804a004에 system("bin/cat flag")의 주소인 0x080485e3을 넣어주면 flag를 확인할 수 있다.
페이로드는 다음과 같이 작성할 수 있다.
(python -c 'print "a"*96 + "\x04\xa0\x04\x08"'; cat) | ./passcode
이 때, scanf("%d", passcode1)로 입력하므로 0x080485e3의 10진수인 134514147을 입력해준다.
flag를 확인할 수 있다.
좋은 글이네요. 공유해주셔서 감사합니다.