这是一道ISG决赛的题目,漏洞比较多,水平有限如有不对之处,欢迎指出。
第一处:
int __cdecl vuln()
{
char s; // [sp+1Ch] [bp-6Ch]@1
while ( 1 )
{
puts("We want your advice on Ye1p please.");
printf("Leave your message: ");
__isoc99_scanf("%s", &s); //显然这里可以溢出
if ( strlen(&s) > 0x10 )
break;
puts("Length too small! Input again.");
putchar(10);
}
return puts("We got that. Thanks.");
}
第二处比较隐蔽,需要理解rest对象的数据结构。
这个数据结构大小是13个dword,其中最后一个dword是这样被赋值的:
dword_804B0A0[13 * v1 + 12] = (char *)&unk_804C500 + 128 * v1;
这里数组可以越界访问,因为没有限制输入的索引大小。
printf("Input the index of Rest. you want to edit: ");
v3 = sub_80487B9();
if ( dword_804B0A0[13 * v3] == -1 )
{
puts("Not exist.");
}
else
{
puts("New score XD: ");
v4 = sub_80487B9();
if ( v4 >= 0 )
{
dword_804B0A0[13 * v3] = v4;
.......
}
在新建rest对象输入其Road信息时,你就可以在0x804C500后的地方伪造一个rest对象的数据结构,它的第3个dword也是一个指针,可以打印出任意地址的数据(导致内存泄漏);这样就可以为下一步越界访问并打印数据做好准备(0x804C500就在对象数组0x804B0A0[1300]的尾部附近)。
puts("On which road(no more than 128 characters)? ");
memset((void *)((v1 << 7) + 0x804C500), 0, 0x80u);
sub_804871D((v1 << 7) + 0x804C500, 128); //接受输入的road信息
dword_804B0A0[13 * v1 + 12] = (char *)&unk_804C500 + 128 * v1;
当v3索引越界,指向伪造的数据结构时:
printf("Rest. index: %d\n", v3);
printf("Rest. name: %s\n", 0x34 * v3 + 0x804B0AC);
printf("Rest. score: %d\n", dword_804B0A0[13 * v3]);
printf("Recommended Dish: %s\n", dword_804B0A0[13 * v3 + 2]); //打印任意地址的数据
sprintf(&s, "Rest. address: No. %d %s", dword_804B0A0[13 * v3 + 11], dword_804B0A0[13 * v3 + 12]);
puts(&s);
下面是在任意地址写任意数据的地方:
puts("Do you want to change the description of the recommended dish(y/n)? ");
sub_804871D(&v5, 8);
if ( v5 == 'y' )
{
puts("New len: ");
dword_804B0A0[13 * v3 + 1] = sub_80487B9();
puts("New description: ");
sub_804871D(dword_804B0A0[13 * v3 + 2], dword_804B0A0[13 * v3 + 1] + 1);// 这里修改了puts的实际地址
}
puts("\nThings are changed. Thank you."); // 这里就可以执行任意命令
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)