The WiFi Pineapple, was a device coined by the Hak5 (www.hak5.org) Team back in 2008. Originally it was a hacked Fon/Fonera AccessPoint (AP) with Karma patches applied to hostapd. Back then Digninja (Robin wood) called it Jasager (http://www.digininja.org/jasager/), it was called this because the AP software answered “Yes” to all WiFi Beacon Frames; if a WiFi client was looking for the SSID BTOpenzone the Pineapple(or Jasager) would reply “That’s Me!”, if a second WiFi client was looking for an SSID of Starbucks, again the Pineapple would reply “Thats Me!” – Thus tricking unsuspecting users/devices into associating with its private network. From this stage you could attack WiFi clients, and perfrom Man-in-The-Middle(MiTM) attacks on their interenet traffic!.
As the device was small, it was a running joke to hide it within an actual pineapple. Then the Hak5 Team discovered some novelty pineapple cocktail-cups which could house the AP board and a small battery pack (Hence the name Pineapple). Nowadays, its a chunky black Alfa AP121U with a nice sticker of an armed pineapple that looks a bit like a viking, slapped on its front cover.
The original Fon device only had a finite amount of processing power and memory, and attacks were limited, any extensive process and the watchdog process would trigger and reset the device (assuming a DoS condition was occurring). The Hak5 development Team moved onto other devices as sourcing Fon/Foneras became difficult, and eventually onto slightly more powerful APs; which brings us to the current module Mk IV. The community has since added they’re own modules, improved the interface and added extra functionality like 3G tethering and 3G USB Modem support.
Blue for the Pineapple…
So back to the main topic. We missed the small unobtrusive AP, so conducted some research on porting the Pineapple build onto a cheap small TPLink WiFi AP that costs approximately $20USD.
Our walkthrough is below, but here is the part list:
- TPLink WR703N – $20(USD)
- 4GB San Cruiser FIT USB Drive – $8(USD)
As the parts are from China/Thailand they can be cheaply acquired anywhere in the world!
This blog post is centered around version 1.5 of the TPLink WR703N. People are reporting recieving different versions upto v1.7. For version 1.6, the image below seems to corrupt or brick the device, general consensus from the comments are to use the later 12.09-rc2. Version 1.7 Attitutude adjustment is confirmed as working, however the trunk is broken… so watch this space…
The default web interface language is all in Chinese, so follow these simple instructions to flash a copy of OpenWRT (http://openwrt.org/)
- Configure your computer with a static IP address of 192.168.1.111
- Connect your computer to the TPLink with an ethernet cable and power on the TPLink through a USB cable (or USB battery)
- Browse to 192.168.1.1. Login admin:admin.
- Mouseover the left hand links to find the DateTimeCfgRpm.htm link and click
- Mouseover the expanded menu to find SoftwareUpgradeRpm.htm link and click
- Use the dialog to upload the new flash (link below) to the TPLink. It will go through a 100% status bar twice then reboot.
Openwrt attitude adjustment on squashfs root can mount an external drive as root with overlayfs.
I used the following Firmware for Version 1.5 (found on the back next to the Serial Number):
For version 1.6, the image above seems to corrupt or brick the device, general consensus from the comments are to use the later 12.09-rc2.
For version 1.7….. TBA
Preparing The USB as / (root)
Format a usb key with two partitions, ext4 and swap, install attitude adjustment squashfs, connect it to the internet (wifi client/eth0), update package lists.
Copy necessary files from flash to the new root partition:
For pivot overlay you can either use an empty new rootfs OR copy the contents of the current overlay (JFFS2) to the new rootfs (assuming the filesystem for the new external rootfs is mounted on /mnt/sda2 (swap=/dev/sda1)):
tar -C /overlay -cvf - . | tar -C /mnt/sda2 -xf -
For pivot root (”only possible as of r26109!”) you must make sure to have a complete root filesystem on the external rootfs device. One possible way to get such a system (assuming the filesystem for the new external rootfs is mounted on /mnt/sda1) is to issue
mkdir -p /tmp/cproot mount --bind / /tmp/cproot tar -C /tmp/cproot -cvf - . | tar -C /mnt/sda2 -xf - sync ; umount /mnt umount /tmp/cproot
Whole external root (pivot root)
After r26109 you can configure a non-overlay rootfs (called a whole_root extroot because the entire filesystem must be present on device, not only the changes from the SquashFS) using option target / in the config mount section for the rootfs device.
In order to set up such a whole root overlay, refer to the example below.
option is_rootfs will still work after r25787, the preferred method of configuring the extroot is
option target /overlay in the
config mount section for the rootfs device in the
config mount option target / option device /dev/sda2 option fstype ext4 option options rw,sync option enabled 1 option enabled_fsck 0
Reboot & Install Packages
You can now install whatever you want from opkg, and it all goes on the USB Drive.
For some Wifi Cracking, here’s a bunch of useful package names:
opkg install htop bash nano netcat tar openssh-sftp-client nmap tcpdump aircrack-ng kismet-client kismet-server nbtscan snort karma samba36-client elinks yafc python php5-cgi uhttpd zoneinfo-core procps
At this point you can install any additional packages you may want/need!
Installing the Hak5 Pineapple Code
The following series of instructions were performed from both a Linux and Mac OSX operating system.
Hacking the Upgrade Image
We used binwalk (https://code.google.com/p/binwalk/) to extract information about the FileSystem boundaries contained within the Hak5 Pineapples upgrade binary firmware image upgrade.bin which is obtainable from http://www.wifipineapple.com/ Direct Link to Image:Firmware-2.8.0
Below is the output of binary-walking the image file:
$ binwalk upgrade.bin DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------- 0 0x0 Squashfs filesystem, little endian, version 4.0, compression: size: 5342622 bytes, 1410 inodes, blocksize: 262144 bytes, created: Thu Jul 12 02:09:55 2012 6291456 0x600000 uImage header, header size: 64 bytes, header CRC: 0x6B09056F, created: Thu Jul 12 02:10:00 2012, image size: 890595 bytes, Data Address: 0x80060000, Entry Point: 0x80060000, data CRC: 0xF9DC8F7E, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: MIPS OpenWrt Linux-3.2.14 6291520 0x600040 LZMA compressed data (sig 3), properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 2690180 bytes
Use dd to extract the image:
Next we use the native unix tool dd, to carve out the squashFS partition:
$dd if=upgrade.bin of=pineapple.img bs=1 count=5342622 5342622+0 records in 5342622+0 records out 5342622 bytes transferred in 12.967170 secs (412011 bytes/sec)
Linux and Mac OSX have a neat program called FUSE (Filesystem in UserSpacE), which allows users to mount/edit filesystems outside of standard kernel code.
Using Squashfuse(https://github.com/vasi/squashfuse) it is incredibly easy to mount the pineapple.img, we extracted earlier. This part of the walkthrough was conducted on OSX (but can easily be replicated in Linux):
mkdir -p /Volumnes/pineapple squashfuse pineapple.img /Volumes/pineapple/
Extract the (MIPS) karma patched binaries (to save on compliation, and from having to build & patch our own binaries)
$ find /Volumes/pineapple/ -name hostapd /Volumes/pineapple//lib/wifi/hostapd.sh /Volumes/pineapple//usr/sbin/hostapd $ find /Volumes/pineapple/ -name hostapd_cli /Volumes/pineapple//usr/sbin/hostapd_cli
The copy/ssh these binaries onto the TPLink Openwrt installation.
The Pineapples Web Interface
If you followed the firmware & squashFS extraction you may continue with the following steps, or skip to the next New Opensource section….
This stage involves copying all the PHP code for the Pineapples Web interface; earlier versions were stored at /www/pineapple later versions not store the code within the images’ root /pineappple
New Opensource Method
As of the last month Sebkinne, has made the Pineapples Web Interface available as Opensource, use git to download the repository.
git clone https://github.com/WiFiPineapple/web-interface.git /pineapple
- Disable all update modules – as this will break the build, the upgrades/updates are all geared for Alfa AccessPoints so you should go through all the code removing the update/upgrade routines to avoid accidentally bricking the TPLink in the future.
- Simple disable method: remove the ‘upgrade’ folder within the ‘/pineapple’ folder.
To make this build compatible with the existing Pineapple Scripts (eg. http://wifipineapple.com/wp4.sh). You need to replace the exisitng Openwrt configurations with the ones listed below.
config dnsmasq option domainneeded 1 option boguspriv 1 option filterwin2k 0 # enable for dial on demand option localise_queries 1 option rebind_protection 1 # disable if upstream must serve RFC1918 addresses option rebind_localhost 1 # enable for RBL checking and similar services #list rebind_domain example.lan # whitelist RFC1918 responses for domains option local '/lan/' option domain 'lan' option expandhosts 1 option nonegcache 0 option authoritative 1 option readethers 1 option leasefile '/tmp/dhcp.leases' option resolvfile '/tmp/resolv.conf.auto' config dhcp lan option interface lan option start 100 option limit 150 option leasetime 12h option 'ignore' '0' list 'dhcp_option' '3,172.16.42.42' list 'dhcp_option' '3,172.16.42.1' list 'dhcp_option' '6,172.16.42.1,188.8.131.52' list 'dhcp_option' '6,172.16.42.1,184.108.40.206'
config defaults option syn_flood 1 option input ACCEPT option output ACCEPT option forward REJECT # Uncomment this line to disable ipv6 rules # option disable_ipv6 1 config zone option name lan option network 'lan' option input ACCEPT option output ACCEPT option forward REJECT config zone option name wan option network 'wan' option input REJECT option output ACCEPT option forward REJECT option masq 1 option mtu_fix 1 config forwarding option src lan option dest wan # We need to accept udp packets on port 68, # see https://dev.openwrt.org/ticket/4108 config rule option src wan option proto udp option dest_port 68 option target ACCEPT option family ipv4 # Allow IPv4 ping config rule option src wan option proto icmp option icmp_type echo-request option family ipv4 option target ACCEPT # Allow essential incoming IPv6 ICMP traffic config rule option src wan option dest * option proto icmp list icmp_type echo-request list icmp_type destination-unreachable list icmp_type packet-too-big list icmp_type time-exceeded list icmp_type bad-header list icmp_type unknown-header-type option limit 1000/sec option family ipv6 option target ACCEPT # include a file with users custom iptables rules config include option path /etc/firewall.user
config interface 'loopback' option ifname 'lo' option proto 'static' option ipaddr '127.0.0.1' option netmask '255.0.0.0' config interface 'lan' option ifname 'eth0' option type 'bridge' option proto 'static' option ipaddr '172.16.42.1' option netmask '255.255.255.0' option gateway '172.16.42.42' option dns '220.127.116.11' config interface 'wan' option ifname 'wlan0' option proto 'dhcp'
# Server configuration config uhttpd main option 'index_page' 'index.php' option 'error_page' '/index.php' # HTTP listen addresses, multiple allowed list listen_http 0.0.0.0:80 # list listen_http [::]:80 # HTTPS listen addresses, multiple allowed list listen_https 0.0.0.0:443 # list listen_https [::]:443 # Server document root option home /www # Reject requests from RFC1918 IP addresses # directed to the servers public IP(s). # This is a DNS rebinding countermeasure. option rfc1918_filter 1 # Certificate and private key for HTTPS. # If no listen_https addresses are given, # the key options are ignored. option cert /etc/uhttpd.crt option key /etc/uhttpd.key # CGI url prefix, will be searched in docroot. # Default is /cgi-bin option cgi_prefix /cgi-bin # List of extension->interpreter mappings. # Files with an associated interpreter can # be called outside of the CGI prefix and do # not need to be executable. list interpreter ".php=/usr/bin/php-cgi" # list interpreter ".cgi=/usr/bin/perl" # Lua url prefix and handler script. # Lua support is disabled if no prefix given. # option lua_prefix /luci # option lua_handler /usr/lib/lua/luci/sgi/uhttpd.lua # CGI/Lua timeout, if the called script does not # write data within the given amount of seconds, # the server will terminate the request with # 504 Gateway Timeout response. option script_timeout 60 # Network timeout, if the current connection is # blocked for the specified amount of seconds, # the server will terminate the associated # request process. option network_timeout 30 # TCP Keep-Alive, send periodic keep-alive probes # over established connections to detect dead peers. # The value is given in seconds to specify the # interval between subsequent probes. # Setting this to 0 will disable TCP keep-alive. option tcp_keepalive 1 # Basic auth realm, defaults to local hostname # option realm OpenWrt # Certificate defaults for px5g key generator config cert px5g # Validity time option days 730 # RSA key size option bits 1024 # Location option country DE option state Berlin option location Berlin # Common name option commonname OpenWrt config uhttpd pineapple list listen_http 0.0.0.0:1471 option home /pineapple option index_page index.php option 'error_page' '/index.php' # Configuration file in busybox httpd format option config /etc/config/httpd.conf option rfc1918_filter 1 # Certificate and private key for HTTPS. # If no listen_https addresses are given, # the key options are ignored. option cert /etc/uhttpd.crt option key /etc/uhttpd.key # CGI url prefix, will be searched in docroot. # Default is /cgi-bin option cgi_prefix /cgi-bin # List of extension->interpreter mappings. # Files with an associated interpreter can # be called outside of the CGI prefix and do # not need to be executable. list interpreter ".php=/usr/bin/php-cgi" # CGI/Lua timeout, if the called script does not # write data within the given amount of seconds, # the server will terminate the request with # 504 Gateway Timeout response. option script_timeout 60 # Network timeout, if the current connection is # blocked for the specified amount of seconds, # the server will terminate the associated # request process. option network_timeout 30# TCP Keep-Alive, send periodic keep-alive probes # over established connections to detect dead peers. # The value is given in seconds to specify the # interval between subsequent probes. # Setting this to 0 will disable TCP keep-alive. option tcp_keepalive 1
[PHP] zend.ze1_compatibility_mode = Off ; Language Options engine = On short_open_tag = On precision = 12 y2k_compliance = On output_buffering = Off ;output_handler = zlib.output_compression = Off ;zlib.output_compression_level = -1 ;zlib.output_handler = implicit_flush = Off unserialize_callback_func = serialize_precision = 100 ;open_basedir = disable_functions = disable_classes = ; Colors for Syntax Highlighting mode. Anything that's acceptable in ; would work. ;highlight.string = #DD0000 ;highlight.comment = #FF9900 ;highlight.keyword = #007700 ;highlight.bg = #FFFFFF ;highlight.default = #0000BB ;highlight.html = #000000 ;ignore_user_abort = On ;realpath_cache_size = 16k ;realpath_cache_ttl = 120 ; Miscellaneous expose_php = On ; Resource Limits max_execution_time = 30 ; Maximum execution time of each script, in seconds. max_input_time = 60 ; Maximum amount of time each script may spend parsing request data. ;max_input_nesting_level = 64 memory_limit = 8M ; Maximum amount of memory a script may consume. ; Error handling and logging ; Error Level Constants: ; E_ALL - All errors and warnings (includes E_STRICT as of PHP 6.0.0) ; E_ERROR - fatal run-time errors ; E_RECOVERABLE_ERROR - almost fatal run-time errors ; E_WARNING - run-time warnings (non-fatal errors) ; E_PARSE - compile-time parse errors ; E_NOTICE - run-time notices (these are warnings which often result ; from a bug in your code, but it's possible that it was ; intentional (e.g., using an uninitialized variable and ; relying on the fact it's automatically initialized to an ; empty string) ; E_STRICT - run-time notices, enable to have PHP suggest changes ; to your code which will ensure the best interoperability ; and forward compatibility of your code ; E_CORE_ERROR - fatal errors that occur during PHP's initial startup ; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's ; initial startup ; E_COMPILE_ERROR - fatal compile-time errors ; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) ; E_USER_ERROR - user-generated error message ; E_USER_WARNING - user-generated warning message ; E_USER_NOTICE - user-generated notice message ; E_DEPRECATED - warn about code that will not work in future versions ; of PHP ; E_USER_DEPRECATED - user-generated deprecation warnings ; ; Common Values: ; E_ALL & ~E_NOTICE (Show all errors, except for notices and coding standards warnings.) ; E_ALL & ~E_NOTICE | E_STRICT (Show all errors, except for notices) ; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) ; E_ALL | E_STRICT (Show all errors, warnings and notices including coding standards.) ; Default Value: E_ALL & ~E_NOTICE error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT display_errors = On display_startup_errors = Off log_errors = Off log_errors_max_len = 1024 ignore_repeated_errors = Off ignore_repeated_source = Off report_memleaks = On ;report_zend_debug = 0 track_errors = Off ;html_errors = Off ;docref_root = "/phpmanual/" ;docref_ext = .html ;error_prepend_string = "" ;error_append_string = "" ; Log errors to specified file. ;error_log = /var/log/php_errors.log ; Log errors to syslog. ;error_log = syslog ; Data Handling ;arg_separator.output = "&" ;arg_separator.input = ";&" variables_order = "EGPCS" request_order = "GP" register_globals = Off register_long_arrays = Off register_argc_argv = On auto_globals_jit = On post_max_size = 8M ;magic_quotes_gpc = Off magic_quotes_runtime = Off magic_quotes_sybase = Off auto_prepend_file = auto_append_file = default_mimetype = "text/html" ;default_charset = "iso-8859-1" ;always_populate_raw_post_data = On ; Paths and Directories ; UNIX: "/path1:/path2" ;include_path = ".:/php/includes" doc_root = "" user_dir = extension_dir = "/usr/lib/php" enable_dl = On ;cgi.force_redirect = 1 ;cgi.nph = 1 ;cgi.redirect_status_env = ; cgi.fix_pathinfo=1 ;fastcgi.impersonate = 1; ;fastcgi.logging = 0 ;cgi.rfc2616_headers = 0 ; File Uploads file_uploads = On upload_tmp_dir = "/tmp" upload_max_filesize = 2M max_file_uploads = 20 ; Fopen wrappers allow_url_fopen = On allow_url_include = Off ;from="firstname.lastname@example.org" ;user_agent="PHP" default_socket_timeout = 60 ;auto_detect_line_endings = Off ; Dynamic Extensions ;extension=ctype.so ;extension=curl.so ;extension=dom.so ;extension=exif.so ;extension=ftp.so ;extension=gd.so ;extension=gmp.so ;extension=hash.so ;extension=iconv.so ;extension=json.so ;extension=ldap.so ;extension=mbstring.so ;extension=mcrypt.so ;extension=mysql.so ;extension=openssl.so ;extension=pcre.so ;extension=pdo.so ;extension=pdo-mysql.so ;extension=pdo-pgsql.so ;extension=pdo_sqlite.so ;extension=pgsql.so ;extension=session.so ;extension=soap.so ;extension=sockets.so ;extension=sqlite.so ;extension=sqlite3.so ;extension=tokenizer.so ;extension=xml.so ;extension=xmlreader.so ;extension=xmlwriter.so ; Module Settings [APC] apc.enabled = 1 apc.shm_segments = 1 ;The number of shared memory segments to allocate for the compiler cache. apc.shm_size = 4M ;The size of each shared memory segment. [Date] ;date.timezone = ;date.default_latitude = 31.7667 ;date.default_longitude = 35.2333 ;date.sunrise_zenith = 90.583333 ;date.sunset_zenith = 90.583333 [filter] ;filter.default = unsafe_raw ;filter.default_flags = [iconv] ;iconv.input_encoding = ISO-8859-1 ;iconv.internal_encoding = ISO-8859-1 ;iconv.output_encoding = ISO-8859-1 [sqlite] ;sqlite.assoc_case = 0 [sqlite3] ;sqlite3.extension_dir = [Pdo_mysql] pdo_mysql.cache_size = 2000 pdo_mysql.default_socket= [MySQL] mysql.allow_local_infile = On mysql.allow_persistent = On mysql.cache_size = 2000 mysql.max_persistent = -1 mysql.max_links = -1 mysql.default_port = mysql.default_socket = mysql.default_host = mysql.default_user = mysql.default_password = mysql.connect_timeout = 60 mysql.trace_mode = Off [PostgresSQL] pgsql.allow_persistent = On pgsql.auto_reset_persistent = Off pgsql.max_persistent = -1 pgsql.max_links = -1 pgsql.ignore_notice = 0 pgsql.log_notice = 0 [Session] session.save_handler = files session.save_path = "/tmp" session.use_cookies = 1 ;session.cookie_secure = session.use_only_cookies = 1 session.name = PHPSESSID session.auto_start = 0 session.cookie_lifetime = 0 session.cookie_path = / session.cookie_domain = session.cookie_httponly = session.serialize_handler = php session.gc_probability = 1 session.gc_divisor = 100 session.gc_maxlifetime = 1440 session.bug_compat_42 = On session.bug_compat_warn = On session.referer_check = session.entropy_length = 0 ;session.entropy_file = /dev/urandom session.entropy_file = ;session.entropy_length = 16 session.cache_limiter = nocache session.cache_expire = 180 session.use_trans_sid = 0 session.hash_function = 0 session.hash_bits_per_character = 4 url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset=" [mbstring] ;mbstring.language = Japanese ;mbstring.internal_encoding = EUC-JP ;mbstring.http_input = auto ;mbstring.http_output = SJIS ;mbstring.encoding_translation = Off ;mbstring.detect_order = auto ;mbstring.substitute_character = none; ;mbstring.func_overload = 0 ;mbstring.strict_detection = Off ;mbstring.http_output_conv_mimetype= ;mbstring.script_encoding= [gd] ;gd.jpeg_ignore_warning = 0 [exif] ;exif.encode_unicode = ISO-8859-15 ;exif.decode_unicode_motorola = UCS-2BE ;exif.decode_unicode_intel = UCS-2LE ;exif.encode_jis = ;exif.decode_jis_motorola = JIS ;exif.decode_jis_intel = JIS [soap] soap.wsdl_cache_enabled=1 soap.wsdl_cache_dir="/tmp" soap.wsdl_cache_ttl=86400 soap.wsdl_cache_limit = 5 [sysvshm] ;sysvshm.init_mem = 10000 [ldap] ldap.max_links = -1 [mcrypt] ;mcrypt.algorithms_dir= ;mcrypt.modes_dir=
New – GitHub Repo
To make code sharing easier, we have created the following Github reposotories:
- https://github.com/PenturaLabs/web-interface With some infusions included: nmap,rickroll,dnssnarf,urlsnarf,sitesurvey,stats