【发布时间】:2015-06-01 21:08:31
【问题描述】:
我正在尝试在 Linux 上用 C/C++ 实现 Heartbleed Bug 的简单实现(在 vmplayer 上使用 ElementaryOS)。根据我对 heartbleed 错误的理解,它涉及客户端向服务器发送心跳请求,为包含的有效负载指定比有效负载的实际大小更大的大小,这导致服务器包含将布局的内存中的内容在本地负载缓冲区之后,在响应中。
到目前为止,我拥有的是一个客户端/服务器应用程序。客户端连接到服务器并发送一条敏感信息,在本例中为密码。接下来,客户端向服务器发送心跳请求,指定错误的有效负载大小。我这样声明我的局部变量:
char password[30];// = new char[30]; //Some sensitve data, that will be accessed using the Heartbleed Bug
char temp[15];// = new char[15];
char payload[45];// = new char[45];
我像这样从心跳请求中检索内容:
int payloadSize = atoi(strtok(buffer, " "));
temp = strtok(NULL, "\n");
在心跳请求中,payload为“payload”,大小为45。然后我像这样调用memcpy():
memcpy(payload, temp, payloadSize /* 45 in this case */);
我希望有效负载变量包含值“有效负载”,然后是密码变量中的内容。但是有效载荷仅包含值“有效载荷”。
cout<<payload<<endl; //prints payload
谁能指出我做错了什么?
所有代码:
int main()
{
ofstream log("ServerLog.txt");
int listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddress, clientAddress;
socklen_t clientLen;
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = 54321;
if(bind(listeningSocket, (sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
{
cout<<strerror(errno)<<endl;
}
else
{
cout<<"Socket bound to port 12345"<<endl;
if(listen(listeningSocket, 5) < 0)
{
cout<<strerror(errno)<<endl;
}
else
{
log<<"Listening for connections now..."<<endl;
int commSocket = accept(listeningSocket, (sockaddr *) &clientAddress, &clientLen);
log<<"Now connected to a client..."<<endl;
int N = 0;
char buffer[100];// = new char[100];
char password[30];// = new char[30]; //Some sensitve data, that will be accessed using the Heartbleed Bug
char *temp = new char[15];
char payload[45];// = new char[45];
N = recv(commSocket, password, 100, 0); //Receive sensitive data, in this case, a password
if(N == 0) //Check for remote socket close
{
cout<<"The remote connection has been closed."<<endl;
}
else if(N < 0) //In case there is an error
{
cout<<strerror(errno)<<endl;
}
else //All good, move on
{
//cout<<N<<" "<<password<<endl;
log<<"Password received from client: "<<password<<" of length: "<<N<<endl;
N = recv(commSocket, buffer, 100, 0); //recv heartbeat request
if(N == 0) //Check for remote socket close
{
cout<<"The remote connection has been closed."<<endl;
}
else if(N < 0) //In case there is an error
{
cout<<strerror(errno)<<endl;
}
else
{
log<<"Heartbeat request received from client: "<<buffer<<endl;
int payloadSize = atoi(strtok(buffer, " "));
temp = strtok(NULL, "\n");
memcpy(payload, temp, 45);
if(N < 0)
{
cout<<strerror(errno)<<endl;
}
}
}
}
}
return 0;
}
【问题讨论】:
-
你如何检查
memcpy()之后的payload?作为字符串查看/打印(这对您没有帮助,因为"payload"末尾的\0将结束打印)?或者转储所有 45 个字节,这可能取决于您的堆栈安排? -
您是否打算让 memcpy 也接收
password? -
不能保证
password在内存中直接位于temp之后。在真正的 Heartbleed 的情况下,情况就是这样,但也许你的程序有不同的内存布局。 -
memcpy() 没有任何问题——它完全按照您的指示行事。
-
Paul Roub:使用简单的 cout。实际上我确实想到了这个,导致终止的空字符,所以我写了一个 for 循环来一个一个地打印出所有 45 个字符。它似乎没有帮助。 (得到相同的结果) Matt McNabb:是的 deviantfan:根据我对局部变量在内存中的布局方式的理解,变量按它们出现在堆栈上的顺序被推送,这应该保证密码在 temp 之后。
标签: c++ linux buffer-overflow heartbleed-bug network-security