出于演示/教育目的,我想编写一个简单的概念验证应用程序,该应用程序使用缓冲区溢出来执行此应用程序中通常不调用的代码。我想的是这样的:
#include <iostream>
#include <cstring>
void vulnerableFunction(const char* input) {
char buffer[10];
strcpy(buffer, input);
}
void printSomething(){
std::cout << "This should not be executed" << std::endl;
}
int main() {
const char* input = "This is a long string that will cause a buffer overflow";
vulnerableFunction(input);
return 0;
}
使用输入字符串,我想覆盖IP并将其指向
printSomething()
方法的内存位置,然后像这样执行它。
所以第一个问题:这样可能吗?
我用 Immunity Debugger 对其进行了分析,并能够准确地创建一个覆盖 EIP 的字符串。所以我知道偏移量,缺少的是找到
printSomething()
方法调用的确切位置。有人知道我该怎么做吗?
是的,你可以做到这一点。根据 ASLR 的状态,可以使用几种不同的方法来查找 printSomething 的位置,但无论如何,最简单的方法就是使用现有的 C 运算符来获取函数的地址:
&printSomething
然后,您需要将该地址的值附加到传递给易受攻击函数的字符串中,例如使用memcpy
char input[64] = "AAAAA...A"; //64 As
void* printSomethingAddress = &printSomething;
memcpy(input + ipOffset,&printSomethingAddress,(sizeof(void*)));
vulnerableFunction(input);
这里的ipOffset是从你在vulnerableFunction中strcpy到的缓冲区的开头到保存的指令指针的位置的距离。
需要注意的几件事:
ipOffset 距离可能会根据细微差别而变化 代码和编译环境。使用调试器和反汇编器 帮助您在重新编译时计算正确的偏移量 程序。
将优化设置得足够高,您的一些功能是 可能会在没有警告的情况下消失,因为编译器检测到 代码是“死的” - 您可以通过确保使用 -O0 来缓解这种情况 并引入具有有意义效果的“副作用” 在程序状态上。
如果您使用 stack cookies 进行编译,那么您 可能会导致程序中止 - 所以请确保跳过它们。
如果 printSomething 本身的地址中有任何空字节 您的 strcpy 可能会意外地在地址中间结束。这 坏消息是你几乎肯定会有空字节,但好消息是 消息是,这些字节往往是MSB,而不是LSB,并且 假设您在小端平台上编译它 不太可能成为问题,因为原始的退货地址和 &printSomething 可能共享这些 MSB。只要你复制在 至少 4 个字节的 &printSomething 到溢出缓冲区,你 可能没问题。然而如果发生一些不幸的事件 printSomething 恰好是 256 字节对齐的(又名 LSB 是 0x00),然后 你可能会遇到麻烦。您可以使用调试器检查这一点。
技术上未定义的行为,但这从来没有阻止过任何人——无论如何在实践层面上。优秀的黑客靠将未定义的行为转变为黑客控制的行为而茁壮成长。