• 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
    ", 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
    ",
    			  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
    ", 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

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

  • 相关阅读:
    ASP.NET面试题2
    [转]深入.NET DataTable
    C#操作Excel (转)
    XML操作大全
    j2sdk 好用了
    我对“重构(refector)”的看法
    成功执行
    java属性类(Properties类)
    Sharpdevelop下载
    POJ 1753 Flip Game(翻转棋盘+枚举+dfs)
  • 原文地址:https://www.cnblogs.com/tr3e/p/7136062.html
Copyright © 2020-2023  润新知