Ghidra 从 XXE 到 RCE

作者:腾讯安全玄武实验室 tomato, salt

0x00 背景

Ghidra是 NSA 发布的一款反汇编工具,它的发布引起了安全研究人员的极大兴趣。
有研究人员发现Ghidra在加载工程时会存在XXE,基于笔者之前对XXE漏洞利用研究发现,攻击者可以利用Java中的特性以及Windows操作系统中NTLM认证协议的缺陷的组合来完成RCE。

0x01 技术细节

Java在使用内置类 sun.net.www.protocol.http.HttpURLConnection 发送HTTP请求遇到状态码为401的HTTP返回头时,会判断该页面要求使用哪种认证方式,若采用的NTLM认证则会自动使用当前用户凭据进行认证。
其根本原因在于Windows下的Java默认启用了透明NTLM认证,并且将所有由外部传入的URL地址都认为是可信的。如下面代码段所示

sun.net.www.protocol.http.AuthScheme#NTLM

if (tryTransparentNTLMServer) {
    tryTransparentNTLMServer =
            NTLMAuthenticationProxy.supportsTransparentAuth;
    /* If the platform supports transparent authentication
     * then check if we are in a secure environment
     * whether, or not, we should try transparent authentication.*/
    if (tryTransparentNTLMServer) {
        tryTransparentNTLMServer =
                NTLMAuthenticationProxy.isTrustedSite(url);
    }
}

再跟入NTLMAuthenticationProxy.isTrustedSite方法

public static boolean isTrustedSite(URL url) {
    try {
        return (Boolean)isTrustedSite.invoke(null, url);
    } catch (ReflectiveOperationException roe) {
        finest(roe);
    }

    return false;
}

通过反射调用了sun.net.www.protocol.http.ntlm.NTLMAuthentication中的isTrustedSite方法,在此方法中将所有外部传入的URL都判定为可信的。

攻击者通过搭建基于NTLM认证的HTTP Server即可获取到当前用户的Net-NTLM Hash。

我们再来看NTLM认证协议的缺陷。NTLM认证协议中存在一种很古老的攻击的技术,被称作为NTLM Relay攻击。此攻击的原理网上已经有很多文章进行说明,在此不再赘述。
但在此次漏洞利用方式中我们使用的凭据反射攻击,即为攻击者将受害者的Net-NTLM Hash再次Relay给受害者,达到以彼之道还施彼身的效果。

下面来看看这个过程的具体实现,攻击者首先搭建基于NTLM认证的恶意HTTP Server,然后通过XXE/SSRF等漏洞使受害者向恶意的HTTP Server进行NTLM认证。

值得注意的是,NTLM认证分为两个版本NTLMv1和NTLMv2,在进行NTLMv1类型认证时攻击将获取到的Net-NTLM Hash直接Relay给受害者的SMB服务即可,但是在使用NTLMv2类型认证时,攻击者在Relay时需要将NTLM认证中Type 2 Message的Negotiate Flags进行修改,将Negotiate Always Sign与Negotiate 0x00004000 两个标志位从设置改为不设置,这其中具体代表的含义为让此次认证被认作在网络上(Relay给本机会被当做是一次本地认证)进行以及将认证中的签名进行去除。

为完成该攻击过程,笔者已经编写好脚本

0x03 复现步骤

受害者环境 Oracle JDK 8u161、Win10、Administrator账户

攻击者环境 Ubuntu16.04 IP为192.168.130.136

首先在局域网内另一台机器上运行前面提到的脚本

python ultrarelay.py -ip 192.168.130.136 -smb2support

脚本将会在80端口开启HTTP服务。然后回到Win10中新建一个Ghidra工程,修改工程中的project.prp,插入XXE攻击代码,如下图所示

再次使用Ghidra打开此恶意工程,攻击者就能获取到受害者机器的NTLM Hash,也可通过脚本中的参数在受害者机器上执行任意命令。

0x04 防御措施

1.开启Windows防火墙,禁止外部请求访问SMB服务

2.若要提供SMB服务 则建议开启SMB Sign

3.升级JDK至最新版本

0x05 参考资料

https://twitter.com/sghctoma/status/1103392091009413120

https://conference.hitb.org/hitbsecconf2018dxb/materials/D2T2%20-%20NTLM%20Relay%20Is%20Dead%20Long%20Live%20NTLM%20Relay%20-%20Jianing%20Wang%20and%20Junyu%20Zhou.pdf

全网筛查 WinRAR 代码执行漏洞 (CVE-2018-20250)

作者:lywang, dannywei

0x00 背景

WinRAR 作为最流行的解压缩软件,支持多种压缩格式的压缩和解压缩功能。今天,Check Point公司的安全研究员 Nadav Grossman 公开了他在 WinRAR 中发现的一系列漏洞。其中以 ACE 解压缩模块的远程代码执行漏洞(CVE-2018-20250)最具危害力。
WinRAR 为支持 ACE 压缩文件的解压缩功能,集成了一个具有 19 年历史的动态共享库 unacev2.dll。 而此共享库自 2006 年以来再未更新过,也未开启任何漏洞利用缓解技术。Nadav Grossman 在 unacev2.dll 中发现了一个目录穿越漏洞,成功利用此漏洞可导致远程代码执行或 Net-NTLM hash 泄露。

0x01 漏洞描述

ACE 文件的解压模块 unacev2.dll 对解压缩路径进行验证时,未能正确过滤压缩文件中的“相对路径”,导致攻击者结合一些技巧可以绕过安全检查,使压缩文件中恶意构造的“相对路径”被直接用作了解压路径使用。从而可以将恶意代码静默释放到系统启动目录中,最终实现远程代码执行或 Net-NTLM hash 泄露。

0x02 漏洞成因

unacev2.dll 模块在解压 ACE 文件时,将对解压缩路径进行验证。它从压缩文件中提取待解压文件的相对路径 file_relative_path,使用 GetDevicePathLen(file_relative_path) 对其进行校验,根据返回结果进行最终解压路径的拼接。如下图所示:

(图片来源:https://research.checkpoint.com/extracting-code-execution-from-winrar/)

当 GetDevicePathLen(file_relative_path) 返回 0 时,将使用 WinRAR 提供的解压路径与压缩文件中的相对路径拼接,得到最终的解压路径:

sprintf(final_file_path, "%s%s", destination_folder, file_relative_path);

而当 GetDevicePathLen(file_relative_path) 返回非 0 时,仅使用压缩文件中的“相对路径”作为最终的解压路径:

sprintf(final_file_path, "%s%s", "", file_relative_path);

因此,若攻击者能够构造恶意的相对路径,在绕过 WinRAR 回调函数 StateCallbackProc() ,unacev2.dll!CleanPath() 等一系列路径检测和过滤函数的前提下,使 unacev2.dll!GetDevicePathLen(file_relative_path) 返回非0值,便可以使得使用恶意构造的相对路径作为最终解压路径,将恶意文件解压至指定目录中。

最终,Nadav Grossman 构造了两种攻击路径:

编号 恶意的相对路径 最终的解压路径
1 C:\C:\some_folder\some_file.ext C:\some_folder\some_file.ext
2 C:\\10.10.10.10\smb_folder_name\some_folder\some_file.ext \10.10.10.10\smb_folder_name\some_folder\some_file.ext

攻击路径 1 的危害:攻击者可以使用漏洞,将恶意文件静默释放至可能造成危害的路径中实现攻击。
攻击路径 2 的危害: 攻击者可以获取受害者的Net-NTLM hash,从而使用NTLM Relay的方式攻击受害者。

值得一提的是,由于 WinRAR 运行在普通用户权限下,使得攻击者无法将恶意文件静默释放至路径已知的系统启动目录(”C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup”)。而释放至用户启动目录(”C:\Users\<user name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup”)需要提前预知受害者的登陆用户名或者进行暴力猜测。
好在大多数此类攻击场景均是受害者将恶意构造的压缩文件下载至桌面(C:\Users\<user name>\Desktop)或者下载目录(C:\Users\<user name>\Downloads),而当压缩文件通过双击解压或右键解压缩时,当前的WinRAR的工作路径与压缩文件一致。这使得攻击者无需猜测受害者用户名,可通过目录穿越的方式将恶意文件释放至用户启动目录,待受害者系统启动时实现任意代码执行。在此前提下, Nadav Grossman 构造了如下的相对路径,使得远程代码执行攻击得以成功:

"C:../AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\some_file.exe"

0x03 影响范围

unacev2.dll 作为一个第三方共享库,也被其它一些支持 ACE 文件格式解压的软件所使用,这些软件也同样受到该漏洞的影响。
利用玄武实验室自研的“阿图因”系统,我们对已收录的全网 PC 软件进行了扫描,统计了 unacev2.dll 的使用情况,其版本分布情况如下图所示:

通过“阿图因”系统,我们还能够对使用了该共享库的软件进行反向溯源,目前扫描到了受影响的有 24 款国外软件,15 款国产软件。
多数受影响的软件都可以被归类为工具软件。其中至少有9款压缩软件,以及8款文件浏览器。还有其它许多软件将 unacev2.dll 作为 WinRAR 的一部分放在了自己的软件包中,作为解压模块使用。

0x04 修复建议

目前,WinRAR 已经在 5.70 Beta 1 版本中修复了这个问题。由于开发 ACE 解压模块的公司已于 2017 年 8 月关闭,而且 unacev2.dll 共享库并没有公开源码,导致漏洞无法被正确修复。因此 WinRAR 的修复方案是直接将 unacev2.dll 模块移除,并决定不再支持 ACE 文件格式的解压。

另外,360压缩在最新版本中也已经修复了这个问题,修复方案同样是移除 unacev2.dll 模块。
对于其它受影响软件的用户,我们建议您关注相关软件的修复更新情况,及时更新版本。在软件开发商主动修复之前,可以通过手动删除安装目录下的 unacev2.dll 模块来应急修复。

0x05 参考资料

[1] Extracting a 19 Year Old Code Execution from WinRAR https://research.checkpoint.com/extracting-code-execution-from-winrar/

[2] ACE (compressed file format) https://en.wikipedia.org/wiki/ACE_(compressed_file_format)

从一起“盗币”事件看以太坊存储 hash 碰撞问题

Author : Kai Song(exp-sky)、hearmen、salt、sekaiwu of Tencent Security Xuanwu Lab

“盗币”

十一月六日,我们观察到以太坊上出现了这样一份合约,经调查发现是某区块链安全厂商发布的一份让大家来“盗币”的合约。

pragma solidity ^0.4.21;
contract DVPgame {
    ERC20 public token;
    uint256[] map;
    using SafeERC20 for ERC20;
    using SafeMath for uint256;
    constructor(address addr) payable{
        token = ERC20(addr);
    }
    function (){
        if(map.length>=uint256(msg.sender)){
            require(map[uint256(msg.sender)]!=1);
        }
        if(token.balanceOf(this)==0){
            //airdrop is over
            selfdestruct(msg.sender);
        }else{
            token.safeTransfer(msg.sender,100);

            if (map.length <= uint256(msg.sender)) {
                map.length = uint256(msg.sender) + 1;
            }
            map[uint256(msg.sender)] = 1;  

        }
    }
    //Guess the value(param:x) of the keccak256 value modulo 10000 of the future block (param:blockNum)
    function guess(uint256 x,uint256 blockNum) public payable {
        require(msg.value == 0.001 ether || token.allowance(msg.sender,address(this))>=1*(10**18));
        require(blockNum>block.number);
        if(token.allowance(msg.sender,address(this))>0){
            token.safeTransferFrom(msg.sender,address(this),1*(10**18));
        }
        if (map.length <= uint256(msg.sender)+x) {
            map.length = uint256(msg.sender)+x + 1;
        }

        map[uint256(msg.sender)+x] = blockNum;
    }
    //Run a lottery
    function lottery(uint256 x) public {
        require(map[uint256(msg.sender)+x]!=0);
        require(block.number > map[uint256(msg.sender)+x]);
        require(block.blockhash(map[uint256(msg.sender)+x])!=0);
        uint256 answer = uint256(keccak256(block.blockhash(map[uint256(msg.sender)+x])))%10000;
        if (x == answer) {
            token.safeTransfer(msg.sender,token.balanceOf(address(this)));
            selfdestruct(msg.sender);
        }
    }
}

经过观察之后,我们在这个合约中,发现了我们之前研究的一个 EVM 存储的安全问题,即 EVM 存储中的 hash 碰撞问题。

继续阅读“从一起“盗币”事件看以太坊存储 hash 碰撞问题”

Return Flow Guard

腾讯玄武实验室 DannyWei, lywang, FlowerCode

这是一份初步文档,当我们有新发现和更正时会进行更新。

我们分析了微软在2016年10月7日发布的Windows 10 Redstone 2 14942中加入的新安全机制Return Flow Guard。

1 保护原理

微软从Windows 8.1 Update 3之后加入了Control Flow Guard,用于阻止对间接跳转函数指针的篡改。CFG通过在每个间接跳转前检查函数指针合法性来实现,但是这种方式并不能阻止篡改栈上的返回地址或者Return Oriented Programming。

本次加入的新安全机制RFG,会在每个函数头部将返回地址保存到fs:[rsp](Thread Control Stack),并在函数返回前将其与栈上返回地址进行比较,从而有效阻止了这些攻击方式。

开启RFG需要操作系统和编译器的双重支持,在编译阶段,编译器会以nop指令的形式在目标函数中预留出相应的指令空间。当目标可执行文件在支持并开启RFG的系统上运行时,预留的指令空间会在加载阶段被替换为RFG指令,最终实现对返回地址的检测。当在不支持RFG的操作系统上运行时,这些nop指令则不会影响程序的执行流程。

RFG与GS最大的区别是,攻击者可以通过信息泄漏、暴力猜测等方式获取栈cookie从而绕过GS保护,而RFG是将当前的函数返回地址写入了攻击者不可控的Thread Control Stack,从而进一步提高了攻击难度。
继续阅读“Return Flow Guard”