GOAhead CVE-2017-17562深入分析
GOAhead是一个嵌入式的webserver,前几周被爆出一个远程命令执行的漏洞,受漏洞影响版本:2.5-3.6.4。本文进行该漏洞的深入分析,漏洞调试环境:Ubuntu 16.04 64bit,GOAhead版本3.6.4,下载地址:https://github.com/embedthis/goahead/releases。
GOAhead安装和cgi扩展启用参考:http://blog.csdn.net/yangguihao/article/details/49820765。
GOAhead要启用CGI时,记的是修改要修改/etc/goahead中的route.txt。
dir是cgi的存放目录,其目录下存放一个cgi_test,里面内容随便写,然后gcc编译即可。
输入cgi的url:http://172.20.94.98:8888/cgi-bin/cgi_test
LD_PRELOAD是Linux系统的一个环境变量,用于动态库的加载执行,动态库加载的优先级最高,一般情况下,其加载顺序为:LD_PRELOAD>LD_LIBRARY>/etc/ld.so.cache >/lib>/usr/lib.它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态库,甚至覆盖正常的函数库。
LA_PRELOAD替换前:
LA_PRELOAD替换后:
演示程序:
a.主程序(login.c)
#include <stdio.h>
#include <string.h>
#include "myverify.h"
void main(int argc, char const *argv[])
{
char pwd[] = "123456";
if(argc < 2)
{
printf("usage: %s <your password>\n", argv[0]);
return;
}
if(!verify(pwd, argv[1]))
{
printf("login success\n");
}
else
{
printf("login fail\n");
}
}
b.调用库(myverify.h和myverify.c)
#include <stdio.h>
int verify(const char *s1, const char *s2);
#include <stdio.h>
#include <string.h>
#include "myverify.h"
int verify(const char *s1, const char *s2)
{
return strcmp(s1, s2);
}
c.编译运行效果如下:
相关命令解释如下:
gcc myverify.c -fPIC -shared -o libmyverify.so #编译动态链接库
gcc login.c -L. -lmyverify -o mylogin #编译主程序
export LD_LIBRARY_PATH=/home/daizy/workplace/CDemo/LinuxAPI/ #指定动态链接库所在目录位置
ldd myverifypasswd #显示、确认依赖关系
d.替换代码如下:(myhack.c)
#include <stdio.h>
#include <string.h>
int verify(const char *s1, const char *s2)
{
printf("hack function invoked.\n");
return 0;
}
e.编译设置环境变量LD_PRELOAD,运行替换代码效果如下:
export LD_PRELOAD="./myhack.so" #设置LD_PRELOAD环境变量,库中的同名函数在程序运行时优先调用
ps:替换结束,要还原函数调用关系,用命令unset LD_PRELOAD 解除
以GOAhead 3.6.4版本为例进行漏洞分析:
当用户post提交数据时,goahead最终会调用http.c中readEvent(Webs *wp)进行数据读取的处理,其中结构体Webs后续会常看到,此处先给出该结构体大致定义,在goahead.h中可以查找到:
typedef struct Webs {
WebsBuf rxbuf; /**< Raw receive buffer */
WebsBuf input; /**< Receive buffer after de-chunking */
WebsBuf output; /**< Transmit buffer after chunking */
WebsBuf chunkbuf; /**< Pre-chunking data buffer */
WebsBuf *txbuf;
WebsHash vars; /**< CGI standard variables */
int rxChunkState; /**< Rx chunk encoding state */
ssize rxChunkSize; /**< Rx chunk size */
char *rxEndp; /**< Pointer to end of raw data in input beyond endp */
ssize lastRead; /**< Number of bytes last read from the socket */
ssize txChunkPrefixLen; /**< Length of prefix */
ssize txChunkLen; /**< Length of the chunk */
int txChunkState; /**< Transmit chunk state */
char *filename; /**< Document path name */
char *path; /**< Path name without query. This is decoded. */
int sid; /**< Socket id (handler) */
int routeCount; /**< Route count limiter */
ssize rxLen; /**< Rx content length */
ssize rxRemaining; /**< Remaining content to read from client */
ssize txLen; /**< Tx content length header value */
int wid; /**< Index into webs */
#if ME_GOAHEAD_CGI
char *cgiStdin; /**< Filename for CGI program input */
int cgifd; /**< File handle for CGI program input */
#endif
struct WebsRoute *route; /**< Request route */
struct WebsUser *user; /**< User auth record */
WebsWriteProc writeData; /**< Handler write I/O event callback. Used by fileHandler */
} Webs;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)