Introducing PyOracle2

I’d like to introduce PyOracle2. It is a python-based padding oracle exploitation tool.

https://github.com/liquidsec/pyOracle2

Why make another tool?

Yes, several other padding oracle exploitation tools already exist. Some of them are really quite good. So why another tool? The short answer is: I created it for myself and later decided I might as well spruce it up and release it. The reason I felt the need to create a tool in the first place is a bit more complicated. PadBuster is the standard, and by all measures it is excellent. There is really one main problem with it, and you might not even agree that it’s a problem – it’s written in Perl.

Of course, there is nothing inherently wrong with that, but as someone that happens to not be very fond of Perl… and in particular: modifying someone ELSES Perl, I ran into a problem. Although PadBuster is great at exploiting textbook padding oracle vulnerabilities, something I learned very quickly as I started to hunt for them is that there are a LOT of edge cases. There are enough small divergences in the way developers implement crypto that I was finding myself having to modify the code. Faced with the decision of doing surgery on PadBuster or writing my own tool in python, which I am significantly more comfortable with, I opted for the latter.

Of course there are other tools too, some of them are even written in python, but none of them did exactly what I wanted.

PadOracle is another excellent option. Written in go, it’s naturally very fast. It also certainly wins the award for coolest looking. Some cool features and probably more mature than PyOracle2 at the moment.

Ok, but how is PyOracle2 different?

It is built around the concept of “jobs” which will have their own configuration files. The concept is to frontload the sometimes annoying job of customizing an attack for a particular target and encapsulate them into a config file. Once this is done, the actual exploitation then becomes as simple as possible. It also makes it easier to come back to an old target later without fumbling over giant CLI commands.

Advanced Features

Fault Tolerance

A common problem when dealing with the large volume of requests (as a padding oracle attack demands) is that sometimes, you might randomly get an error on the website or  have something get mangled in transmission. When you are 15 blocks into a 16 block decryption, this is simply unacceptable. To deal with this, PyOracle2 includes has a “sanity check” which will examine the results of a completed block to ensure they make sense. If they do not it will start the block over. This is a much better option than starting over from scratch.

Resume feature

After every successfully completed block, the current state is serialized and written to disk as a .pkl file. This allows for resuming the job later. If  for some reason the python process itself is interrupted, or your computer reboots, or you need to turn it off for the day – you can pick back up where you left off, at least to the nearest completed block. To resume, simply run pyOracle2.py with the -r option, pointing to the desired .pkl file.

HTTP Proxy Support

Supports the use of an HTTP proxy. This can be used to loop an intercepting proxy into the attack or to forward traffic to an attack box first.  

Positive and negative oracle searching

When conducting a padding oracle attack, determining when the padding is correct is usually a matter of listening to the responses and looking for a particular string (for example: “logged in user:”). This would be considered “positive searching”. In addition to this, pyOracle2 also supports “negative searching”, which is looking for the absence of a particular phrase, as is necessary with some targets (for example: “padding invalid”).

Multiple IV modes

PyOracle2 supports a variety of initialization vector configurations depending on how the target is configured. First block IV is by far the most common. Last block IV is supported, which is a less common configuration but still occasionally encountered. Finally,  known IV – where the IV is not one of the blocks in the ciphertext and is instead hardcoded in within the application (Developers: This is a really bad idea, don’t do it).

Limitations and future plans

Encoding modes

Currently only base64 encoding is supported. Although this is certainly the most common, you may encounter another encoding such as ASCII HEX, decimal, or even raw binary. Future support is planned for these modes.

Update: Hex mode has been added, more coming soon hopefully!

Ability to operate inside of XML parameters and JSON variables

Currently, it is possible to specify the “inputMode” within the configuration to parameter, body , or cookie. For parameters, both GET and POST are supported. This defines what kind of variable the vulnerable parameter is, so that the request can be properly reconstructed. In the future, support will be available for targeting parameters within XML content, as well as within JSON parameters.

Support for timing-based oracles

I am not aware of a tool that can effectively perform a timing-based padding oracle attack currently. If there is one, please let me know and I will be happy to reference it… but as far as I know, doing this currently would require heavy customization of existing tools. I would like to add native support for timing-based attacks. This type of padding oracle vulnerability is incredibly difficult to spot in the first place, and depending on how subtle the time difference is, very difficult to exploit. It will probably require me making a fake vulnerable app for myself to use to develop the feature.

Usage

usage: pyOracle2.py [-h] [-r RESTORE] [-i INPUT] [-m MODE] [-d] [-c CONFIG]
 optional arguments:
   -h, --help            show this help message and exit
   -r RESTORE, --restore RESTORE
                         Specify a state file to restore from
   -i INPUT, --input INPUT
                         Specify either the ciphertext (for decrypt) or
                         plainttext (for encrypt)
   -m MODE, --mode MODE  Select encrypt or decrypt mode
   -d, --debug           increase output verbosity
   -c CONFIG, --config CONFIG
                         Specify the configuration file 

Putting aside the configuration file (more on that in a moment), a command to decrypt a particular ciphertext would look like this:

python3 pyOracle2.py -m decrypt -c example.ini -i y25az1UAzQ5NN0F5bq%2FjQ2Cbqxe9Cun1

A command to encrypt arbitrary text would be very similar:

python3 pyOracle2.py -m encrypt -c example.ini -i PlainTextToEncrypt

As stated previously, PyOracle2 is designed around the creation of a configuration file for each unique “job”. A sample of the configuration file is provided.

Config file example

 [default]
 # Job Name
 name = Name
 # Specify the target URL
 URL = http://127.0.0.1/index.php
 # Specify the HTTP method (GET or POST)
 httpMethod = GET
 # specify the input mode (parameter, body, cookie)
 inputMode = cookie
 # Specify the parameter which contains the vulnerable variable
 vulnerableParameter = auth
 # Additional Parameters (specified in a dictionary as a key/value pair). Be sure to use double quotes. 
 additionalParameters = {}
 # Set the blocksize for the target
 blocksize = 8
 # Enable / Disable http proxy for outgoing traffic
 httpProxyOn = True
 httpProxyIp = 127.0.0.1
 httpProxyPort = 8080
 # Specify headers to add to the request (specified in a dictionary as a key/value pair)
 headers = {"User-Agent":"Mozilla/5.0"}
 # Specify Cookies to add to the request (specified in a dictionary as a key/value pair)
 cookies = {}
 # Specify the IV mode
 # In most implementations, the IV is provided as the 'first block' of the ciphertext. 
 # In other cases, the IV may be kept a known secret by both endpoints. In such a case, it should still be possible to decrypt everything but the first block.
 # The IV may also be a static values such as all zeroes.
 # Modes: 
 # 'firstblock'. This mode assumes that the first block of the ciphertext is the IV (most common)
 # 'knownIV'. This mode allows for user provided IV
 # 'unknown'. Use this mode when you do not know the IV and it is not the first block but still wish to decrypt all but the first block, or re-encrypt all but the first block for encryption
 # 'lastblock'. This has not been implemented yet, but it may be in the future as it is a rare but possible configuration
 # choose from one of the above modes
 ivMode = firstblock
 # If using knownIV mode, specify the IV
 #IV should be in decimal list format. For example: [72,65,82,65,77,66,69]
 iv =  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
 # The oracle defines the information leak that is abused to know when padding is valid. This is typically an error message.
 # There are several trigger modes depending on the situation. Sometimes you will want to look for a specific phrase, other times you want to look for an absence of that phrase. 
 # trigger modes:
 # 'search' - simply look for a specific phrase
 # 'negative' - the opposite of search. Trigger when you don't see the phrase
 oracleMode = negative
 # Define the search phrase to look for from the oracle
 oracleText = Invalid padding

Hopefully, the comments within the sample configuration provide enough information to make it clear how they are supposed to be used.

Although the intention behind the configuration file is that a wide variety of padding oracle vulnerabilities can be addressed without customization, you very well might run into one which is not supported by the current options.

I tried to design the actual code to be as friendly to modification as possible in these cases, and made an effort to provide useful comments to facilitate this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s