Samba远程代码执行-分析(CVE-2017-7494)

经历了前一阵windows的EternalBlue之后,某天看见了360的 samba高危预警,这个号称linux端的EternalBlue(EternalRed),于是便研究了一波

概述(抄)

Samba是在Linux和UNIX系统上实现SMB协议的一个软件。2017年5月24日Samba发布了4.6.4版本,中间修复了一个严重的远程代码执行漏洞,漏洞编号CVE-2017-7494,漏洞影响了Samba 3.5.0 之后到4.6.4/4.5.10/4.4.14中间的所有版本。

原因分析

注:个人认为对于已经打过patch的代码,根据他的git diff可以很方便也很简单地定位到漏洞代码

首先从samba github上打的patch入手来看的话

github-patch

patch代码就只添加了一行过滤,

所以可以确定成因在于is_known_pipename函数中对pipename路径符号的过滤不全导致的。

那么继续向下分析其将pipename传入smb_probe_module

bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
    //...
    status = smb_probe_module("rpc", pipename);
    if (!NT_STATUS_IS_OK(status)) {
        DEBUG(10, ("is_known_pipename: %s unknown\n", pipename));
        return false;
    }
    //...
}

smb_probe_module则将pipename传入do_smb_load_module

NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
    return do_smb_load_module(subsystem, module, true);
}

再继续深入do_smb_load_module,其在加载模块时对module_name进行了一次判断(模块路径第一个字符是否为/
若为false,则直接调用load_module函数加载模块,若成功加载将返回一个init函数指针,并执行它

static NTSTATUS do_smb_load_module(const char *subsystem,
                   const char *module_name, bool is_probe)
{
    //...
    if (subsystem && module_name[0] != '/') {
        full_path = talloc_asprintf(ctx,
                        "%s/%s.%s",
                        modules_path(ctx, subsystem),
                        module_name,
                        shlib_ext());
        if (!full_path) {
            TALLOC_FREE(ctx);
            return NT_STATUS_NO_MEMORY;
        }

        DEBUG(5, ("%s module '%s': Trying to load from %s\n",
              is_probe ? "Probing": "Loading", module_name, full_path));
        init = load_module(full_path, is_probe, &handle);
    } else {
        init = load_module(module_name, is_probe, &handle);
    }
    //...
    if (!init) {
        TALLOC_FREE(ctx);
        return NT_STATUS_UNSUCCESSFUL;
    }
    
    DEBUG(2, ("Module '%s' loaded\n", module_name));

    status = init(NULL); //RCE POINT!!!
}

那么load_module究竟又做了什么呢?它返回的init函数指针又是什么?
它直接打开path,若成功加载则调用dlsym函数用于加载该模块中的samba_init_module

init_module_fn load_module(const char *path, bool is_probe, void **handle_out)
{
    //...
    
    handle = dlopen(path, RTLD_NOW);
    
    //...
    
    if (handle == NULL) {
        //...
    }
    
    init_fn = (init_module_fn)dlsym(handle, SAMBA_INIT_MODULE);
    
    //...
}

//...

#define SAMBA_INIT_MODULE "samba_init_module"

至此,整个漏洞成因也就清晰了,is_known_pipename函数由于路径符号过滤不严谨,导致攻击者可以通过上传恶意so文件,并且猜测路径导致任意代码执行。

攻击过程

条件:攻击者拥有上传文件权限

  • 首先攻击者上传含有恶意代码的so文件至samba服务器
  • 猜测绝对路径,通过构造以/开头的路径名(eg. /home/samba/attacker.so)发送到服务端,使其返回该文件FID
  • 请求该FID便可调用so文件中的samba_init_module,实现任意代码执行。

POC

在自己搭建的环境中,没利用成功,期末考后继续尝试

转载于:https://www.cnblogs.com/tr3e/p/7136062.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值