Building a Custom Captive Portal Page for BLEShark Nano
The BLEShark Nano ships with a default captive portal page - functional, clean, and generic. For most quick demos, it's fine. For a proper security awareness exercise, a targeted red team engagement, or a custom environment, you want a page that matches your scenario.
BLEShark Nano supports fully custom portal HTML. You write the page, upload it via the file portal, and the Nano serves it to every device that connects to its AP. No backend required, no server to manage. The Nano handles DNS hijacking, DHCP, and HTTP serving - your job is just the HTML.
This article covers the complete workflow: what the Nano expects from your HTML file, how form submissions are captured, practical examples, and tips for building pages that actually work on mobile browsers.
How the Portal Serving Works
When a device connects to the BLEShark' Nanos AP, the Nano's DNS server resolves every domain to the Nano's own IP. The Nano's HTTP server listens on port 80 and serves the portal page for any request to the root path (/) or any unrecognized path.
Your custom HTML file replaces the default portal template. The Nano reads your file from its filesystem and serves it verbatim. This means the page you build is the page users see - the Nano doesn't modify your HTML or inject anything into it.
The only thing the Nano handles behind the scenes is form submission routing. When a connected device submits a form to the Nano's IP, the Nano captures the POST data and stores it. Your HTML just needs to point forms at the right endpoint.
Uploading Your Custom Portal HTML
The BLEShark Nano includes a file portal - a web interface accessible over the AP or a connected WiFi network that lets you upload and download files to and from the device. This is where you upload your custom portal HTML.
To access the file portal:
- Connect your computer to the BLEShark Nano's AP (or connect both to the same WiFi network via WiFi Connect)
- Navigate to the Nano's IP (nano.place) in a browser
- Upload your HTML file as the captive portal page
The file portal also lets you download captured portal submissions (stored as portal.json), upload DuckyScript payloads, manage WiFi network credentials, upload PCAP files, and modify device settings. It's the primary interface for customizing everything about how the Nano operates.
Once uploaded, the portal page takes effect immediately - no reboot required. The Nano starts serving your HTML to the next device that connects.
graph TD
subgraph "Portal Setup"
A["Create custom HTML file"] --> B["Connect to BLEShark WiFi AP"]
B --> C["Open file portal at 192.168.4.1"]
C --> D["Upload HTML to device storage"]
D --> E["Select custom portal in menu"]
end
subgraph "Portal Serving Stack"
E --> F["BLEShark broadcasts SSID"]
F --> G["DHCP server assigns IP to client"]
G --> H["DNS server hijacks all queries"]
H --> I["HTTP server intercepts requests"]
I --> J["Serve custom HTML page"]
end
subgraph "Data Capture"
J --> K["User fills form on portal page"]
K --> L["POST submission captured"]
L --> M["Data saved to portal.json"]
M --> N["Accessible via file portal"]
end
Custom captive portal workflow - from HTML creation through serving to form data capture
Form Submission: How Captured Data Works
If your portal page includes a form, the Nano captures submitted data and stores it in portal.json on the device. You retrieve this file via the file portal later. Documentation on how to design your HTML to submit to the Nano, with examples, are listed here:
The Nano captures all submitted field names and values and appends them as a JSON object to portal.json. If you submit three times from three different devices, portal.json will contain three entries.
After a successful submission, the Nano serves a confirmation response. You can customize this behavior by including a redirect in your form handler logic, or by building your confirmation into the page using JavaScript to handle the fetch response.
For red team exercises, this system is designed for security awareness demonstrations - showing a client that submitted data goes somewhere. The BLEShark Nano captures inputs but doesn't perform any outbound exfiltration. All captured data stays on the device until you retrieve it via the file portal.
Building a Security Awareness Demo Portal
The most common use case for custom portal pages is a corporate security awareness demonstration. The goal: show employees what a convincing fake portal looks like, then reveal it's a test - building awareness rather than trapping people.
A good security awareness demo portal has a few characteristics:
- It looks plausible for the environment (generic "Company Guest WiFi" branding, not impersonating a specific real service)
- It asks for something low-stakes in the demo context (name, employee number, or just an email for "terms acceptance")
- It reveals itself as a test after submission or on the confirmation page
- It includes a brief educational note about what just happened
Documentation on how to submit JSON to the portal, with examples, are listed here:
Important: Keep Your HTML Self-Contained
This is the most common mistake when building custom portal pages: referencing external resources.
Remember that on the captive portal network, DNS is hijacked and nothing is accessible except the Nano itself. Any HTML that tries to load resources from external URLs will fail silently. This means:
- No Google Fonts (
fonts.googleapis.com- DNS hijacked, fails) - No CDN libraries (
cdn.jsdelivr.net,unpkg.com- DNS hijacked, fails) - No external images (
src="https://..."- DNS hijacked, fails) - No external stylesheets (
rel="stylesheet" href="https://..."- DNS hijacked, fails)
Everything - CSS, JavaScript, fonts, images - must be inline in the single HTML file. Use inline <style> blocks for CSS. Use inline <script> tags for JavaScript. Encode any images as base64 data URIs if you need them.
This constraint is also a useful reminder of what the portal user is experiencing: they have no internet access, only what the Nano serves them. Your page needs to work completely offline from the user's perspective.
Handling the Post-Submit Experience
After a user submits your form, the Nano acknowledges the submission. You have a few options for how to handle the user experience after that:
Option 1: Simple redirect via meta refresh. After your form submits and the Nano responds, you can use JavaScript to listen for the response and display a different section of your page.
Option 2: Build a single-page flow with JavaScript. Use a fetch() POST instead of a traditional form submit, handle the response in JavaScript, and show a thank-you section by manipulating the DOM. This gives you full control over the post-submit UX without needing the Nano to serve a separate page.
Option 3: Use the success section for the reveal. In a security awareness demo, the confirmation is the perfect moment for the educational message. After "connecting", the user sees: "This was a security test. You just submitted your details to a fake network. Here's what that means..."
Testing Your Portal Before Deployment
Before running your portal in a real exercise, test it on a device connected to the BLEShark Nano AP:
- Upload your HTML via the file portal
- Disconnect your test device from all networks and connect it to the BLEShark Nano's "captive portal" AP
- The portal should auto-open on iOS and Android (within a few seconds of connecting)
- Check that all styling renders correctly - no broken fonts, no layout issues
- Submit the form and verify the submission appears in portal.json
- Test on both iOS and Android if both will be in scope - rendering differences exist
Common issues to watch for:
- Auto-open not triggering: The OS captive portal detection fired but the redirect response wasn't correct. Check that your HTML is valid and the Nano is serving it at the root path. This could be triggered by the VPN usage.
-
Layout broken on mobile: Missing viewport meta tag. Add
<meta name="viewport" content="width=device-width, initial-scale=1.0">. -
Fonts looking wrong: External font loaded via Google Fonts that failed. Use a system font stack instead:
font-family: Helvetica, Arial, sans-serif; -
Form not submitting: Action attribute pointing to wrong endpoint. Use
action="/submit".
Portal Testing at Scale With Shiver Mesh
For environments where you want to run captive portals across multiple physical locations simultaneously, BLEShark's Shiver mesh lets you deploy up to 16 nodes (ESP-NOW, 20-50m range) and distribute commands across them. Each node can serve its own portal HTML & SSID, or you can push the same HTML to all nodes from the initializing node.
Portal JSON submissions from all nodes aggregate to all nodes, giving you a unified view of who submitted what across the entire test environment. This is the kind of distributed assessment capability that traditionally required expensive enterprise hardware - or multiple people running separate tools manually.
The Full Picture
Custom captive portal HTML on BLEShark Nano is a powerful, flexible feature with a low barrier to use. Write standard HTML, keep it self-contained, upload it, test it. The Nano handles everything else - the AP, the DHCP server, the DNS hijacking, the form capture. Your page is the entire user experience.
Used in authorized security awareness programs, it makes abstract phishing risk concrete. Used in red team engagements with a proper scope agreement, it provides realistic evidence of physical social engineering exposure. Used in CTF or training environments, it's a quick way to stand up a realistic attack scenario for students to analyze and defend against.