A staged orchestration layer over feroxbuster, ffuf, hashcat, and
thc-hydra -- project-aware, resumable, and reported in one place instead
of four.
Quickstart · Features · Usage · Roadmap · Contributing
Screenshot placeholder -- add docs/images/demo.png (a terminal run or the HTML report) and this shows it.
- What is Obliquity?
- Features
- Requirements
- Installation
- Quickstart
- Usage
- Built-in gameplans
- How resume actually works
- Data location
- Roadmap / future features
- Contributing
- License
Obliquity is a CLI for staged penetration-testing tool orchestration, built around four pillars, each wrapping one underlying tool:
| Pillar | Tool | Job |
|---|---|---|
bust |
feroxbuster |
Staged directory/file content discovery |
fuzz |
ffuf |
Parameter, endpoint, and raw-request fuzzing |
crack |
hashcat |
Staged offline password/hash cracking |
brute |
thc-hydra |
Staged online login/credential attacks |
It is not a replacement for any of those tools -- it's a thin, honest wrapper that adds the project management layer they don't try to be:
- project + host/job tracking, with per-host metadata (
--tech,--server,--profile) - JSON gameplans: an ordered sequence of stages instead of one flag-heavy command
- completed-stage skipping -- rerunning a finished gameplan doesn't redo the work
- stop-and-warn instead of silently repeating scans, with a suggested next step
- raw output archiving + JSONL parsing into one shared SQLite database per project
- unified reporting across all four pillars: HTML, JSON, CSV, and Markdown
- a small downloadable wordlist catalog, so you're not manually
git clone-ing SecLists
A real engagement rarely means one content-discovery scan. For a single
host you end up running feroxbuster over and over: common.txt, then
big.txt, then raft-medium, then raft-large, then the same lists again
with .bak/.old/.zip/.config extensions, then again recursively into
each interesting directory you just found (/admin/, /backup/, /api/).
That's easily 4-6 wordlist passes per host -- and then you multiply the
whole thing by every host in scope, and again by every promising
subdirectory.
Doing that by hand means babysitting a queue of near-identical commands, manually remembering which wordlist/extension/depth combination you've already thrown at which host and which path, and starting over from scratch whenever a scan gets interrupted or you close the laptop. It's slow, it's easy to lose your place in, and it's miserable to resume cleanly.
Obliquity turns that into a single declarative gameplan per host. It runs the passes in order, fingerprints each one so it never repeats a combination it's already completed, resumes where you left off, and logs every finding from every host into one project database and one report -- so the busywork disappears and you just read results.
- Project-based target management -- one project, many hosts, each with its own server/tech/profile metadata that Obliquity actually uses (see Host/Application Awareness below)
- Resumable by design -- every stage is fingerprinted on its exact parameters (wordlist, extensions, recursion, hash type, attack mode, ...) and skipped once completed
- Smart-ish rerun handling -- trying to rerun a fully completed gameplan stops, tells you what it already found and when, and offers a sensible escalation instead of either silently doing nothing or silently redoing everything
- Gameplan escalation ladders --
generic-quick->generic-standard->generic-deep,quick-dictionary->standard, offered automatically - Unified scan history across all four pillars in one readable log
- Multi-format reporting -- HTML (with cracked-hash, crack-run, and found-credential sections), JSON, CSV, and Markdown, all from the same underlying data
- Downloadable wordlist catalog -- no more manually cloning all of
SecLists just to get
common.txtandrockyou.txt - Dry-run mode everywhere, and Burp-friendly proxy/header passthrough
- Python 3.10+
feroxbuster,ffuf,hashcat, andhydrainstalled and available onPATH(obliquity doctorchecks them for you; each pillar only needs its own tool, so a missing one just disables that pillar)- SecLists content for the default profiles -- or just let Obliquity download the handful of files it actually needs, see Wordlist setup
If you don't already have it (python3 --version / py --version):
| Platform | Command |
|---|---|
| macOS (Homebrew) | brew install python |
| Windows (winget) | winget install Python.Python.3.12 |
| Debian / Ubuntu / Kali | sudo apt install python3 python3-pip python3-venv |
| Fedora / RHEL | sudo dnf install python3 python3-pip |
| Arch | sudo pacman -S python python-pip |
pip and venv ship with Python on Windows/macOS; on Debian/Ubuntu they're
the separate python3-pip / python3-venv packages shown above.
Each pillar only needs its own tool; install just the ones you'll use.
macOS (Homebrew):
brew install feroxbuster ffuf hashcat hydraWindows (winget):
winget install epi052.feroxbuster
winget install ffuf.ffuf
# hashcat has no winget package -- grab the portable build from hashcat.net,
# unzip it, and add the folder to your PATH:
curl.exe -L -o hashcat.7z https://hashcat.net/files/hashcat-6.2.6.7z
# (check https://hashcat.net/hashcat/ for the current version number)
# thc-hydra has no native Windows build; run it under WSL:
# wsl sudo apt install hydraDebian / Ubuntu / Kali (apt):
sudo apt install feroxbuster ffuf hashcat hydraFedora / RHEL (dnf): hashcat and hydra are packaged; feroxbuster and ffuf aren't, so install those from upstream:
sudo dnf install hashcat hydra
curl -sL https://raw.githubusercontent.com/epi052/feroxbuster/main/install-nix.sh | bash -s $HOME/.local/bin
go install github.com/ffuf/ffuf/v2@latest # or grab a prebuilt binary from ffuf's releases pageArch (pacman):
sudo pacman -S feroxbuster hashcat hydra
go install github.com/ffuf/ffuf/v2@latest # ffuf: via Go, or the AUR (yay -S ffuf)The manual: obliquity manual prints the full command reference in the
terminal on any platform (pipe to a pager: obliquity manual | less -R). On
Linux/macOS you can also install the man page for man obliquity:
man ./docs/obliquity.1 # view without installing
sudo install -Dm644 docs/obliquity.1 /usr/local/share/man/man1/obliquity.1 # installAny platform, no package manager: feroxbuster/ffuf/hashcat ship prebuilt
binaries on their release pages -- download, extract, and put them on your
PATH: feroxbuster,
ffuf,
hashcat. thc-hydra is built from source
(vanhauser-thc/thc-hydra) or run
under WSL on Windows.
From inside this repo:
python3 -m pip install -e .Or run it without installing at all:
python3 -m obliquity.cli --helpYou'll very likely need one. On recent Python installs -- Homebrew Python
on macOS, and most current Linux distros -- pip install directly into the
system Python refuses to run at all, with an externally-managed-environment
error. Even where it's allowed, installing project dependencies system-wide
is how unrelated projects end up breaking each other's package versions. A
virtual environment (venv) is just a private, disposable copy of Python +
pip scoped to this project only, so none of that happens.
python3 -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows (PowerShell: .venv\Scripts\Activate.ps1)
python3 -m pip install -e .A venv only needs activating once per terminal session -- not before
every single command. Once you source .venv/bin/activate, your prompt
gets a (.venv) prefix and obliquity/python3/pip all resolve inside
it until you close that terminal tab or run deactivate. Opening a new
terminal tab starts a fresh shell that isn't activated, so you'll need to
run the source line again there -- that's a property of terminals, not
something wrong with the venv.
Making it persistent, if re-typing source .venv/bin/activate in every
new terminal gets old, pick one:
Option A -- auto-activate with direnv (recommended if you work in this repo a lot)
brew install direnv # or your package manager
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc # or ~/.bashrc for bash
echo "source .venv/bin/activate" > .envrc
direnv allowNow the venv activates automatically the moment you cd into this
directory, and deactivates when you leave it. Nothing to remember.
Option B -- install with pipx (recommended if you just want the obliquity command, and don't care about venvs at all)
brew install pipx # or: python3 -m pip install --user pipx
pipx install --editable .pipx builds and manages its own isolated venv for you behind the scenes
and puts obliquity straight on your PATH -- no activation step, ever,
in any terminal.
Option C -- a shell alias (simplest, one line in your shell rc file)
echo "alias obliquity-env='source /path/to/obliquity/.venv/bin/activate'" >> ~/.zshrcThen just type obliquity-env in any new terminal before using the tool.
# 1. Create a project (and list all projects any time with `obliquity project list`)
obliquity project create acme
# 2. Add a host, with whatever metadata you already know
obliquity host add acme https://app.acme.com --server iis --tech aspnet
# 3. Preview the plan -- no --gameplan needed, Obliquity recommends one
# from the host's --tech/--server/--profile (aspnet-standard here)
obliquity bust plan acme
# 4. Run it
obliquity bust run acme --open-reportThat's the whole loop: project, host, plan, run, report. Everything below is what's available once you need more control.
🧪 Want to try every feature safely? The repo ships a Test Lab -- a localhost-only web/FTP/SSH/SMB target set plus hash fixtures, with a full begin-to-end walkthrough for both the regular CLI and the interactive console.
List projects, and set an active project so you stop repeating its name
on every command (like kubectl/docker contexts):
obliquity project create acme --root ~/engagements/acme # keep ALL output (runs, reports, raw) in one folder
obliquity project list # all projects + host/job/run counts; * marks active
obliquity project use acme # make acme the active project (persists)
obliquity project current # show the active project + its defaults (see below)
obliquity project unset # clear it
obliquity project archive acme --yes # back up files, drop the DB record (keeps a copy)
obliquity project delete acme --yes # PERMANENTLY delete DB records + files (no copy)project current shows the active project's root, created date, hosts (with
their profile/tech/server metadata), crack jobs, and the default gameplan
for each tool -- with (default) marking the ones still inheriting
Obliquity's built-in default rather than a value you set.
Per-project default gameplans. Instead of passing --gameplan on every
run, set a default per tool per project so it auto-applies:
obliquity project set-gameplan bust generic-deep # this project's bust default
obliquity project set-gameplan crack rules-basic # this project's crack default
obliquity project set-gameplan fuzz --clear # revert fuzz to the built-in defaultResolution precedence for a run's gameplan is explicit --gameplan >
project default > (bust only) host-metadata recommendation > built-in
fallback. An explicit --gameplan on the command line always wins.
Once a project is active, its name is optional everywhere. Resolution
precedence is explicit name > OBLIQUITY_PROJECT env var > active
project, and a Using active project: acme line prints whenever the name
wasn't given explicitly, so it's never a surprise which project a command
hit:
obliquity project use acme
obliquity bust run https://app.acme.com --gameplan generic-quick # acme implied
obliquity history # acme implied
obliquity bust run other https://x.test --gameplan generic-quick # explicit winsPrefer an msfconsole-style prompt over retyping obliquity each time? Drop
into the REPL:
$ obliquity console
obliquity(acme) > use fuzz
obliquity(acme:fuzz) > set endpoint /search
fuzz endpoint => /search
obliquity(acme:fuzz) > options
obliquity(acme:fuzz) > run --dry-run
obliquity(acme:fuzz) > back
obliquity(acme) > project current
obliquity(acme) > exit
It's a dual-mode CLI: the one-shot obliquity <command> still works
everywhere (and stays the scriptable path). In the console, every command works
without the prefix; use <tool> selects a tool so bare run/plan/resume/
set/unset/options/job/creds target it, and back deselects. The
prompt shows project:tool context. Tab-completion and command history are on
(via readline); help lists everything; exit or Ctrl-D quits. A bad
command just prints an error -- it never drops you out of the session.
If you'd rather set things up once and just run -- like msfconsole's
set/show options/run -- each tool has options you can store on the active
project. This is additive: every flag below still works on run and
overrides a stored option.
obliquity set fuzz host https://app.acme.test
obliquity set fuzz endpoint /search
obliquity set fuzz gameplan parameter-names-quick
obliquity options fuzz # 'show options': OPTION / VALUE / REQUIRED / SOURCE
obliquity fuzz run # uses the stored options -- no flags needed
obliquity unset fuzz endpoint # revert one optionset host <url> is Metasploit-style: if that host isn't in the project yet it's
added automatically (a bare hostname gets an https:// prefix). With several
hosts and none chosen, a run just uses the first one (and says so); pick
another with a URL arg or set host <url>. options bust shows the project's
host even when you haven't set one.
Precedence is explicit flag > stored option > project default > built-in
default, so obliquity fuzz run --endpoint /admin still wins for that run.
Stored options also show up in obliquity project current. Settable options per
tool: bust (host, gameplan, threads, rate, proxy), fuzz (host, gameplan,
endpoint, template, request), crack/brute (job, gameplan). gameplan is the
same value project set-gameplan manages.
# Dry-run first to see the exact feroxbuster command that will run
obliquity bust run acme https://app.acme.com --gameplan aspnet-standard --dry-run
# Run it for real
obliquity bust run acme https://app.acme.com --gameplan aspnet-standard
# Resume later -- completed stages are skipped automatically
obliquity bust resume acme https://app.acme.com --gameplan aspnet-standardThe host URL is only needed when a project has more than one host -- with
exactly one, every bust/fuzz plan/run/resume command uses it
automatically:
obliquity bust run acme --gameplan aspnet-standardRecursion control: each gameplan stage already sets feroxbuster's native recursion (it re-scans directories it finds, with the same wordlist). Override it for every stage without editing the gameplan:
obliquity bust run acme --depth 3 # force recursion depth 3 on all stages
obliquity bust run acme --no-recurse # disable recursion entirely(--depth and --no-recurse are mutually exclusive. A re-scan at a different
depth is tracked as a distinct run, so it won't be skipped as "already done".)
Response filters: cut noise by dropping responses that match a status
code, byte size, word count, line count, or a body regex (feroxbuster's
-C/-S/-W/-N/-X). Pass them on the CLI (applies to every stage) or set them
per stage in a gameplan's JSON:
obliquity bust run acme --filter-status 404,500 --filter-size 0 --filter-regex 'Not Found'A run with different filters is fingerprinted as a distinct run, so tightening filters doesn't collide with an earlier, noisier scan.
Flood detection (wildcard / soft-404): some hosts answer every path with
200 (a wildcard or soft-404), which floods a scan with junk. During a run
Obliquity watches the live results, and if one status code dominates past a
threshold it stops that stage mid-run and offers to re-run it with that
status filtered out, then continue:
! Flood detected: status 200 returned 400/400 matches -- likely a wildcard / soft-404.
Re-run this stage excluding status 200 and continue? [Y/n]
Tune or disable it with --flood-threshold N (default 250; the re-run is a
distinct, fingerprinted run) or --no-flood-guard. In non-interactive runs it
auto-re-runs filtered and says so.
Live progress: during a run each stage shows an animated bar driven by
feroxbuster's real request counter (parsed from its output over a PTY) --
percent, requests done, findings, and errors, updating as it goes. Prefer
feroxbuster's own full interactive UI? Add --ferox-ui:
obliquity bust run acme --ferox-uiEach stage then hands the terminal to feroxbuster's native display -- pinned
progress bars, scrolling results, clickable URLs, and its Scan Management Menu
(press ENTER to add a URL/filter, cancel a sub-scan, or set a scan limit) --
with the startup banner suppressed. Obliquity still prints its own stage header
before and one-line summary after each stage, so the orchestration stays
visible. Off a real terminal (piped output, the REPL) it falls back to the
one-line progress automatically.
Link extraction (discovery multiplier): feroxbuster parses every response
body (HTML, JavaScript, robots.txt, ...) for URLs and folds the ones it finds
back into the scan. This reaches paths that live in no wordlist -- an admin
console linked only from a <script>, a legacy API referenced in a bundled
.js, a report linked from the homepage. It is on by default; disable it
per run when you want a pure wordlist scan (faster, quieter, fewer requests):
obliquity bust run acme --no-extract-linksToggling it fingerprints as a distinct run. The test lab has a built-in demo:
its homepage and /assets/app.js link to deliberately obscure paths
(/reports/q4-internal-8kd.html, /dev-x9f2-console/, ...) that only turn up
when extraction is on -- run a default scan against it, then --no-extract-links,
and compare.
Extension Intelligence: appending extensions to a wordlist that already
contains them (index.php + .php -> index.php.php) just wastes requests.
Obliquity detects it and warns during bust plan/run. Inspect any wordlist
directly -- entry count, size, whether it carries extensions, and a preview:
obliquity wordlists inspect seclists-common
obliquity wordlists inspect /usr/share/seclists/Discovery/Web-Content/raft-medium-files.txtGameplan stages can also use named extension tiers instead of copy-pasting
lists: set a stage's "extensions" to "low", "medium", or "high" and
Obliquity expands it (low = common web pages; medium adds config/backup/data;
high adds archives, scripts, secrets, and more).
Host/Application Awareness: --gameplan itself is optional. From the
host metadata you set with host add, Obliquity recommends a matching
built-in gameplan instead of always defaulting to generic-quick, and
always shows why:
Selected gameplan: aspnet-standard (recommended: tech=aspnet)
The three metadata fields have distinct, non-overlapping roles (checked
tech → profile → server, then the default):
| Field | Role | Examples |
|---|---|---|
--tech |
backend language / framework | aspnet, php, java, node, python |
--profile |
application type | api, wordpress, admin-panel (default generic) |
--server |
web server software | iis, apache, nginx, tomcat |
An explicit --gameplan always wins outright, with no label.
bust finds content; fuzz is for when the interesting value belongs
inside a request -- a parameter name, a parameter value, or a field in a
raw captured request.
# List every fuzz gameplan
obliquity gameplans list
# Dry-run first to see the exact ffuf command without sending anything
obliquity fuzz run acme https://app.acme.com --gameplan parameter-names-quick --endpoint /search --dry-run
# Discover accepted GET parameter names
obliquity fuzz run acme https://app.acme.com --gameplan parameter-names-quick --endpoint /search
# Fuzz values for a known parameter
obliquity fuzz run acme https://app.acme.com --gameplan parameter-values-quick --template '/search?q=FUZZ'
# Fuzz a raw request captured from Burp (FUZZ marker inside the file)
obliquity fuzz run acme https://api.acme.com --gameplan api-request-quick --request ./request.txt
# Coverage across tools -- what's already been tried against this host
obliquity coverage acme
obliquity coverage acme https://api.acme.comhashcat cracks password hashes gathered during an engagement, staged the same way bust/fuzz gameplans are: a plain dictionary first, then the same dictionary with rules, then a mask fallback -- each stage runs only if the previous one didn't recover everything.
# Add a hash file as a crack job (plays the role a host URL plays for bust/fuzz)
obliquity crack job add acme ./dumped-hashes.txt --hash-type 1000 --name ntlm-dump
# --hash-type is hashcat's -m mode number: 0=MD5, 1000=NTLM, 1800=sha512crypt, ...
# (see `hashcat --help` for the full list)
obliquity crack job list acme
# Preview, dry-run, execute -- job name optional with exactly one job, same as hosts
obliquity crack plan acme --gameplan quick-dictionary
obliquity crack run acme --gameplan quick-dictionary --dry-run
obliquity crack run acme --gameplan standard --open-report
# Resume later -- resumes hashcat mid-keyspace from its own checkpoint
obliquity crack resume acme --gameplan standardCrackplan stages support all five common hashcat attack modes:
dictionary (-a 0), mask (-a 3), combinator (-a 1, two
wordlists glued together), and the two hybrids hybrid-wordlist-mask
(-a 6, e.g. a real word + ?d?d?d?d) and hybrid-mask-wordlist
(-a 7). See hybrid-standard for a policy-shaped example.
A hashcat exit code of
1("exhausted this wordlist/mask, hashes remain") is treated as a normal stage completion, not a failure -- that's what lets a crackplan fall through to its next stage automatically.Unlike bust/fuzz,
crack resumegenuinely resumes an interrupted stage from hashcat's own.restorecheckpoint (mid-keyspace), not just from the last completed stage.
brute (backend: thc-hydra) is the one online pillar: unlike crack
(offline hashing, no host), it makes live login attempts against a service --
web login forms, SSH, FTP, SMB, RDP, and more -- so it fits the project/host
model directly. A login job is service + target (optionally linked to a
project host); a loginplan stages credential lists the same way the others
stage wordlists. (The pillar is named for the function, like bust/fuzz/crack;
hydra is just today's backend, with medusa/ncrack as future options.)
# Add a login target as a job (the role a host URL plays for bust/fuzz)
obliquity brute job add acme 10.0.0.5 --service ssh --name ssh-box --port 22
# Web login forms need hydra's form spec (path : body-with-^USER^/^PASS^ : failure-text)
obliquity brute job add acme app.acme.test --service http-post-form --name web-login \
--form-spec "/login:user=^USER^&pass=^PASS^:F=invalid"
obliquity brute job list acme
# Preview, dry-run, execute -- job name optional with exactly one job
obliquity brute plan acme --gameplan quick
obliquity brute run ssh-box --gameplan common-creds --dry-run
obliquity brute run ssh-box --gameplan common-creds
# Review what was recovered
obliquity brute creds acmeService profiles: each service carries sensible defaults, so a job needs
almost nothing. Adding a job auto-fills the standard port (ssh→22, ftp→21,
smb→445, rdp→3389, mysql→3306, …) when you don't pass --port, and brute run
picks a service-tuned loginplan when you don't pass --gameplan:
ssh-default, ftp-default, and smb-default use service-appropriate
username lists (root/admin vs anonymous/ftp vs administrator/guest) against a
small common-password list; other services fall back to common-creds.
Precedence stays explicit --gameplan > project default > service default >
quick, and --port always overrides.
Authorization required. hydra performs live credential guessing. Only run it against systems you're explicitly authorized to test. Online guessing can trigger account lockouts, rate limits, and alerts -- keep
-t(tasks) low and prefer small, targeted credential lists. Obliquity prints this reminder on every plan/run and defaults the built-in plans to conservative parallelism.
brute resumeis stage-level (it skips already-completed stages), not mid-attack resume within a single hydra pass.
obliquity doctordoctor checks feroxbuster, ffuf, hashcat, and hydra (core), plus
gobuster/wfuzz/john (optional, for future alternate-tool support --
see Roadmap).
Not sure which wordlist a gameplan uses, or what's actually inside a list before you throw it at a target? The explorer is an interactive, scrollable browser over every built-in gameplan and every wordlist they reference (plus the download catalog):
obliquity exploreScroll the left pane (↑/↓, wrapping around at the ends; Home/End); the
right pane shows details for the highlighted item and scrolls with
PgUp/PgDn; q quits. Tool tags ([bust]/[fuzz]/[crack]/[brute]) are
color-coded and the detail pane uses the app's subtle blue/orange accents. For a
wordlist it shows length, size, whether entries already carry extensions
(and which), a head and tail sample, its description and typical use, the
gameplan(s) that reference it, and similar wordlists. For a
gameplan it shows its stages, the wordlist each uses, and the exact run
command.
It picks a TUI backend for your OS automatically: curses (stdlib) on
macOS/Linux, and Textual on Windows (pip install textual). Force one with
obliquity explore --backend {auto,curses,textual,text}, or skip the TUI
entirely with --no-tui (or OBLIQUITY_NO_TUI=1) for a plain printed listing.
With no interactive terminal (or nothing installed) it prints the overview
anyway. To inspect a single list non-interactively, use
wordlists inspect.
Loading a gameplan from the explorer: press Enter on a gameplan to set
it as your active project's default for that tool (the same as
project set-gameplan), so your next bust/fuzz/crack/brute run uses it
automatically. (Enter on a bare wordlist points you to the gameplan(s) that
include it, since Obliquity runs gameplans rather than lone wordlists.)
Typing a pillar with no subcommand -- obliquity bust, fuzz, crack,
brute -- lists that tool's built-in gameplans (a quick reminder of what you
can run).
Obliquity doesn't need the full SecLists repo -- it downloads just the
specific files its built-in gameplans reference, stored under
~/.obliquity/wordlists/. A gameplan referencing e.g.
/usr/share/seclists/... automatically falls back to the downloaded copy
if that system path doesn't exist, with no profile edits needed.
obliquity wordlists status # what's missing
obliquity wordlists setup # interactive, asks per wordlist
obliquity wordlists install seclists-common rockyou # install specific ones
obliquity wordlists install --all-missing # everything the built-ins need
obliquity wordlists list # full catalog + install statusobliquity project create checks for missing defaults and offers to
download them right there when run interactively.
rockyou is the largest catalog entry (~50MB download, ~133MB extracted)
and is only needed for crack gameplans beyond smoke-test. For anything
outside this small curated catalog -- CMS-specific lists, Assetnote's
technology-specific collections -- obliquity wordlists list prints links
to the full SecLists repo and Assetnote's site; point a custom gameplan
JSON at whatever you download, the same way --gameplan ./my-plan.json
already works.
HTML is the default/richest format; JSON, CSV, and Markdown are also available for further processing or sharing:
obliquity report html acme
obliquity report open acme # generate the HTML report AND open it in your default browser
obliquity report serve # browse EVERY project's report in your browser (local server, pick from a list)
obliquity report json acme
obliquity report csv acme --kind cracked-hashes # or: findings, runs, crack-runs, found-credentials, login-runs
obliquity report markdown acmereport open (and report html --open) open the report in your default
browser on any OS -- it uses Python's webbrowser first and falls back to
open (macOS) / start/os.startfile (Windows) / xdg-open (Linux) if that
no-ops. You can also open one automatically right after a scan:
obliquity bust run acme --gameplan generic-quick --open-reportobliquity history acme # unified log across bust/fuzz/crack
obliquity history acme --tool hashcat
obliquity history acme --status failed --limit 20One readable line per run: timestamp, tool, status, target, gameplan/stage,
finding count, duration. (obliquity runs still exists as the lower-level
bust/fuzz-only view.)
obliquity bust run acme https://app.acme.com \
--gameplan generic-quick \
--proxy http://127.0.0.1:8080 \
--header 'Cookie: session=replace-me'| Bust (feroxbuster) | Fuzz (ffuf) | Crack (hashcat) |
|---|---|---|
|
|
The |
Use a custom gameplan path instead of a built-in name, same syntax everywhere:
obliquity bust run acme https://app.acme.com --gameplan ./examples/custom-gameplan.jsonEach bust stage is fingerprinted on: target URL, gameplan name, stage name,
wordlist, extensions, recursion setting, depth, status codes, extra args.
Crack stages the same way, keyed on hash file + hash type instead of a URL,
plus attack mode/wordlist/rules/mask. A stage that completed successfully
before is skipped unless --force is used.
obliquity bust run acme https://app.acme.com --gameplan aspnet-standard --force
obliquity crack run acme --gameplan standard --forcebust resume/crack resume always skip completed stages silently --
that's their whole job. A plain bust run/crack run is different: run it
interactively against a target whose gameplan already fully completed, and
Obliquity stops before doing anything, tells you when it last finished and
what it found, and offers the next step up a small escalation ladder
(generic-quick -> generic-standard -> generic-deep,
quick-dictionary -> standard) -- accept with y. Decline that (or
there's no escalation defined yet) and it falls back to an explicit "rerun
anyway?" confirmation. This only triggers in a real interactive terminal;
scripts and --force/--dry-run runs are unaffected.
One nuance worth knowing: for
bustthis is stage-level resume, not mid-scan. feroxbuster runs with--no-state, so an interrupted stage restarts its wordlist from the beginning (findings already found aren't lost, but requests get resent); ffuf has no native checkpointing either.crackis the exception -- it resumes an interrupted stage mid-keyspace from hashcat's own.restorecheckpoint.
~/.obliquity/
Override with:
export OBLIQUITY_HOME=/path/to/workdirTextual UI demo (fake-data terminal UI playground -- doesn't run tools or touch the real database)
python -m pip install -r requirements-tui-demo.txt
python -m obliquity.tui_demo
# Minimal terminal-style experiment
python -m obliquity.tui_terminal_demo
# Posting-inspired keyboard UI experiment
python -m obliquity.tui_posting_demoArrow keys, Enter, Tab, Space, Escape, and letter shortcuts navigate workflow screens, settings, review pages, a live dashboard, tables, sparklines, and a simulated terminal stream -- all fake data, purely a UI exploration for a possible future dashboard.
Obliquity intentionally keeps the current design simple and honest about what it doesn't do yet. Roughly in the order they'd get built:
- Extension Intelligence -- avoid double-appending extensions to wordlist entries that already have one baked in
- Host/Application Awareness composition -- combine tech + intensity + auth-required into a generated stage list, instead of picking one static built-in gameplan file
- Recursive auto-follow-up discovery -- automatically queue deeper
scans against interesting discovered paths (
/admin,/backup,/api) - Project export/import -- move a project, with its full scan history, to a different machine
- Wordlist compiler/deduper (
obliquity wordlists build) -- generate deduplicated staged lists (quick,standard-delta,large-delta) - Alternate-tool backends --
gobusteras an alternative to feroxbuster,wfuzzas an alternative to ffuf,johnas an alternative to hashcat,medusa/ncrackas alternatives to hydra underbrute, selectable per run (defaulting to the current backends) -- deliberately deferred until the core pillars are solid - Burp Suite integration -- a Burp extension bridging to a local Obliquity API, so findings and requests can move in both directions
The full prioritized breakdown, including what's already built vs. what's
genuinely just an idea, lives in CHANGES.md.
This is an actively developed MVP, not yet accepting external
contributions in a structured way -- issues and ideas are still welcome.
pytest (92 tests as of this writing) covers the core adapters, resume
logic, and CLI wiring; run it with:
python3 -m pip install -e . pytest
pytest