Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: tests
on:
push:
branches:
- main
- dev
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Python 3
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Ruff
run: pip install ruff
- name: Ruff format check
run: ruff format --check .
- name: Ruff lint check
run: ruff check .

test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install poetry
poetry install --with test
- name: Run tests with pytest
run: poetry run pytest tests/ -q --tb=short
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Config files (may contain real targets/creds)
*.ini
!example.ini

# Python
__pycache__/
*.pyc
*.pyo

# Logs
*.log
.coverage
159 changes: 67 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,121 +1,96 @@
# PyOracle2
# blockbuster

https://blog.liquidsec.net/2020/11/30/introducing-pyoracle2/
![License](https://img.shields.io/badge/license-GPLv3-f126ea.svg)
![Python](https://img.shields.io/badge/python-3.10+-blue.svg)
![Tests](https://github.com/liquidsec/blockbuster/actions/workflows/tests.yaml/badge.svg?branch=main)

A python-based padding oracle tool.
A python-based padding oracle exploitation tool.

Although several other padding oracle attack tools exist, some quite excellent, there are relatively few written in python. This tool provides another take on attacking padding oracle vulnerabilities with a handful of less common advanced features.
Although several other padding oracle attack tools exist, some quite excellent, there are relatively few written in python. This tool provides another take on attacking padding oracle vulnerabilities with a handful of less common advanced features.

Special Features:
## Features

- **Fault Tolerance** - Can handle some random bad requests (performs sanity check and will redo a block result that doesn’t make sense)
- **Resume feature** - Can be stopped and resumed at will (State of the operation is serialized and stored to disk!)
- **HTTP Proxy Support**
- **Positive and negative oracle searching** - can look for a special string to identify a successful request, and optionally the lack of a string
- **Multiple IV modes** - Supports first block IV (most common), last block IV, or known IV.
- **Async Concurrency** - Solve bytes with up to 256 concurrent requests for massive speed improvements
- **Fault Tolerance** - Configurable confirmation rounds to eliminate false positives from unreliable oracles
- **Resume** - Full state serialization to disk. Stop and resume at any point, including mid-block byte-level resume
- **Encrypt & Decrypt** - Both CBC padding oracle decryption and encryption (via intermediary values)
- **HTTP Proxy Support** - Route traffic through Burp, mitmproxy, etc.
- **Positive and Negative Oracle Modes** - Search for a string on valid padding, or detect its absence
- **Multiple IV Modes** - First block (most common), known IV, unknown IV, or anchor block
- **Multiple Encoding Modes** - Base64, Base64URL, and Hex
- **Multiple Input Modes** - URL parameter, query string, cookie, or POST body
- **Redirect Following** - Manual redirect following with configurable delay between hops
- **HTTP/2 Support** - Via httpx with h2
- **Pre-seeded Intermediates** - Skip known bytes from a previous partial run

Planned improvements:

- ~~Different encoding modes (only base64 is supported currently, although this is definately the most common)~~ **Hex support added**
- Ability to operate inside of XML parameters and JSON variables
- Support for timing-based oracles
## Installation

```bash
pip install poetry
poetry install
```

## Usage

```
usage: pyOracle2.py [-h] [-r RESTORE] [-i INPUT] [-m MODE] [-d] [-c CONFIG]
usage: blockbuster [-h] [-r RESTORE] [-i INPUT] [-m MODE] [-d] [-c CONFIG] [-s INTERMEDIATES]

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
plaintext (for encrypt)
-m MODE, --mode MODE Select encrypt (e) or decrypt (d) mode
-d, --debug increase output verbosity
-c CONFIG, --config CONFIG
Specify the configuration file
-s INTERMEDIATES, --intermediates INTERMEDIATES
Pre-seed solved intermediate values. Format: "15:210,14:216"
```

pyOracle2 is designed around the creation of a configuration file for each unique "job". The goal is to frontload the configuration of the job so that once it is set correctly, exploitation can occur as easily as possible with a concise CLI command. A sample of the configuration file is provided.


Config file example
This example config should work out of the box (aside from setting the correct IP address) with the PentesterLab padding oracle exercise iso: https://pentesterlab.com/exercises/padding_oracle/iso
```
[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

# when using POST, specifiy the POST mode: (form-urlencoded, multipart, or json)
postFormat = x-www-form-urlencoded

# specify the input mode (parameter, body, cookie)
inputMode = cookie

# encoding mode. Current options are base64, base64Url, or hex
encodingMode = base64

# 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 = {}
Blockbuster is designed around the creation of a configuration file for each unique job. The goal is to frontload the configuration so that once it is set correctly, exploitation occurs with a concise CLI command.

# Set the blocksize for the target
blocksize = 8
### Quick Start

# Enable / Disable http proxy for outgoing traffic
httpProxyOn = True
httpProxyIp = 127.0.0.1
httpProxyPort = 8080
```bash
# Decrypt mode
blockbuster -m d -i "BASE64_CIPHERTEXT" -c target.ini

# Specify headers to add to the request (specified in a dictionary as a key/value pair)
# Encrypt mode
blockbuster -m e -i "plaintext to encrypt" -c target.ini

headers = {"User-Agent":"Mozilla/5.0","Content-Type":"application/json"}
# Resume a saved state
blockbuster -r blockbuster-state-job-BLOCK_2-1710000000.pkl

# Resume with pre-seeded intermediates from a previous run
blockbuster -r blockbuster-state-job-BLOCK_2-1710000000.pkl -s "15:210,14:55,13:128"
```

# 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
## Configuration

See `example.ini` for a fully commented configuration file. Key settings:

| Setting | Description |
|---------|-------------|
| `URL` | Target URL |
| `httpMethod` | `GET` or `POST` |
| `inputMode` | `parameter`, `querystring`, `cookie` |
| `encodingMode` | `base64`, `base64Url`, `hex` |
| `vulnerableParameter` | Name of the parameter containing the ciphertext |
| `blocksize` | Block size (8 for DES/3DES, 16 for AES) |
| `oracleMode` | `search` (text present = valid) or `negative` (text absent = valid) |
| `oracleText` | The string to search for in the response |
| `ivMode` | `firstblock`, `knownIV`, `unknown`, or `anchorBlock` |
| `concurrency` | Number of concurrent async requests per byte (1-256) |
| `confirmations` | Re-verification rounds per solved byte (0 = none) |
| `followRedirects` | Follow HTTP redirects manually |
| `redirectDelay` | Seconds to wait before following each redirect |

## Running Tests

```bash
poetry install --with test
poetry run pytest tests/ -q
```
3 changes: 3 additions & 0 deletions blockbuster/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from blockbuster.blockbuster import main

__all__ = ["main"]
Loading
Loading