RUP is a desktop application (Tauri 2 + TypeScript UI, Rust backend) that reproduces
the core of a Burp-style workflow: spin up a local HTTPS MITM proxy, auto-launch a
Chromium instance pinned to it, capture and replay requests, and incrementally map a
target (crawl + light fuzz). The proxy backend wraps hudsucker
and rustls, issues per-host leaf certificates from a local CA, and streams every
intercepted exchange to the UI over the Tauri event bus.
RUP is a MITM proxy: it breaks TLS end-to-end guarantees for any client configured to trust its CA. Use it only against systems and targets you own or are explicitly authorized to test (pentest engagement, bug bounty in-scope, CTF, lab). Keep the CA private key secure and remove the CA from trust stores when you're done.
flowchart LR
subgraph App["RUP desktop app (Tauri 2)"]
UI["TypeScript UI<br/>history · replay · site map"]
subgraph Backend["Rust backend"]
CMD["Tauri commands<br/>start_proxy · launch_chromium · replay_request · mapper_*"]
CORE["burp_core<br/>lossless HTTP model (ordered headers, raw start line)"]
PROXY["burp_proxy<br/>hudsucker + rcgen CA + rustls upstream + Chromium launcher"]
MAP["burp_mapper<br/>job queue · crawl HTML · fuzz common paths · per-origin profiles"]
CMD --- CORE --- PROXY --- MAP
end
UI <-->|"Tauri events: proxy:message · mapper:update · debug:proxy"| Backend
end
CHROME["Chromium<br/>dedicated profile + NSS trust store<br/>--proxy-server, --disable-quic"]
ORIGIN[(Origin server)]
CHROME -->|"HTTP/1.1 · HTTP/2 over TCP"| PROXY
PROXY -->|"per-host leaf cert signed by local CA"| CHROME
PROXY -->|"rustls (aws-lc-rs, webpki roots)"| ORIGIN
MAP -.->|crawl / fuzz requests| ORIGIN
- QUIC is disabled in Chromium so all traffic stays on the TCP proxy path. HTTP/2 is supported; HTTP/3 is not proxied.
- Every intercepted request emits a
Messageto the UI (proxy:message). Responses currently pass through — extendhandle_responseto capture bodies.
- Transparent HTTP/1.1 and HTTP/2 interception
- On-the-fly leaf certificate issuance from your local CA (rcgen)
- Chromium launcher with dedicated profile and NSS trust store
- Lossless request parsing and serialization (ordered headers, raw start line)
- Request replay
- Basic site mapper: seed → crawl links → fuzz common paths
- Tauri events streaming to the UI
src-tauri/
Cargo.toml
src/
main.rs # Tauri app entry, commands, event wiring
lib.rs # Example Tauri command (greet)
crates/
burp_core/ # Data model and lossless HTTP parse utilities
burp_proxy/ # Hudsucker wrapper, CA loading, Chromium launcher
burp_mapper/ # Crawler + light fuzzer + profiles
-
burp_coreData structures:Request,Response,Message,HeaderList,HttpVersion. Utilities: lossless parsing of request/status lines and headers. -
burp_proxy-
Hudsucker proxy with:
- CA:
RcgenAuthorityfromca.pem+ca.key.pem - Upstream TLS: rustls using webpki roots (aws-lc-rs provider)
HttpHandlerthat emitsMessageon every request
- CA:
-
Chromium launcher:
- sets
HOMEto the chosen profile directory - uses
--user-data-dir,--proxy-server,--disable-quic - verifies NSS DB and CA import
- sets
-
-
burp_mapper- Async manager with a job queue and per-origin concurrency
- Seed URLs, crawl HTML, fuzz common endpoints
- Emits
MapperEventon discoveries - Optional per-origin profiles (headers, cookies)
-
Files expected in the profile directory:
ca.key.pem— CA private key (PKCS#8 or SEC1; SEC1 is auto-converted)ca.pem— self-signed CA certificate (X.509) with CA basic constraints.pki/nssdb/cert9.db— NSS database that trusts the CA
-
RUP loads the CA into
RcgenAuthority. Hudsucker issues per-origin leaf certs on demand. -
Upstream TLS uses
rustlswith webpki roots (aws-lc-rs crypto provider).
- Sets
HOMEand--user-data-dirto the same profile directory to force the NSS trust store used by that profile. - Uses
--proxy-server=http=HOST:PORT;https=HOST:PORTand--proxy-bypass-list=<-loopback>. - Uses
--disable-quicto avoid HTTP/3.
- Rust stable, Node 18+
- Tauri 2 toolchain
libnss3-tools(certutil) for NSS DBopensslor any tool able to generate a CA- Chromium or Chrome installed and discoverable in
PATH(chromium,chromium-browser,google-chrome-stable, etc.)
PROFILE="$HOME/.local/share/rup"
mkdir -p "$PROFILE/.pki/nssdb"Example with OpenSSL:
cd "$PROFILE"
openssl genrsa -out ca.key.pem 4096
openssl req -x509 -new -nodes -key ca.key.pem -sha256 -days 3650 \
-subj "/CN=BurpCloneCA" \
-out ca.pem \
-addext "basicConstraints=critical,CA:true,pathlen:1" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-addext "subjectKeyIdentifier=hash" \
-addext "authorityKeyIdentifier=keyid,issuer"# Create an empty NSS DB (uses sql: driver)
certutil -N -d "sql:$PROFILE/.pki/nssdb" --empty-password
# Import the CA as a trusted issuer for TLS
certutil -A -d "sql:$PROFILE/.pki/nssdb" -n "BurpCloneCA" -t "C,," -i "$PROFILE/ca.pem"
# Verify
certutil -L -d "sql:$PROFILE/.pki/nssdb"You should see BurpCloneCA listed.
From the repo root:
# install deps
npm i
# dev run
npm run tauri devThe app exposes Tauri commands to:
- start the proxy:
start_proxy(bind: "127.0.0.1:8080", auto_launch: bool) - launch Chromium bound to the proxy:
launch_chromium(bind: "127.0.0.1:8080") - replay a request:
replay_request(Request) - mapper control:
mapper_enqueue_seed,mapper_enqueue_discovered,mapper_set_profile
In the UI, call window.__TAURI__.invoke("<command>", args).
-
proxy:message→MessageEmitted for every intercepted request. -
mapper:update→MapperEventEmitted for every discovered URL with status and content type. -
debug:proxy→StringOptional debug lines from the proxy layer.
Request { id, method, url, version, headers: HeaderList, body, timings, annotations, raw_request_line }Response { id, version, status, reason, headers, body, timings, annotations, raw_status_line }Message { id, request, response: Option<Response>, created_at, scope }HeaderListpreserves header order and original casing.
Lossless helpers:
parse_request_line(&str) -> (Method, target, HttpVersion)parse_status_line(&str) -> (HttpVersion, status, reason)parse_header_lines_lossless(&[&str]) -> HeaderListbuild_url_from_parts(scheme, host, port, path_q) -> Url
Programmatic facade exposed in Tauri:
-
mapper_set_profile(SiteProfile)Default headers and cookie hints per origin. -
mapper_enqueue_seed(url: String)Starts exploration. -
mapper_enqueue_discovered(url: String)Manually add URLs.
Events:
mapper:updatewithMapperEvent { origin, url, status, content_type, discovered_by, when }.
Heuristics:
- Extract links from HTML (
a[href],link[href],script[src],img[src],form[action]) - Fuzz small wordlist for directories and sibling files
- Limited redirects and body sizes
replay_request(Request) -> Response
Rebuilds a Reqwest request with original method, URL, and headers, then returns a Response object with headers and body. Cookies and auth flows are not persisted automatically. Adjust as needed.
-
Chromium cannot connect or shows certificate errors
- Ensure
BurpCloneCAappears incertutil -L -d "sql:$PROFILE/.pki/nssdb". - Verify
HOMEis set to the profile dir and--user-data-dirpoints to the same path. - Ensure
--disable-quicis applied. - Check that the proxy bind address is reachable and not blocked by firewall.
- Ensure
-
Pages like Wikipedia or YouTube do not load
- These enforce HSTS and strict TLS. The CA must be trusted by the active profile. Double-check NSS import and that Chromium launched with that profile.
- Confirm traffic is HTTP/1.1 or HTTP/2 over TCP, not QUIC.
-
certutil: command not found- Install
libnss3-tools(Debian/Ubuntu) or the equivalent for your distro.
- Install
-
Build error about
with_rustls_client- Hudsucker ≥0.24 uses
.with_rustls_connector(provider)instead. The code already uses this.
- Hudsucker ≥0.24 uses
-
Proxy starts but nothing appears in the UI
- Ensure the UI subscribes to
proxy:messageandmapper:update. - Confirm
start_proxywas invoked with the expected bind address.
- Ensure the UI subscribes to
- Capture and store full responses in
handle_response. - Interception rules and modification hooks.
- Persistent project storage and search.
- Larger fuzz wordlists and smarter scheduling.
- WebSocket handling and HTTP/2 push.
See the callout at the top: authorized targets only, protect the CA private key, remove the CA from trust stores when finished.
Working desktop app. Request interception + replay + a basic site mapper; response-body
capture, interception/modification rules, and persistent project storage are the obvious
next steps (see TODO.md and Extending above).
Part of my work — more at zz0r0.fr.