By placing the configuration settings on a USB, we can dynamically change how the system boots. If necessary, we can send the client replacement files via email. This is critical if things don’t work after the device has already been deployed and we are still not able to connect. We can also use this functionality if we need to test multiple VLANs during a single engagement.
The settings that we will dynamically control include the following:
- Network settings
- Default gateway
- Proxy settings
- Authentication (Basic/NTLM)
First let’s locate where the partition on the USB drive that we labeled ‘USB’ is mounted.
mount | grep USB
You should see something like the following.
/dev/sdb1 on /media/root/USB type vfat (rw,nosuid,nodev,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=utf8,shortname=mixed,showexec,utf8,flush,errors=remount-ro,uhelper=udisks2)
In the above case the mount point would be /media/root/USB
Now we need the ID of the vfat partition (/dev/sdb1).
ls -l /dev/disk/by-id | grep -w sdb1
You should see something similar to the following.
lrwxrwxrwx 1 root root 10 Sep 13 19:51 usb-SanDisk_Ultra_Fit_4C530146140423118490-0:0-part1 -> ../../sdb1
With that information we can now automount the partition without root logging in by adding the following to fstab.
/dev/disk/by-id/usb-SanDisk_Ultra_Fit_4C530146140423118490-0:0-part1 /media/root/USB vfat defaults 0 0
Now let’s create our example config files (some of these will look familiar from our work with tunnels).
If the RIPT Server will be using DHCP in the client environment then the configuration is easy; it’s one line of code.
nmcli con add con-name ript ifname eth0 type ethernet
If we need to assign the RIPT Server a static IP address then we take the information the client gives us and create a configuration file similar to the following.
nmcli con add con-name ript ifname eth0 type ethernet ip4 192.168.1.67/24 gw4 192.168.1.1 nmcli con mod ript ipv4.dns 18.104.22.168 nmcli con mod ript +ipv4.dns 22.214.171.124
If we have a direct connection out to the Internet then we will create the following config file for our SSH tunnels. This is exactly what we used in our previous configuration to test our tunnels.
Note: This is assuming RIPT Server 01. Modify for 02, 03, 04…by changing the IdentityFile and RemoteForward ports accordingly.
Host ript* HostName localhost AddressFamily inet User ript-relay Port 22 IdentityFile /root/.ssh/ript-01.id_rsa ProxyCommand /usr/bin/ncat --ssl-verify <FQDN of RIPT Relay> 443 ServerAliveInterval 10 ServerAliveCountMax 3 ExitOnForwardFailure yes StrictHostKeyChecking yes UserKnownHostsFile /root/.ssh/known_hosts Host ript-ssh-tunnel RemoteForward 11095 localhost:22 Host ript-vnc-tunnel RemoteForward 11096 localhost:5901 Host ript-squid-tunnel RemoteForward 11097 localhost:3128 Host ript-socks-tunnel RemoteForward 11098 localhost:9999 Host client HostName localhost AddressFamily inet User root Port 22 IdentityFile /root/.ssh/ript-01.id_rsa LocalForward 9999 192.168.1.69:3306 ServerAliveInterval 10 ServerAliveCountMax 3 ExitOnForwardFailure yes NoHostAuthenticationForLocalhost yes
If we have to go through an outbound proxy then we will use the following config file for our SSH tunnels. Note that ncat ostensibly supports proxies, but would not create a connection to the HAProxy. I think it may have something to do with the CONNECT directive. No worries, though, as proxytunnel works just fine. Unfortunately, proxytunnel doesn’t support certificate checking by default. There is a fork by yarinb (https://github.com/yarinb/proxytunnel) if you want to pursue that. I’m not too concerned as it only affects connections where we’re using an outbound proxy and even if an attacker performs a MitM on our SSL/TLS connection we’re still performing strict host key checking on the SSH server. The certificate verification is honestly probably overkill.
Note: Again, this is assuming RIPT Server 01. Modify for 02, 03, 04…by changing the IdentityFile and RemoteForward ports accordingly.
Host ript* HostName localhost AddressFamily inet User ript-relay Port 22 IdentityFile /root/.ssh/ript-01.id_rsa ProxyCommand /usr/bin/proxytunnel -v -p 192.168.1.69:3128 -P pentester:squidward -d <FQDN of RIPT Relay>:443 -e ServerAliveInterval 10 ServerAliveCountMax 3 ExitOnForwardFailure yes StrictHostKeyChecking yes UserKnownHostsFile /root/.ssh/known_hosts Host ript-ssh-tunnel RemoteForward 11095 localhost:22 Host ript-vnc-tunnel RemoteForward 11096 localhost:5901 Host ript-squid-tunnel RemoteForward 11097 localhost:3128 Host ript-socks-tunnel RemoteForward 11098 localhost:9999 Host client HostName localhost AddressFamily inet User root Port 22 IdentityFile /root/.ssh/ript-01.id_rsa LocalForward 9999 192.168.1.69:3306 ServerAliveInterval 10 ServerAliveCountMax 3 ExitOnForwardFailure yes NoHostAuthenticationForLocalhost yes
In the above we are connecting to the client’s proxy server at 192.168.1.69 on port 3128 using Basic Auth as the user “pentester” with the password “squidward” and establishing a connection to our RIPT Relay. For more information on proxytunnels or how to authenticate using NTLM instead, you can RTFM (http://proxytunnel.sourceforge.net/usage.php)
Finally, we’ll import the authorized_keys file. This will be the public key from your RIPT Client. This is important if we lose access to our private key or if a consultant becomes unavailable and we need to grant access to another tester.
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAkr4DSPepiL5adKD0n3f9CLmOjOEDO5UrfQsZkUihh8Sf9G7UQk42ohQSljssThE41CEk9yiyd+z+Kw6/LePGyAn6MTcr2jDYC24w8ZC380ItOatsjQSem1dWycjqjk4zBxkpFBEKCcYJ4Z/wtPcQTgBPVQoxbUU9hf6iVwi6HJq6prrMktBtP4mW41vtd1gBJJ6ff+2+7W7JcB72LEf3nMEqO2WrA/ekqC2oP+70rnDQlK8zKDrBb01pazJcPE/O0nawmZBrywyH1teZIUVevEiIFsC7gNmNXK3K+RzzDozPLCRuV5zGkHN+a7zFyiF0K6RmiFyo/w6NKSrgPQ/2SQ== ript_client
As we run commands from the config files as root, we have to encrypt everything!
If an attacker tries to replace a gpg encrypted config file with a direct command, e.g., cat /etc/shadow, then it will produce the following error message:
gpg: no valid OpenPGP data found. gpg: decrypt_message failed: eof
If the attacker tries to gpg encrypt a command with a random passphrase/key, then it will produce the following error message:
gpg: decryption failed: bad key
So, let’s encrypt all of our example config files and place them in a subdirectory of the config directory. The gpg passphrase can be anything you want. We will use the same passphrase in our script files to decrypt the configs. Note, I’ve used one passphrase for the dhcp/static files, another passphrase for the direct/proxy files, and yet another passphrase for authorized_keys, but you can use the same for all.
gpg -c example-network-dhcp.conf gpg -c example-network-static.conf gpg -c example-connection-direct.conf gpg -c example-connection-proxy.conf gpg -c example-authorized-keys.conf mkdir /root/configs/gpg/ mv *.gpg /root/configs/gpg/
Let’s put some encrypted configuration files on the USB drive.
mkdir /media/root/USB/configs/ cp /root/configs/gpg/example-network-dhcp.conf.gpg /media/root/USB/configs/network.conf.gpg cp /root/configs/gpg/example-connection-direct.conf.gpg /media/root/USB/configs/connection.conf.gpg cp /root/configs/gpg/example-authorized-keys.conf.gpg /media/root/USB/configs/authorized.conf.gpg
Now we’ll write the scripts that will process those configs.
Configure the Network
This will delete the connection ‘ript’ if it already exists, otherwise there will be multiple like named connections and that just gets ugly. It will also decrypt the network config file and setup the new ‘ript’ connection.
#!/bin/bash CONF=$(gpg --decrypt --passphrase=<PASSPHRASE> -q /media/root/USB/configs/network.conf.gpg) nmcli connection delete id ript sleep 5 while read -r command; do $command sleep 5 done <<< "$CONF" nmcli con up ript
Configure the Outbound Connection
This will create our SSH config file and restart all of our tunnel services to use the new configurations.
#!/bin/bash CONF=$(gpg --decrypt --passphrase=<PASSPHRASE> -q /media/root/USB/configs/connection.conf.gpg) echo "$CONF" > /root/.ssh/config sleep 5 service ript-ssh-tunnel restart sleep 5 service ript-vnc-tunnel restart sleep 5 service ript-squid-tunnel restart sleep 5 service ript-socks-tunnel restart
Import the Authorized Keys
This will overwrite the existing authorized_keys.
#!/bin/bash CONF=$(gpg --decrypt --passphrase=<PASSPHRASE> -q /media/root/USB/configs/authorized.conf.gpg) echo "$CONF" > /root/.ssh/authorized_keys sleep 5
We’ll now add all of these scripts to a master script that will run on boot.
Script of Scripts
#!/bin/bash sleep 60 /root/scripts/auth.sh sleep 5 /root/scripts/netset.sh sleep 10 /root/scripts/connection.sh
Make all of the scripts executable.
chmod 700 /root/scripts/*.sh
To have the launcher script run at boot add it to crontab.
Add the following line to the end and save.
The encrypted configs we uploaded in the example above will configure the RIPT Server for a direct connection to the Internet via DHCP and allow connections with the RIPT Client’s private key.
Reboot and see if things come up as expected. We could now jump right into remote control, but first we’ll do some logging and troubleshooting in the next section.