标签:
服务器端有个程序在监听端口30000,该程序有一个安全漏洞,通过阅读源码找出漏洞。向该程序提交请求,如果触发漏洞,便会在响应中发回88字节的flag每个参赛者有自己的Token,提交的请求中需要包含Token,每个Token只有四次提交请求的机会BurpSuit + WireShark
用自己的python代理,给服务器发送数据,服务器不响应,用浏览器却可以,使用wireshark抓包比较,也没发现区别(希望有大神告诉我为什么),为了节省时间干脆就用BurpSuit Repeater发包,用WireShark查看收到的数据包内容。。。
程序的流程
一系列初始化 -> 监听端口 -> 接受请求 -> 判断格式 -> 判断token -> 交给rpc函数处理
rpc函数列表
0号 rpc_strcat 1号 rpc_insert2号 rpc_setstr3号 rpc_replace4号 rpc_delete5号 rpc_strcmp6号 rpc_readlog7号 rpc_test看到rpc_readlog、writelog,凭直觉这两个函数有蹊跷(没事提供读写日志功能干嘛- -!),虽然察觉到了,但是发现漏洞的过程还是很艰难(- -!)。
经过漫长曲折的分析,最后发现问题确实出现在rpc_readlog中,rpc_readlog函数的代码如下:
response_t*rpc_readlog(request_t*request){req_t req; memcpy(&req,request->data,sizeof(req_t));if(req.str1.len != strlen(req.str1.string)|| req.str2.len != strlen(req.str2.string)|| req.str1.len !=0|| req.str2.len !=0|| req.pos <0|| req.len ==0|| validkey(&req)== FAIL){char*message ="Wrong Argument.";return create_response(strlen(message), message);}char*buffer;char len = req.len;if(len <0) len =-len;if((buffer =(char*)malloc(len + SAFE_SPACE_LEN))== NULL){char*message ="Malloc Error.";return create_response(strlen(message),message);} memset(buffer,0,len + SAFE_SPACE_LEN);if((readlog(request->token,request->len_token,&req,buffer))<0){ free(buffer);char*message ="Operation Error.";return create_response(strlen(message),message);}response_t*response = create_response(len,buffer); free(buffer);return response;}代码中使用有符号char型变量len存储长度,如果len小于0就取负得到正的len,然后为buffer分配空间,长度为len+ 130(SAFE_SPACE_LEN),问题就出在这里,为什么呢?
在本地gcc编译环境中进行试验,发现当len 等于 -128(0x80) 时,负 len 还等于-128(0x80) ,而-128又是合法的值。
如果直接将len传给malloc,分配空间是会失败的,但是,代码中给len加上了个SAFE_SPACE_LEN,这会导致成功给buffer分配2字节的空间,最终造成了后面的”血案“。
rpc_readlog为buffer分配空间后,调用了readlog函数:
int readlog(char* token,unsignedchar len_token,req_t* req,char* response){int fd;int pos = req->pos;char len = req->len;char filename[512]="/rpcserver/";char*filecontent;int filesize =0;struct stat buf;if(pos <0)return FAIL;if(len <0){ pos = pos + len; len =-len;}assert(SAFE_POSITIVE(len)); memcpy(filename +11,token,len_token); memcpy(filename +11+ len_token,".log",5);if((fd = open(filename,O_RDONLY,0644))<0)return FAIL;if(fstat(fd,&buf)<0){ close(fd);return FAIL;} filesize = buf.st_size;if(pos <0|| pos > filesize || pos + len > filesize ||(filecontent =(char*)malloc(filesize))== NULL ){ close(fd);return FAIL;}if(filesize != read(fd,filecontent,filesize)){ close(fd); free(filecontent);return FAIL;}char l = len;do{ response[l]= filecontent[pos + l]; l--;}while(l >=0); close(fd); free(filecontent);return SUCCESS;}这个函数的功能就是读取log文件中的部分内容,读取的位置和长度由请求中的pos和len指定,最后将读取的内容写到buffer中,我们来分析一下len = -128时,是否可以通过合法性检测并触发漏洞。
首先注意到开始部分有个断言:
assert(SAFE_POSITIVE(len));这个断言咋一看看挺“吓人”的,但实际SAFE_POSITIVE宏的定义是这样的:
#define SAFE_POSITIVE(x)( x = x >0? x : x + SAFE_SPACE_LEN )>0也就是说len>0或者len+ SAFE_SPACE_LEN >0就可以了,换句话说,len=-128是没问题的。再看后面的合法性检查,可以总结出当len = -128时,只要pos > 128就可以了,当然还要求存在log文件且有一定长度的内容。
看来len=-128通过合法性检测是没有问题了,现在直接看最后这个循环:
char l = len;do{ response[l]= filecontent[pos + l]; l--;}while(l >=0);filecontent中存储了log文件中的所有内容,这个循环便是将指定pos和len的内容复制到response中,response就是rpc_readlog中分配了2字节长度的buffer。当 l = -128时,l-- = 127,也就是会给response[-128]以及response[0]->response[127]的内存空间赋值,结果就是导致堆溢出。
上一节详细说明了漏洞的原理,现在总结一下触发漏洞都有那些要求:
根据要求不难看出漏洞触发需要提交两次请求:
漏洞触发要求已经明确,在发送请求来触发漏洞之前还有一件非常重要的工作:分析请求格式。
每个人只有4次调用rpc功能的机会,本菜由于请求格式问题,前两次都没有成功调用rpc,导致后两次到了“不成功,便成仁”的境地(唉,在点发送请求的时候手抖啊)。
根据源码,可以分析出请求格式如下

其中需要注意两点:
首先需要调用rpc_strcat功能,构造请求如下

rpc_strcat功能执行成功后,服务器会返回拼接的字符串,同时由于设置了logRequest为1,会在服务器上生成相关log文件。
下面是调用rpc_readlog功能时的请求,注意请求中 pos = 0x00000082,len=0x80。

请求发送后,服务器返回flag

标签:
原文地址:http://www.cnblogs.com/Wrong-Side/p/4380445.html