My Experience With Wifi Pineapple

I had completed all of my projects at the end of December so, coming back to work I wanted to do something fun until I was bogged down with boring stuff again. My coworker handed me a Pineapple Tetra and said “go have fun.” which is exactly what I wanted to hear.

My goal was to connect the pineapple to wifi and then have users connect to my pineapple. I was going to use the AP that our team had set up and that one has a password on it. So I would need a password on my AP, as well.

Step 1. Upgrade firmware

So, I plugged the little guy in via USB (both of the little Y connectors have to be plugged in or the machine doesn’t recognize it) and connected to ​
During setup I was good and turned off the AP. I made it a client and connected via wifi to get updates, downloaded the firmware via the web interface and got it installed.

Step 2: Find documentation and get started

I looked around for documentation and found that it was SCARCE AT BEST. I searched through the forums and mostly found people complaining about documentation or that the modules are developed by 3rd parties and aren’t supported. I even found a shared Google Doc that anyone could edit, which to me was hilarious:

So, I did what every nerd does and joined their IRC channel. #pineapple

First thing I noticed was that their SSL cert was expired, so I reached out to one of the admins:

"01/06/17 10:32:21 "-!- Irssi: Join to #pineapple was synced in 0 secs
"01/06/17 10:32:45 "< kateo> Looks like IRC cert expired. Not sure who I should
be telling, foxtrot ?
--- Log closed Fri Jan 06 10:33:42 2017 

No one seemed to care.

I asked about setting up a password and got this response:

"01/06/17 16:27:31 "<@foxtrot> You can
"01/06/17 16:27:36 "< dade> its your hardware, do with it what you want (except illegal things because they are illegal)
"01/06/17 16:27:38 "<@foxtrot> edit /etc/config/wireless
"01/06/17 16:27:47 "<@foxtrot> and refer to the OpenWRT wiki on UCI


Now to connect to the Internet via wifi and also serve it up from the pineapple:

"01/06/17 17:03:39 "<@foxtrot> You have two radios, radio0 and radio1
"01/06/17 17:03:47 "<@foxtrot> or in logical names, wlan0 and wlan1
"01/06/17 17:04:04 "<@foxtrot> wlan0 is for the access point, wlan1 is for pineap and anything else
"01/06/17 17:04:35 "<@foxtrot> when you use pineap, it creates a monitor interface to use called wlan1mon, and as such the wlan1
interface is no longer available
"01/06/17 17:21:01 "< kateo> So which one would you connect to the Internet with?
"01/06/17 17:36:54 "< kateo> you mean wlan0 is for the access point as a client. and PineAP is an access point for others ..
creating a monitor interface so wlan0 would have to be for Internet..
"01/06/17 17:36:58 "< kateo> yeah yeah I think I get it
"01/06/17 17:44:09 "-!- sudormrf [sudosmurf@VHIrc-cci.9un.ku0bgi.IP] has quit [Ping timeout: 121 seconds]
"01/06/17 17:49:01 "<@foxtrot> no "01/06/17 17:49:03 "<@foxtrot> you dont get it
"01/06/17 17:49:18 "<@foxtrot> You can't use wlan0 for anything else, it does its own thing
"01/06/17 17:49:39 "<@foxtrot> you can use wlan1 for connecting to the internet, but thats not what its main purpose is
"01/06/17 17:53:10 "<@foxtrot> if you connect to the internet with wlan1, you cannot use PineAP 

So, turns out if I want to connect via wifi, I have to get a third radio. Let’s put this on the backburner.

Now, my goal is instead to just make a captive portal and serve it up. To get around the third radio problem, I just hardwired the pineapple with its Ethernet port.

Step 3: Download modules

I downloaded the modules “Evil Portal” and “PortalAuth” It looks like PortalAuth is what I’ll need to clone the portal.

It could recognize that I had a captive portal, but it didn’t seem to be able to do anything with it.

Eventually, it would bomb out and the errors didn’t make any sense, so I just ssh’d in and tried to run it manually:

/pineapple/modules/PortalAuth/api/module.php​ ​says it calls the like this: python $argString

Not knowing what the strings are, I just gave it a go python  and got the following:

root@pineapple:/pineapple/modules/PortalAuth/includes/scripts# python 
usage: [-h] --portalName PORTALNAME --portalArchive
                       PORTALARCHIVE --url URL --injectSet INJECTIONSET
                       [--injectjs] [--injectcss] [--injecthtml] [--injectphp]
                       [--stripjs] [--stripcss] [--striplinks] [--stripforms] error: argument --portalName is required

So I tried it with portalName, portalArchive and the URL that I was going to pass it.

root@pineapple:/pineapple/modules/PortalAuth/includes/scripts# python --portalName test --portalArchive
/root/portals/ --url --injectSet Blank

YAY it worked! Now to try it against the URL to my captive portal! I connected to our wifi network that had a captive portal and gave it a go. Doing that made it bomb out because of $args, unfortunately I didn’t capture the error here, I’ll circle back around and add it.

Step 4: Ditch modules

I decided instead of troubleshooting their code, I would go the manual route.

I switched over to Evil Portal and created a new one into /root/portals/Test

I then manually went to my portal and copied all of the code. Turns out there were a lot of links, pictures, stuff to agree to and some .css files I had to add. I manually went to each of those and put them in their respective directories. If you get lost, press F12 in your browser and look at the code and what it references.

I changed the all of the base href’s to match the pineapple instead of the original portal:

Now I’ve got a pretty looking portal, seems legit!

But I want to capture the form data into a file and still authorize the user, so I changed the final page before actually filling out the form to include this function:

function redirect() {
    window.location = "/captiveportal/index.php";

Make sure the variables in the POST actually match the ones in the form on your site:



And then changed the form submit button to this:

Now to do something fancy with the captiveportal..

root@pineapple:~/portals/Test# cat /www/captiveportal/index.php

You could pass the redirect, but I hardcoded it because I realized I want it to be the same thing every time. If you are doing something more dynamic, use that $redir variable instead of hardcoding it. Now I have a pretty portal and a log file to capture credentials. Please keep in mind where you save that textlog.txt file, as you might be serving it up:

And you won’t want everyone to have access to that. Go ahead and move it out of /www!

Step 5: Blend in

Now, to see what the other APs in the area looked like, I went to the Recon tab and did a scan:

I looked for MAC addresses that ran in sequence with the AP I wanted to impersonate and then went to the Networking tab and set a new MAC address:

Now to fire it up! Put your Open AP as the network you’re impersonating and Enable PineAP.

This caused some issues because all of the “Log Probes” and “Log Associations” started finding everyone with a home network and answered as an open AP on their behalf. If you don’t want to be noticed, turn those two settings off and just “Allow Associations.”

I found countless times during this when I tried to turn off the PineAP and it just DIDN’T.

If you want to force it off for any reason, I found SSHing in and killing it worked:

Next, my coworkers started to notice the difference between the real one and mine for 3 reasons:

1) This portal was faster than our actual portal

2) IP Address range is

3) URL has an IP address in it instead of our normal registration page

Because I’m still testing, I don’t want to slow it down.

I’m curious now how many people connect to the real one and put in tickets for how slow it is…

To create more confusion, I decided to change the pineapple’s default IP range.

Step 6?: Change range:

If you decide to do this, make sure you backup your configs in both ​/www​ and ​/root/portals ​because you might ruin it and have to reinstall the module.

I had to follow the code, but basically did a ​grep -r “172.16.”  . ​in ​/pineapple/modules​ and replaced all of the files to point to the new network range. I also did the same grep in ​/etc/​ and modified those files as well.

The Evil Portal itself makes IPTables calls that are hardcoded to the 172.16 network, so make sure you update all of the authorizeClients() and revokeClients() portions of the code. I’m planning to submit some code to make that dynamic for them. (If I find the time).

Step 7: Update DNS

SSH in and depending on what your pineapple range is, ​echo ‘’ >> /etc/hosts  And then ​killall -HUP dnsmasq

Make sure you update all of the base href’s from your pages and now they should see the actual URL you want to use.

Step 8: Mobilize

My phone has unlimited data, so I plugged my phone into the pineapple via USB and it can get to the Internet!

Next is to find a way to power the device with a battery. More to come, soon.

Leave a comment

You can use basic HTML tags, including <code> and <pre>.