ESP32 Marauder · Volume 8
ESP32 Marauder Firmware Volume 8 — SD Card Layout, Evil Portal Templates, and Customization
Directory tree, FAT32 constraints, beacon-spam SSID format, Evil Portal HTML authoring with per-OS bypass recipes, settings schema
Contents
1. About this volume
Vol 8 is the SD card volume. Most user customization of Marauder happens on the SD card, not in firmware rebuilds — Evil Portal HTML, beacon-spam SSID lists, wordlists for offline cracking, settings persistence. This volume documents the layout, formats, and authoring conventions for all of it.
The Evil Portal HTML authoring section (§ 5) is the largest — Evil Portal is the most operationally complex feature in Marauder and the most user-customizable. The captive-portal bypass recipes per OS (§ 5.4) are the most-asked-about content in this volume.
2. The SD-card directory tree
2.1 Standard tree (mainline)
When Marauder mainline boots for the first time with an SD card mounted, it creates the canonical directory tree:
/marauder/ ← root of all Marauder content on the card
├── pcaps/ ← packet capture output (Vol 4 + Vol 6)
│ ├── eapol_<timestamp>.pcap
│ ├── pmkid_<timestamp>.pcap
│ └── ble_<timestamp>.pcap
├── evil_portal/ ← Evil Portal user content (Vol 5 § 5)
│ ├── index.html ← the captive page (override SPIFFS bundled)
│ ├── style.css ← optional asset
│ └── logo.png ← optional asset
├── wordlists/ ← user-supplied wordlists (Vol 9 § 4)
│ ├── rockyou.txt ← typical staple — 14 MB compressed
│ └── custom_<engagement>.txt
├── beacons.txt ← beacon-spam SSID list (§ 4)
├── creds.txt ← captured Evil Portal credentials (Vol 5 § 5.4)
├── evil_portal.log ← Evil Portal connection events
└── settings.txt ← runtime settings (§ 6)
Standalone files (not under any subdirectory):
beacons.txt— SSID list for beacon spamcreds.txt— credential capture logevil_portal.log— connection/disconnect eventssettings.txt— runtime config
Files written by Marauder are append-only (creds.txt, evil_portal.log) or rewritten in full (settings.txt). User-edited files (beacons.txt, evil_portal/index.html) are read-only from Marauder’s perspective.
2.2 Fork-specific additions
| Fork | Additional directories | Notes |
|---|---|---|
| Mainline | (none beyond § 2.1) | The baseline tree |
| Ghost ESP | /marauder/airtags/, /marauder/ble_spam/ | AirTag detection logs + BLE-spam-payload customization |
| Bruce | /Bruce/ parallel root with sub-GHz / IR / RFID subdirs | Bruce uses its own /Bruce/ root; the /marauder/ tree co-exists for Marauder-class features |
| Bad Pinguino | Subset of mainline tree | Only pcaps/ and settings.txt typically |
Cross-fork migration (Vol 7 § 8) preserves the /marauder/ tree. Fork-specific additions remain on the card as inert directories after switching forks — harmless.
3. SD card formatting requirements
FAT32 mandatory. ExFAT is explicitly not supported — Arduino-ESP32’s SD.h driver does not include exFAT support in default builds, and Marauder ships against the default. NTFS, ext4, and other filesystems are likewise unsupported.
Card size and cluster size:
| Card size | FAT32-spec status | Marauder verdict |
|---|---|---|
| 1-2 GB | Native FAT32 / FAT16 — fine | ✓ |
| 4 GB | FAT32 native — fine | ✓ (the cheapest viable card) |
| 8-32 GB | FAT32 native — sweet spot | ✓ recommended |
| 64 GB | Above FAT32 spec — formatter dependent | Works if formatted FAT32 on host with appropriate cluster size; manufacturer’s exFAT-by-default format won’t work |
| 128-256 GB | Same as 64 GB | Same |
| > 256 GB | Practical FAT32 limit | Not recommended; cluster size grows large, performance degrades |
Speed class:
- Class 10 / U1 minimum (10 MB/s sustained write) — sufficient for any Marauder capture
- U3 / V30 / faster — no benefit; SPI bus is the bottleneck (~2 MB/s peak)
Pre-formatting on host:
Format the card before inserting into Marauder. Windows’ built-in formatter handles up to 32 GB as FAT32 natively; for larger cards, use a third-party formatter (Rufus, EaseUS, or the SD Association’s SD Card Formatter tool with the “Overwrite” option). Mac and Linux can format any size as FAT32 via the terminal:
# Linux:
sudo mkfs.vfat -F 32 /dev/sdX1
# Mac (via Disk Utility GUI is simpler; CLI:)
diskutil eraseDisk FAT32 MARAUDER MBRFormat /dev/diskN
Recovery from “no SD card detected”:
Marauder’s first-boot directory creation only fires if the card is detected. If the SD slot reports no card and the card is physically inserted:
- Try a known-good card (4 GB FAT32 class-10) to rule out card vs slot issue.
- Check Marauder serial output (USB) —
SD mount failedmessages appear if the card is detected but unmountable. - Re-format on host; ensure FAT32 not exFAT.
- If the slot has hardware issues (loose contacts), a microSD-to-microSD spring-mount adapter rarely helps — replace the host hardware.
4. Beacon-spam SSID list format
/marauder/beacons.txt carries the SSID list for beacon-spam attacks (Vol 5 § 3.3). Format:
- One SSID per line.
- UTF-8 encoding. Emoji and non-ASCII characters work; multi-byte UTF-8 sequences count against the 32-byte SSID limit.
- 32-byte SSID hard limit per line. The 802.11 SSID-length field is 1 byte (255 max value) but Marauder truncates to 32 bytes per long-standing IEEE convention. Lines exceeding 32 bytes are silently truncated; ASCII users are fine up to 32 characters.
- Comment lines start with
#and are skipped at parse time. - Empty lines are skipped.
- Maximum total entries: ~500-1000 depending on host hardware (PSRAM-equipped S3 hosts more; classic-ESP32 hosts less). Exceeding the limit silently truncates the list.
Example beacons.txt:
# Marauder beacon-spam custom list — 2026-05-13
# One SSID per line, 32-byte UTF-8 max
#
# Rick Roll classics
Never Gonna Give You Up
Never Gonna Let You Down
Never Gonna Run Around
Rick Roll Free WiFi
#
# Corporate-impersonation pretexts (use only on authorized engagements)
Conference_Guest
Hotel_WiFi
Free_Airport_WiFi
Starbucks_WiFi
#
# Emoji (each emoji is ~4 bytes UTF-8 — so ~7 emoji per line max)
🎶 Rick Roll 🎶
📡 Free WiFi 📡
Marauder reads beacons.txt at attack-start; runtime changes to the file are not picked up until the attack stops and restarts. To switch between lists during an attack: stop, swap the file, restart.
Multi-list switching pattern: keep multiple files on SD (beacons_rickroll.txt, beacons_pretexts.txt, beacons_random.txt) and either edit settings to point at the right one (some forks support this) or rename the active file to beacons.txt on the host before insertion.
5. Evil Portal HTML authoring
5.1 File priority and locations
Marauder looks for Evil Portal content in priority order:
/marauder/evil_portal/index.htmlon the SD card (preferred) — overrides everything./data/index.htmlin the firmware’s SPIFFS / LittleFS partition — fallback when no SD content.
When the SD content is present, the SPIFFS bundled version is ignored entirely — Marauder doesn’t fall back per-asset. If your custom page references style.css and you only have index.html on SD, the style won’t load (the SPIFFS bundled style.css is unreachable in mixed-mode).
Always put the full asset set on SD when overriding — index.html plus any CSS, JS, images. Place them in /marauder/evil_portal/ and reference them relatively from the HTML.
5.2 Form structure and field naming
The minimum viable Evil Portal HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Network Sign-In</title>
</head>
<body>
<h2>Sign in to continue</h2>
<form action="/get" method="get">
<label>Email: <input type="email" name="email" required></label><br>
<label>Password: <input type="password" name="password" required></label><br>
<button type="submit">Connect</button>
</form>
</body>
</html>
Critical details:
action="/get"andmethod="get"— Marauder logs URL query parameters. The form fields end up as[email protected]&password=hunter2in the GET request, which Marauder parses out of the URL.- Newer mainline builds also support
method="post"withaction="/post". POST is preferred for credentials (doesn’t expose them in URL access logs). - Field
nameattributes become the keys in/marauder/creds.txt. Match field names to what makes sense in the engagement report. - Required fields prevent empty submissions; not strictly necessary but reduces noise in the cred log.
Beyond email + password:
Add whatever fields the pretext calls for — phone number, room number, employee ID, conference badge code. Marauder logs all of them.
5.3 Asset bundling (CSS / JS / images)
Static assets go alongside index.html in /marauder/evil_portal/. Reference them relatively:
<link rel="stylesheet" href="style.css">
<img src="logo.png" alt="Company">
<script src="app.js"></script>
Marauder’s HTTP server (Vol 5 § 5.1) serves any file requested under the captive AP. Asset paths resolve relative to the request URL — /style.css is served from /marauder/evil_portal/style.css.
Size guidance:
- Keep total page (HTML + CSS + JS + images) under 64 KB. Smaller is faster — captive-portal sheets display the page incrementally; large pages render visibly slowly on iOS captive sheets.
- Avoid external CDN references — they won’t resolve (DNS spoof points everything to Marauder; Marauder doesn’t have the CDN content). Bundle everything locally.
- Inline CSS / small JS rather than separate files when possible — fewer HTTP round-trips on resource-constrained mobile captive sheets.
5.4 Per-OS captive-portal bypass recipes
(See Vol 5 § 5.2 for the underlying detection mechanism.)
Default behavior — Marauder serves index.html to every URL. iOS / Android / Windows captive sheets pop, showing the page directly. Effective for attended attacks where the user immediately interacts.
Recipe A — Suppress iOS captive sheet (stealthy long-duration capture):
iOS tests with captive.apple.com/hotspot-detect.html. To suppress the sheet, serve the Apple-expected success page to that exact URL:
In /marauder/evil_portal/index.html, do not change anything. The trick is to configure Marauder to serve the Apple success page at /hotspot-detect.html (the URL iOS specifically tests). Some forks expose this as a setting; mainline does not directly.
For mainline operators, the workaround: edit the firmware’s HTTP handler to add a path-routing exception. This requires a rebuild (Vol 10). For Ghost ESP, there’s a settings toggle.
Apple’s expected success body:
<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>
When iOS gets this, it considers the network “open” and doesn’t pop the captive sheet. The user must manually navigate to the captive page (e.g., open Safari and hit any URL) to see it.
Use case: sustained capture in venues where you want devices to stay-connected-quietly until users actively need a URL.
Recipe B — Suppress Android sheet (HTTP 204 short-circuit):
Android tests with connectivitycheck.gstatic.com/generate_204 and expects HTTP 204. Serve HTTP 204 (no content) to that exact URL.
Same caveat as iOS — requires firmware-level routing exception or fork-specific setting. Implementation effort similar to Recipe A.
Use case: mixed-OS environment where you want Android devices to stay quiet alongside iOS handling above.
Recipe C — Serve different pages per User-Agent (advanced):
Some Evil Portal forks expose User-Agent-based template selection. Useful when you want OS-specific pretexts (e.g., “Apple ID required” on iOS users, “Microsoft account login” on Windows users). Mainline doesn’t support this; community templates implement it in JavaScript on the client side (detect user agent → redirect to template HTML).
Implementation is fragile (UA strings change) but raises engagement quality.
5.5 Common pretext templates
Common Evil Portal pretexts the community ships:
| Pretext | When applicable | Field names typically captured |
|---|---|---|
| Generic “Wi-Fi sign-in” | Most common — works in most public Wi-Fi contexts | email, password |
| Hotel check-in | Hospitality venues | room_number, last_name, password |
| Conference reg | Tech conferences | email, badge_code |
| ISP / cable-modem login | Residential | username, password |
| Corporate Wi-Fi pretext | Office buildings | employee_id, password |
| Captive-portal terms of service | Low-engagement; click-to-accept variant | (no creds — operational signal only) |
| Apple ID phishing variant | Apple-heavy events | apple_id, password, verification_code |
| Microsoft account variant | Corporate Windows-heavy environments | email, password, mfa_code |
Templates ship in the Marauder repo’s data/ directory (browse github.com/justcallmekoko/ESP32Marauder/tree/master/data) and in the Ghost ESP / Bruce equivalents. Community-contributed templates also live on dedicated GitHub repos — search “Evil Portal HTML template”.
5.6 Size constraints
- Total
index.html+ bundled assets: keep under 64 KB. Faster render on captive sheets. - Single asset file: keep under 16 KB. Larger files block the page load.
- Total
/marauder/evil_portal/directory: keep under 1 MB. Beyond this, SD-card seek time on the SPI bus becomes a UX problem.
For high-fidelity engagements (real-looking corporate branding, logos, polished CSS), the budget is tight. Use SVG for logos instead of PNG (smaller, scales well); inline CSS rather than separate files; minify HTML/JS.
6. Settings.txt schema
/marauder/settings.txt is a simple key:value text file Marauder loads at boot and rewrites when settings change in the menu UI.
Format:
- One key:value pair per line
- No quotes around values
- Whitespace around
:is not tolerated —key:valuenotkey : value - Empty lines and lines starting with
#are skipped - Unknown keys are silently ignored (forward-compatibility with newer firmware)
- Values are parsed by type based on the key — strings, integers, booleans (
true/false)
Documented keys (mainline at v1.12.x):
| Key | Type | Default | Notes |
|---|---|---|---|
EvilPortalSSID | string | ”Marauder” | SSID Evil Portal advertises |
ChannelHop | int | 1 | Hop interval in 100 ms units; 0 = static |
StaticChannel | int | 6 | Channel for static-channel mode |
Brightness | int (0-100) | 75 | TFT backlight |
ColorTheme | int (0-3) | 0 | Display color palette |
Country | string | ”US” | Channel-plan region (some forks only; mainline is build-time) |
RandomMAC | bool | true | Randomize source MAC for attacks |
GPSEnabled | bool | false | Activate GPS module (only relevant on HAS_GPS builds) |
Example /marauder/settings.txt:
# Marauder runtime settings
EvilPortalSSID:CompanyGuest
ChannelHop:0
StaticChannel:6
Brightness:60
ColorTheme:1
RandomMAC:true
Cross-fork delta:
- Ghost ESP adds keys for runtime country code, runtime beacon-rate, BLE-spam variant selection, AirTag-detect filter thresholds.
- Bruce’s settings file is in a different format entirely (key=value rather than key:value, and namespaced by module).
Migration tip: don’t blindly copy settings.txt from mainline to Bruce — re-do settings from the menu UI on Bruce after migration.
7. Cross-fork SD compatibility
(See also Vol 7 § 8.)
| File | Mainline | Ghost ESP | Bruce | Notes |
|---|---|---|---|---|
pcaps/*.pcap | ✓ | ✓ | ✓ | Standard link-type-105 format; identical |
evil_portal/index.html | ✓ | ✓ | (uses /Bruce/portal/) | Path differs on Bruce |
beacons.txt | ✓ | ✓ | ✓ | Same format; Ghost ESP supports more entries |
wordlists/*.txt | ✓ | ✓ | ✓ | Plain text |
creds.txt | ✓ (csv) | ✓ (csv) | ✓ (different field order) | Format compatible at parse-line level |
evil_portal.log | ✓ | ✓ | ✓ | Plain text log |
settings.txt | Native | Compatible + extra keys | Incompatible | Bruce uses different format |
The migration recipe:
- Backup
/marauder/to host. - Flash the new firmware (Vol 7 § 8.3).
- Reinsert SD; let new firmware create any missing directories.
- Restore your customizations (
beacons.txt,evil_portal/index.html). - Re-do settings in the menu UI — don’t trust the carried-over settings.txt.
8. Wordlists and cred-log housekeeping
/marauder/wordlists/ is for host-side tools, not Marauder itself — Marauder doesn’t crack passwords on-device. The wordlists live with the captures for portability (you carry the SD card to your laptop and run hashcat against wordlists/rockyou.txt against pcaps/eapol_*.pcap).
Staple wordlists:
rockyou.txt— the all-purpose 14 MB list. Pre-2010 leak. Top-10K-most-common passwords still hit a substantial fraction of consumer Wi-Fi.darkc0de.txt— alternative classic.- Custom engagement-specific lists — generated from target-organization name, employee names, location names, common phrases.
creds.txt housekeeping:
- Append-only from Marauder’s perspective. Manual rotation is operator’s job.
- After every engagement: extract
creds.txtto host, hash (sha256), securely delete from SD before next deployment. - Don’t ever ship
creds.txtover the network in plain text — it’s plaintext credentials. Encrypt before any transfer.
9. Backup, transfer, and chain-of-custody
For engagement-deliverable workflows, the SD card carries plaintext credentials and personally-identifiable data. Chain-of-custody discipline:
At capture-time (in the field):
- Photo the SD card in situ with a known timestamp source (your phone clock) before removal — provenance metadata.
- Power down Marauder cleanly before SD removal (don’t pull during a write).
- Place SD in a labeled physical envelope or sealed container; note collection time + location.
At transfer:
-
Hash the SD contents immediately on the receiving host:
cd /mnt/sd_marauder find . -type f -exec sha256sum {} \; > /tmp/marauder_capture_<engagement>.sha256 -
Verify the hash file on a separate host before delivery.
-
Encrypt the SD contents at rest: tar + age / gpg for archive transfer.
At engagement close:
-
Sanitize SD card — secure-erase by writing random data over the entire card multiple times. Linux:
sudo dd if=/dev/urandom of=/dev/sdX bs=4M status=progress # Repeat 2-3 times for thoroughness sudo mkfs.vfat -F 32 /dev/sdX1 -
Mac / Windows: equivalent tools (Disk Utility’s “Erase + Most Secure”, Rufus’ wipe option).
-
Document the sanitization in the engagement report.
Don’t:
- Don’t transfer
creds.txtover unencrypted channels (email, Slack, plaintext HTTPS without strong identity verification). - Don’t keep
creds.txton the SD past the engagement-deliverable date. - Don’t share SD cards between engagements without sanitization in between.
Reference: ../../../_shared/legal_ethics.md for the broader Hack Tools posture on captured data.
10. Resources
Upstream
- Marauder wiki — SD card setup: https://github.com/justcallmekoko/ESP32Marauder/wiki
- Marauder
data/directory (built-in Evil Portal templates): https://github.com/justcallmekoko/ESP32Marauder/tree/master/esp32_marauder/data
Evil Portal templates community
- “Awesome Evil Portal Templates” repos — search GitHub
- Ghost ESP
data/directory: https://github.com/Spooks4576/Ghost_ESP/tree/main/data
FAT32 tools
- SD Card Formatter (SD Association): https://www.sdcard.org/downloads/formatter/
- Rufus (Windows): https://rufus.ie/
mkfs.vfat(Linux dosfstools): standard package
Wordlists
- SecLists (the catalogue): https://github.com/danielmiessler/SecLists
- rockyou.txt (standard from Kali / various mirrors)
Forward references in this series
- Capture analysis pipeline (post-SD-card workflow): Vol 9
- Build toolchain (for firmware-level Evil Portal customization): Vol 10
- Operational posture / chain-of-custody full treatment: Vol 11 § 7
This is Volume 8 of a twelve-volume series. Next: Vol 9 covers the host-side analysis pipeline — pcap → Wireshark / tshark / scapy / hashcat / aircrack-ng / bettercap. What to do with the captures once they’re off the SD card.