GOAhead CVE-2017-17562深入分析
GOAhead是一个嵌入式的webserver,前几周被爆出一个远程命令执行的漏洞,受漏洞影响版本:2.5-3.6.4。本文进行该漏洞的深入分析,漏洞调试环境:Ubuntu 16.04 64bit,GOAhead版本3.6.4,下载地址:78fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6W2L8h3u0W2k6s2c8Z5K9i4y4Q4x3V1k6Y4L8$3q4Z5k6h3q4V1i4K6u0r3M7X3g2D9k6h3q4K6k6i4y4Q4c8e0y4Q4z5o6m8Q4z5o6t1`.
GOAhead安装和cgi扩展启用参考:048K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0D9L8$3N6Q4x3X3g2U0M7$3c8F1i4K6u0W2L8X3g2@1i4K6u0r3P5h3q4F1k6$3N6#2K9h3S2S2L8#2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3y4o6V1^5x3U0l9%4y4U0g2Q4c8e0y4Q4z5o6m8Q4z5o6t1`.
GOAhead要启用CGI时,记的是修改要修改/etc/goahead中的route.txt。

dir是cgi的存放目录,其目录下存放一个cgi_test,里面内容随便写,然后gcc编译即可。


输入cgi的url:9f5K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5%4x3W2)9J5k6e0t1H3i4K6u0W2z5e0c8Q4x3X3f1&6z5q4)9K6b7e0R3^5z5o6S2Q4x3V1k6U0k6$3W2Q4x3X3c8T1K9h3&6Q4x3V1k6U0k6$3W2Q4y4h3k6@1k6i4y4@1
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;
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课