c - 如何使用缓冲区溢出攻击找到要利用的程序的漏洞
问题描述
作为一个实验室的任务,我想首先找到以下代码的漏洞,然后作为示例时间服务器运行,然后使用缓冲区溢出对其进行攻击。但第一个问题是不知道从哪里开始。我知道在那个 C 程序中有些函数可能是有害的(例如“strftime”、“memcoy”或“strcpy”),但我无法选择最适合开始使用的函数。
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <time.h>
#define CANBUFSIZE 106
#define MSGBUFSIZE 256
#define TIMEBUFSIZE 128
char msgbuf[MSGBUFSIZE];
char canarybuf[CANBUFSIZE];
void get_time(char* format, char* retstr, unsigned received)
{
// memory for our local copy of the timestring
char timebuf[TIMEBUFSIZE];
time_t curtime;
// if the format string esceeds our local buffer ...
if(strlen(format) > TIMEBUFSIZE)
{
strcpy(retstr,"Process Error.");
return;
}
// otherwise create a local working copy
memcpy(timebuf,format,received);
// Get the current time.
curtime = time (NULL);
// Convert it to local time representation.
// and convert the format string to the real timestring
struct tm *loctime = localtime (&curtime);
strftime(retstr,TIMEBUFSIZE,timebuf,loctime);
return;
}
int main(int argc, char** argv)
{
int port; // the portnumber of our service
struct in_addr bind_addr; // bind address of the server
int sd; // the socketdescriptor
struct sockaddr_in addr; // address of our service
struct sockaddr_in addr_from; //address of the client
int addrlen = sizeof(addr_from);
int pid; // our process id
int sid; // our session id
unsigned received; // number of bytes received from network
// resolve command line arguments
if(argc != 3)
{
printf("Usage: timeservice <bind address> <portnum>\n");
return 1;
}
if (inet_aton(argv[1], &bind_addr) == 0)
{
fprintf(stderr, "Invalid bind address\n");
exit(EXIT_FAILURE);
}
port = atoi(argv[2]);
if ((port < 1024) || (port > 65535))
{
printf("Portrange has to be between 1024 and 65535.\n");
exit(EXIT_FAILURE);
}
// forking to background
pid = fork();
if(pid < 0)
{
printf("fork() failed\n");
exit(EXIT_FAILURE);
}
// we are parent
else if(pid > 0)
{
return 0;
}
/*
* we are the child process
* because of the termination of our parent, we need a new session id,
* else we are zombie
*/
sid = setsid();
if (sid < 0) {
return 1;
}
/*
* since we are a system service we have to close all standard file
* descriptors
*/
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// create an udp socket
if((sd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
{
return 1;
}
// clear the memory of our addr struct
memset(&addr,0,sizeof(addr));
// Protocol Family = IPv4
addr.sin_family = PF_INET;
// Listen on bindAddr and bindPort only
addr.sin_addr.s_addr = bind_addr.s_addr;
addr.sin_port = htons(port);
// bind to the udp socket
if(bind(sd,(struct sockaddr*)&addr,sizeof(addr)) != 0)
{
return 1;
}
for(;;)
{
// prepare memory
memset(&msgbuf, 0, sizeof(msgbuf));
received = recvfrom(sd,msgbuf,MSGBUFSIZE,MSG_WAITALL,
(struct sockaddr*)&addr_from,(socklen_t*) &addrlen);
// fork a new child
pid = fork();
// we are parent
if (pid > 0)
{
// wait for the child to finish
waitpid(pid,NULL,0);
}
else
{
/*
* we are inside the child process
*/
// reserve some memory for our response
char * returnstr = (char*) malloc(TIMEBUFSIZE);
// analyse the client request and format the time string
get_time(msgbuf, returnstr, received);
// send our response to the client
sendto(sd,returnstr,strlen(returnstr)+1,MSG_DONTWAIT,
(struct sockaddr *) &addr_from, addrlen);
free(returnstr);
return EXIT_SUCCESS;
}
}
close(sd);
return 0;
}
我使用 gcc 编译文件并使用 ./timeserver 127.0.0.1 2222 运行本地服务器,然后使用 nc -u 127.0.0.1 2222 连接到该文件。然后我现在可以向服务器输入一些格式字符串并取回一些结果。例如,如果我在命令行中使用 %d,它将以特殊格式显示日期/时间。我知道这是我应该强制使用一些字符串并使程序崩溃的地方,但我找不到确切的字符串。
解决方案
的返回值recvfrom
没有被检查,这是一个错误。如果 recvfrom 出错,则返回值为 -1。由于 的类型received
是无符号的,这是第二个错误,这似乎是一个很大的正值。memcpy 调用将导致程序失败。
推荐阅读
- c# - 如何使用 C# 在 Unity 中使用 JsonUtility 从给定的 JSON 格式获取数据?
- javascript - 如何将多个 Ajax Post 调用异步到同一个 URL
- django - 如何根据登录的用户来匹配页面上的不同内容?
- php - 带有子选择的 Doctrine 查询构建器内部联接
- symfony4 - 在 API 平台中保存相关对象
- asp.net-core - .NET Core 操作筛选器不是属性类
- c# - 有没有办法快速检查,字符串与正则表达式匹配的百分比是多少?
- laravel - Laravel google oauth 2回调返回403禁止
- solver - SimCity (BuildIt) 经济的子集可以用 Minizinc 表示吗?
- python - 机器人框架:使用关闭所有浏览器时套件拆解失败