Metadata-Version: 2.4
Name: quicdraw
Version: 0.9.2
Summary: QuicDraw(H3) Fuzzing and Racing HTTP/3 (over QUIC)
Author-email: Maor A <m2a2@users.noreply.github.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/cyberark/QuicDrawh3
Project-URL: Issues, https://github.com/cyberark/QuicDrawh3/issues
Keywords: HTTP/3,QUIC,Web,Security,Fuzzing,Fuzz,Race-Conditions,Web Security,Web Application Security,HTTP3
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Framework :: AsyncIO
Classifier: Topic :: Security
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: System :: Networking
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: aioquic
Requires-Dist: wsproto
Provides-Extra: test
Requires-Dist: pytest>=7.0.0; extra == "test"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
Requires-Dist: pytest-qt>=4.2.0; extra == "test"
Provides-Extra: ui
Requires-Dist: pyside6; extra == "ui"
Dynamic: license-file

# QuicDraw (H3)

![HTTP/3 Request Editor](screenshots/quicdraw-h3-logo.png "QuicDraw Logo")

```bash
    -----------
    QuicDraw(H3): HTTP/3 Fuzzing and Racing (Client)
    -----------
               _         _
              (_)       | |                          ______
    __ _ _   _ _  ___ __| |_ __ __ ___      __  /\  /\___ /
   / _` | | | | |/ __/ _` | '__/ _` \ \ /\ / / / /_/ / |_ \
  | (_| | |_| | | (_| (_| | | | (_| |\ V  V / / __  / ___) |
   \__, |\__,_|_|\___\__,_|_|  \__,_| \_/\_/  \/ /_/ |____/
      |_|    _______
         \  |QFS____| -------------------- HTTP/3
          \ |_//
            |_|

    GitHub: https://github.com/cyberark/QuicDrawH3
    License: Apache-2.0 License
    Author: Maor Abutbul <CyberArk Labs>
    -----------
```

QuicDraw is a security research tool designed for fuzzing and racing
HTTP/3 servers. QuicDraw implements the `Quic-Fin-Sync` on HTTP/3 (over
QUIC), for race-condition testing.

The tool was originally published as part of CyberArk Labs' research:
"[Racing and Fuzzing HTTP/3: Open-sourcing
QuicDraw(H3)](https://www.cyberark.com/resources/threat-research-blog/racing-and-fuzzing-http-3-open-sourcing-quicdraw)"

The research, has been presented at: BlackAlps, Nullcon (Goa), and [BlueHatIL26](https://www.youtube.com/watch?v=tOfBfbc5ClY).

## TOC

- [QuicDraw](#quicdraw-h3)
  - [Main Features](#main-features)
  - [Quick Start](#quick-start)
    - [Install using pip](#install-using-pip)
    - [Build and install locally by cloning the source
      (optional)](#build-and-install-locally-by-cloning-the-source-optional)
  - [Usage](#usage)
    - [Print Help](#print-help)
    - [Normal HTTP/3 (over QUIC)
      Requests](#normal-http3-over-quic-requests)
    - [Observability](#observability)
      - [Include response headers in the output
        `-i`](#include-response-headers-in-the-output--i)
      - [Verbose logging `-v` / `-vv`](#verbose-logging--v---vv)
      - [Write the response body to a file or stdout
        `-o OUTPUT`](#write-the-response-body-to-a-file-or-stdout--o-output)
      - [Log TLS Secrets to file
        `-l SECRETS_LOG`](#log-tls-secrets-to-file--l-secrets_log)
    - [Testing Race-Conditions in HTTP3 applications](#test-race-conditions-in-http3-applications)
      - [Racing example](#racing-example)
    - [Fuzzing HTTP3 applications](#fuzzing-http3-applications)
      - [Fuzzing Example (POST data)](#fuzzing-example-post-data)
      - [Path Fuzzing Example (GET)](#path-fuzzing-example-get)
- [QuicDraw-UI](#quicdraw-ui)
  - [Install quicdraw-ui using pip
    (PyPi)](#install-quicdraw-ui-using-pip-pypi)
  - [Example 1: Simple HTTP/3
    Request](#example-1-simple-http3-request)
  - [Example 2: Fuzzing with a
    Wordlist](#example-2-fuzzing-with-a-wordlist)
- [Contributing](#contributing)
- [Limitations](#limitations)
- [Known issues](#known-issues)
- [License](#license)
- [Contact](#contact)
  - [Contact Via LinkedIn](#contact-via-linkedin)

##  Main Features

- Implements the `Quic-Fin-Sync` on HTTP3 (over QUIC), for
  race-condition testing.
- Supports fuzzing multiple requests with the `FUZZ` and wordlist
  (`-w` argument) mechanisms.
- Custom HTTP headers functionality (`-H` argument).
  - Note: Custom headers are converted to lowercase since we have
    seen issues with some server implementations.
- Supports SSLKEYLOGFILE (`-l` argument) for TLS decryption/inspection
  via packet analyzers such as Wireshark.
- Based on aioquic (http3_client)
  - [aioquic](https://github.com/aiortc/aioquic) is a library for
    the QUIC network protocol in Python.
  - It features a minimal TLS 1.3 implementation, a QUIC stack, and
    an HTTP/3 stack.

## Quick Start

Prerequisite:

- python \>=3.9
- pip3

## Install using pip

The easiest way to install QuicDraw is to run:

```bash
pip install quicdraw
```

### Running (after pip install)

```bash
quicdraw -h
```

### Install quicdraw-ui using pip (PyPi)

The easiest way to install QuicDraw-UI is to run:

```bash
pip install quicdraw[ui]
quicdraw-ui -h
```

### Build and install locally by cloning the source (optional)

<details>
  <summary>Build from source</summary>

If there are no wheels for your system or if you wish to build QuicDraw
from source.

Clone the repository:

(You may prefer to do this within a
[Virtual
Environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/))

```bash
git clone https://github.com/cyberark/quicdrawh3.git
python3 -m build
pip install .\dist\quicdraw-<VERSION>.whl
pip install .\dist\quicdraw-<VERSION>.whl[ui] # with the GUI (dependencies)
```

</details>

---

## Usage

### Print Help

```bash
quicdraw -h
```

### Normal HTTP/3 (over QUIC) Requests

### An HTTP/3 GET Request

```bash
quicdraw <https://http3_server.com/path>
```

### An HTTP/3 POST Request

HTTP POST requests are determined by using the `-d` argument followed by
the HTTP POST data to be sent.

```bash
quicdraw <https://http3_server.com/path> -d '{"key":"value"}'
```

## Observability

QuicDraw offers several ways to inspect requests and responses, from
quick console output to files consumable by other tools:

| Flag                | Purpose                                                      |
| ------------------- | ------------------------------------------------------------ |
| `-i, --include`     | Prepend the HTTP response headers to the output (curl-style) |
| `-v` / `-vv`        | Increase logging verbosity (`-v` debug, `-vv` also QUIC)     |
| `-o, --output`      | Write the raw response **body** to a file or stdout          |
| `-l, --secrets-log` | Log TLS secrets to a file, for use with Wireshark            |

### Include response headers in the output `-i`

Use the `-i/--include` argument to print the HTTP response headers
alongside the response, mirroring `curl -i`. Each received response
header is printed to the console, and when combined with `-o/--output`
the headers are also prepended to the written body.

```bash
quicdraw <https://http3_server.com/path> -i
```

Without `-i`, only the response status line and body are surfaced; the
individual headers are still available at debug level via `-v`.

### Verbose logging `-v` / `-vv`

Verbosity is cumulative — repeat the flag to increase detail:

- `-v` sets the QuicDraw logger to **DEBUG**. It logs (prints) the
  request data to be sent, the full response headers, and the response
  content, along with the tool version. In the case of GET requests (no
  `-d` argument supplied), the request URL (:path) is logged (printed).
- `-vv` additionally raises the underlying **QUIC** logger to DEBUG, so
  you also see low-level QUIC/HTTP-3 protocol events.

```bash
quicdraw <https://http3_server.com/path> -v    # debug logging
quicdraw <https://http3_server.com/path> -vv   # debug + QUIC internals
```

Note: `-v` is intended for interactive inspection — it interleaves the
response content with log lines. For scripting or piping the response
body, prefer `-o/--output` (below).

### Write the response body to a file or stdout `-o OUTPUT`

Use the `-o/--output` argument to write the raw HTTP response **body** to a
file, mirroring `curl`'s output behavior. Pass a filename to save the body,
or `-` to stream it to standard output (so it can be piped to other tools).

Unlike `-v`, which prints the response content interleaved with log lines,
`-o` writes only the response body, making it suitable for scripting and
piping.

Save the response body to a file:

```bash
quicdraw <https://http3_server.com/path> -o response.json
```

Stream the response body to stdout and pipe it to another tool:

```bash
quicdraw <https://http3_server.com/path> -o - | grep -i "token"
```

Notes:

- `-o` writes the response body only. Combine it with `-i/--include` to
  prepend the response headers (curl-style).
- When multiple requests/streams are sent (e.g. with `-tr` or `-w`), all
  response bodies are concatenated into the single output target.
- `-o/--output` writes a single response target (file or stdout), whereas
  `--output-dir` writes each downloaded stream to its own file in a
  directory. They are independent options.

### Log TLS Secrets to file `-l SECRETS_LOG`

Use the `-l/--secrets-log` argument to log the TLS secrets to a file
(SSLKEYLOGFILE), for use with a packet analyzer such as Wireshark.

```bash
quicdraw <https://http3_server.com/path> -l /path/to/secrets.log
```

To inspect the traffic in Wireshark: Open Wireshark → Edit → Preferences
→ Protocols → TLS and set "(Pre)-Master-Secret log filename" to the full
path of `secrets.log`. Wireshark can then decrypt the captured QUIC/TLS
traffic.

## Test Race-Conditions in HTTP/3 applications

`-tr TOTAL_REQUESTS`

To use the same request multiple times (using the `Quic-Fin-Sync` /
`single-packet`), use the `-tr/--total-requests` argument.

Note: If a WORDLIST (`-w`) argument is specified, this argument
(`-tr TOTAL_REQUESTS`) is overridden by the wordlist number of lines.

### Racing example

Repeat the same request 12 times (`-tr 12`) (using `Quic-Fin-Sync`)

```bash
quicdraw <https://http3_server.com/path> -d '{"key":"value"}' -H 'Authorization: bearer eyJ...' -tr 12
```

Repeat the same request 12 times (`-tr 12`), use `Quic-Fin-Sync` and log (`-l`) TLS secrets

```bash
quicdraw <https://http3_server.com/path> -d '{"key":"value"}' -H 'Authorization: bearer eyJ...' -H 'content-type: application/json' -l /m2a/ssl_key_log_file.log -tr 12
```

Repeat the same request 12 times (`-tr 12`), use `Quic-Fin-Sync`, log (`-l`) TLS secrets, and print verbose (`-v`) output including HTTP response content

```bash
quicdraw <https://http3_server.com/path> -d '{"key": "value"}' -H 'Authorization: bearer eyJ...' -H 'content-type: application/json' -l /m2a/ssl_key_log_file.log -tr 12 -v
```

## Fuzzing HTTP3 applications `-w` WORDLIST

Fuzzing in QuicDraw is based on a simple concept, like other web fuzzers
([Ffuf](https://github.com/ffuf/ffuf),
[Wfuzz](https://github.com/xmendez/wfuzz)), go over the data section
(`-d`), and replace any reference to the `FUZZ` keyword with the value
given in the wordlist (`-w`) as the payload.

To define fuzzing, use the wordlist (`-w`/`--wordlist`) argument with
the `FUZZ` keyword either in the DATA (`-d`) section (POST-data fuzzing)
**or** in the request URL path (path fuzzing, when no `-d` is supplied).

Note: If the payload (`-d`) does not include the `FUZZ` keyword, the
same data will be sent according to the _number of lines_ in the
wordlist file.

### Fuzzing Example (POST data)

Use `Quic-Fin-Sync`, go over the data section (`-d`), and replace any reference to the `FUZZ` keyword with the value given in the wordlist file (`-w`) as the payload

```bash
quicdraw <https://http3_server.com/path> -w path/to/wordlist -d '{"example_key":"FUZZ"}'
```

### Path Fuzzing Example (GET)

When no `-d` (POST data) argument is supplied, the `FUZZ` keyword is
substituted in the request URL path instead. For each word in the
wordlist (`-w`), a GET request is sent with `FUZZ` replaced by that word
— useful for endpoint/directory discovery.

```bash
quicdraw <https://http3_server.com/FUZZ> -w path/to/wordlist
```

For example, with a wordlist containing `admin`, `login`, and `api`, the
tool requests `/admin`, `/login`, and `/api` respectively.

Note: Per the [Limitations](#limitations), fuzzing is applied **once**.
If `-d` is supplied, QuicDraw assumes POST-data fuzzing and sends the
URL path as-is (any `FUZZ` in the path is left untouched).

---

## QuicDraw-UI

```bash
    -----------
    QuicDraw-UI: HTTP/3 Request Editor - A GUI for QuicDraw(H3): HTTP/3 Fuzzing and Racing (Client)
    -----------
               _         _
              (_)       | |                            __  ______
    __ _ _   _ _  ___ __| |_ __ __ ___      __        / / / /  _/
   / _` | | | | |/ __/ _` | '__/ _` \ \ /\ / / _____ / / / // /
  | (_| | |_| | | (_| (_| | | | (_| |\ V  V / /____// /_/ // /
   \__, |\__,_|_|\___\__,_|_|  \__,_| \_/\_/        \____/___/
      |_|    _______
         \  |QFS____| -------------------- HTTP/3
          \ |_//
            |_|
```

### Install quicdraw-ui (using pip PyPi)

The easiest way to install QuicDraw-UI is to run:

```bash
pip install quicdraw[ui]
quicdraw-ui -h
```

### Example 1: Simple HTTP/3 Request

Send a basic request to an HTTP/3 server:

```bash
quicdraw-ui https://www.cyberark.com
```

### HTTP/3 Request Editor

![HTTP/3 Request Editor](screenshots/QD-UI_basic_1.png "HTTP/3 Request Editor")

### Advanced Tab

![Advanced Tab](screenshots/QD-UI_basic_3.png "Advanced Tab")

The following options can be set by the advanced tab

Option Description

---

`-l, --secrets-log` TLS secrets file (for Wireshark)
`-v, --verbose` Verbose output

**Results Tab:**

![Results Tab](screenshots/QD-UI_basic_2.png "Results Tab")

---

## Example 2: Fuzzing with a Wordlist

To fuzz an HTTP/3 endpoint, you need:

1. **A wordlist file** (`-w`) - contains payloads to test (one per
   line)
2. **The `FUZZ` keyword** in your data - gets replaced by each wordlist
   entry

```bash
quicdraw-ui https://www.cyberark.com -w path/to/wordlist -d '{"example_key":"FUZZ"}'
```

![Fuzzing Example](screenshots/fuzzing.png)

The `FUZZ` keyword in `{"example_key":"FUZZ"}` will be replaced with
each line from your wordlist file.

---

### Command-Line Options

QuicDraw-UI parameters are imported to the UI.

---

Option Description

---

`-d, --data` HTTP POST data (use `FUZZ` for wordlist
substitution)

`-H, --header` Custom header (repeatable)

`-b, --cookie` Custom cookie header

`-w, --wordlist` Fuzzing wordlist file

`-tr, --total-requests` Number of concurrent requests (race testing)

`-l, --secrets-log` TLS secrets file (for Wireshark)

`-v, --verbose` Verbose output

---

Note: "copy-as-curl compatible" meaning common curl arguments (-d,-H,-b)
are supported by QuicDraw-UI.

---

## Testing

QuicDraw includes a comprehensive pytest-based test suite covering unit, integration, and end-to-end scenarios.

<details>
  <summary>Running Tests</summary>

## Running Tests

### Install Test Dependencies

```bash
# Install project with test dependencies
pip install -e ".[test]"

# Or install test dependencies separately
pip install pytest pytest-asyncio pytest-cov pytest-mock
```

### Run All Tests

```bash
# Run all tests
pytest

# Run with verbose output
pytest -v

# Run tests with coverage report
pytest --cov=src/quicdraw --cov-report=html --cov-report=term-missing

# View coverage report (after running with --cov-report=html)
open htmlcov/index.html  # macOS
xdg-open htmlcov/index.html  # Linux
```

### Run Specific Test Categories

```bash
# Run only unit tests (fast, no I/O)
pytest tests/unit/ -v

# Run only integration tests
pytest tests/integration/ -v

# Run only end-to-end tests
pytest tests/e2e/ -v

# Run tests with specific markers
pytest -m unit           # Unit tests only
pytest -m integration    # Integration tests only
pytest -m "not slow"     # Skip slow tests
```

### Run Specific Test Files or Functions

```bash
# Run a specific test file
pytest tests/unit/test_validation.py -v

# Run a specific test function
pytest tests/unit/test_validation.py::test_non_negative_float_valid -v

# Run tests matching a pattern
pytest -k "validation" -v
```

## Test Structure

```bash
tests/
├── unit/              # Fast unit tests (no I/O dependencies)
├── integration/       # Integration tests with mocked I/O
├── e2e/              # End-to-end workflow tests
└── ui/               # GUI component tests (optional)
```

</details>

---

## Contributing

We welcome contributions of all kinds to this repository. For
instructions on how to get started and descriptions of our development
workflows, please see our [contributing guide](CONTRIBUTING.md)

## Limitations

- The `Quic-Fin-Sync` is mostly effective in POST requests (using the
  `-d` argument).
  - GET requests will benefit from the mechanism, but according to
    our tests, only a few requests "fit" on a single QUIC packet.
- The fuzzing mechanism (`FUZZ` and `--wordlist/-w`) only works in
  POST messages data **or** in the GET request URL (:path) argument.
- Currently, the fuzzing mechanism only works **once**, meaning if the
  data argument is supplied (`-d`), we assume fuzzing on the POST
  data, supplying the `FUZZ` keyword in the URL (:path) will result in
  sending the URL (:path) as-is (including the `FUZZ` keyword).
- We do not support multiple different domains in the current version.
  (For different paths, you can use the FUZZ keyword in the URL's path
  part)

---

## Known issues

- None

## License

Copyright (c) 2025 CyberArk Software Ltd. All rights reserved This
repository is licensed under the Apache-2.0 License - see
[`LICENSE`](LICENSE) for more details.

## Contact

Feel free to contact us via GitHub issues if you have any feature
requests or project issues.

### Contact Via LinkedIn

[Maor Abutbul](https://il.linkedin.com/in/maor-abutbul)
