A Padding Oracle Attack Implemented In Javascript

On September 28, 2010, posted by aazubel



You have probably seen or at least heard about the amazing work done by Juliano Rizzo and Thai Duong where they use decryption oracles against different web applications in many different ways. They also created a new technique (CBC-R) that turns a decryption oracle into an encryptor which is independent of the secret key and the block cipher used.

If you know nothing about this, please find more about it at http://www.netifera.com/research/.

Among the tools they released, there's a javascript implementation of a decryption oracle exploit they show in their presentations and in this video that I developed thanks to the fact they were generous enough to share their research with me before releasing their results.

You can find this implementation of the attack here .

Next I'll explain how this proof-of-concept implementation of the attack works, so you can test and understand the attack yourself in a controlled manner.


Screenshot of an attack in progress.

Screenshot of a successful attack.

The .zip package

The file poet-js-1.0.0.zip contains three files:

  • README: self explanatory.
  • vulnerable.rb: a sample vulnerable server.
  • poetjs.html: an html containing the attack written in javascript. This file should be renamed to attack.html.

The sample vulnerable server

vulnerable.rb is a simple padding oracle vulnerable server written in ruby.

This server binds to localhost:8000 and waits for incoming HTTP requests.

This server simulates a CAPTCHA system that sends encrypted codes to clients which will later be returned back along with manual input of a human to be compared by the server.

This server responds to two different requests.

If the request points to http://localhost:8000/attack.html the server responds with the file attack.html containing an exploit for its vulnerability (This is a convenient way to obtain the javascript to perform the attack, but has nothing to do with the attack itself).

If the request points to http://localhost/securityWord=(.*) the server tries to decrypt the value of the securityWord parameter. The decryption process reveals the difference between valid and invalid padding formats. This one bit information leak creates a side channel that turns the decryption process into a decryption padding oracle.
If the securityWord parameter can be decrypted (the padding is valid), the server responds with an image [HTTP Content-type: image/jpeg] otherwise (the padding is not valid) the server responds with text [HTTP Content-type: text/html].

The attack

Pointing a web browser to http://localhost:8000/attack.html downloads the attack and starts it. (It is also possible to open that file from the local filesystem.)

The attack.html file is an html file containing the attack written in javascript which is crunched into the html for simplicity but it could also be a separate javascript resource.

The sample attack decrypts the des-cbc encrypted value of the securityWord parameter exploiting the side channel created by the way errors in the padding of the last cbc cipherblock are handled by the vulnerable server.

The attack has no real knowledge of the block cipher used by the server, the only information the attack knows is a valid encrypted securityWord issued by server and the IV used.

As a note, the encrypted ciphertext corresponds to the cleartext "secret!" encrypted with the DES encryption algorithm using the key "\x11secret\x11" , but this infornation is not known by the attacker.

Why javascript?

The advantage of implementing this attack in javascript is that any web server hosting the attack could distribute the execution of the attack among clients easily (for example, leveraging a XSS vulnerability), delegating minimal parts of it to different clients and leaving no tracks of the real origin of the attack.

To bypass cross-domain restrictions the attack uses html img tags to ask the decryption oracle for padding consistency. The results of the image loading are verified using the onLoad() and onError() callbacks.