Challenge description

The challenge was called Revolutional Secure Angou. A zip file (revolutional-secure-angou-de97106aa248a41a40fdd001fc5f7b4b4f28a39eb6bcabf8401b108b7a8961c5) was given to us. Inside we could find three file: an

RSA public key publickey.pem (PEM formatted), the encrypted flag
flag.encrypted  and the Ruby script called generator.rb used to
generate both the public key and the ciphertext. Our goal is obvious: decrypt
the file flag.encrypted .

Read More →

La session Securimag de ce soir sera axée sur le RF433MHZ avec comme base pour les manips les challenges hardware du CTF de GreHack 2017.

Une introduction au SDR par l’écoute d’une télécommande et le rejeu de celle-ci avec un hardware spécifique (Arduino + chip RF).

En pièce jointe, le write-up qui avait été joué la semaine suivante et qui montre les outils qui seront utilisés :

PrezWriteupHardwareGH17-compressed

Pièces jointes

The Insomni’Hack Teaser 2018 took place last weekend and with Securimag, we finished 21st among 433 participating teams. With my friend depierre (who says he wants to do more exploit/reverse but always solely look at the web challenges… :D) we looked at FileVault. It was a tricky challenge and I thought that it deserved a writeup.

The challenge consisted in a simple web page where we could upload files to the server.

Fiddling around, we see that the information about our virtual vault is stored client-side, in a PHP object, serialized. With access to the source (every good web challenge should provide its source IMHO), we understand that the serialized object is HMACed, preventing us from tampering with it.

Going through the source, there are multiple restrictions. First, the serialized object is secured with a HMAC and there is no way to forge our own valid signature. Secondly, a ‘.htaccess’ file is created in our sandbox to disable PHP execution. As such, even though we can upload PHP files to our sandbox, it will never be executed.

There are a few elements in the source code that caught our attention. First, the call to str_replace, which seems to attempt to prevent path traversal, can easily be bypassed using ‘…/’. But even then, since the content of the file is never read by the application, we could not actually exploit the path traversal (cf. s_serialize function above)
Second, the application resets twice our cookie when we want to clear our vault, and this doesn’t make sense to me even after solving the challenge.

Third, when calling open, the application will use the name of the object specified in the serialized object and call its open method. While this could be explained by trying to be flexible and support future classes, it did not make sense to call open with two attributes of the class, instead of two actual parameters, which hinted us towards exploiting the s_unserialize function.

Then we realized that the call to str_replace was done **after** the object was serialized. Why is that a problem? Well, str_replace would be reducing the size of our string if it contained ‘../’ but it would not update the information of the PHP serialized object it just modified.

Here is a simple VaultFile being serialized. You can quickly see that PHP serialization is mostly of the form TYPE:LENGTH:VALUE.

Let’s now create a VaultFile that contains a series of ‘../’ in its fakename.

After str_replace has been called, the serialized object now contains:

As we can see, our string object is now of size 24 but the information still says 31, meaning that unserialize will attempt to read a string of 31 characters, although the string is in fact shorter, and consume the next serialized object. With the example above, the unserialization fails:

So, how can we exploit this issue? Well, we can manipulate the serialized object so that our fakename, when being unserialized, will consume part of the original realname object placed after it.

In addition, we can inject a string containing our crafted serialized PHP object in the extension of our file, since it is kept by the application and appended to the realname. All in all, we could trick unserialize to consider that string as the actual serialized object to unserialize!

One thing we couldn’t understand at first was how we could « comment out » the trailing part of the original serialized object. Then I realized that simply closing the original array (by injecting ‘”;}})’) would stop unserialized from parsing the trailing part.

So let’s assume for a second that we can indeed trick unserialize to unserialize arbitrary objects. What then? There is no class with magic methods (e.g. __construct) that we can leverage, which greatly reduces our playground. However, that call to open we mentioned earlier could be very useful. It provides us with the following property: call the open method of an arbitrary class (declared in the application or in PHP obviously) with 2 parameters that we control.

While we couldn’t find a way to actually read arbitrary files, we found ZipArchive that had a matching open method. The first parameter is the file to open, while the second parameter is the mode. By using ZipArchive::OVERWRITE (8), we could override the .htaccess file with nothing, therefore removing the restriction preventing us from executing PHP code!

I came up with the following code to generate our payload:

We used the original upload, s_serialize and s_unserialize functions to make sure that everything would match what’s being executed on the server. It gave us the following output:

The first array is the legitimate array of files we plan to upload. The second one is the result of our injected PHP object, after the function s_unserialized was called.

Because our injected PHP object would be in the extension of the file, we cannot have any ‘.’ or PHP will only keep whatever is after the last dot as the extension. But we can get around that restriction by calling changename after injection our PHP object and renaming our ZipArchive fakename to .htaccess.

Due to the fact ‘.htaccess’ is created each time we access the PHP page, we first had to upload our go-to PHP shell (the most advanced you have ever seen):

And retrieve its path:

Then we did our dance with the PHP serialization vulnerability and called open, which returned 1, meaning that ZipArchive::open was indeed successful!

Flag: INS{gr4tz_f0r_y0ur_uns3ri4l1z1ng_tal3nts}

And there you have it! It was a very well crafted challenge in our opinion. Everything appeared almost exploitable but not exploitable enough, making you wonder if you were missing the obvious or some PHP obscure shenanigans. You had to really understand implication of str_replace to find how to actually exploit anything. Even then, you had to think hard about how to leverage the unserialize with all the restrictions in place (cannot read the content of a file, no classes with __construct available, only one call with 2 parameters, etc.)

Kudos to the creator(s)!

Pièces jointes


Ce jeudi nous présenterons les solutions (write-ups) de plusieurs
challenges du CTF de GreHack 2017. Si certains d’entre-vous en avez
réussi certains, ce sera aussi l’occasion de présenter rapidement
comment vous avez fait.

Comme d’habitude, ce sera en amphi E (ou D1xx si amphi indisponible) et
on commencera vers 17h30.

Pièces jointes