h1

Reverse Port Forward through a SOCKS Proxy

April 2, 2015

I had a friend come to me with an interesting problem. He had to get a server to make an outbound connection and evade some pretty tough egress restrictions. Egress is a problem I care a lot about [1, 2, 3]. Beacon is a working option for his Windows systems. Unfortunately, the server in question was UNIX-based. He asked if there were a way to make the UNIX system tunnel through Beacon to make its outbound connection.

reversesocks

The first option is to look at Covert VPN. This is a Cobalt Strike technology to make a layer-2 connection into a target environment. You get an IP address that other systems can connect to and interact with. Once you have a presence in the environment, it’s possible to use native tools to setup a port forward.

I like Covert VPN, but it’s a heavy solution and depending on latency and the layer-2 controls on the pivot network, it may not make sense for a given situation. His situation required him to tunnel Covert VPN through Meterpreter, which he had to tunnel through Beacon, which was calling back to him through multiple redirectors. For this situation, I advised against Covert VPN.

So, what else can one do?

Beacon has a full implementation of the SOCKS4a protocol. Most folks associate SOCKS with outbound connections only. Did you know, it’s also possible to use SOCKS for inbound connections as well?

The SOCKS specification has a BIND command. This command creates a listening socket on the far end and binds it to a specific port. It then waits for someone to connect before it returns an acknowledgement to the SOCKS client. The BIND command was made to enable FTP data transfer to work over a SOCKS proxy.

For intellectual curiosity and to help my friend out, I wondered if we could abuse this BIND option to create a reverse port forward through a Beacon.

A lot of hackers whip out Python or Ruby for these one-off situations. Good, bad, or indifferent, I work in my Sleep language when I need to accomplish a task like this. Here’s the POC I hacked together to do a reverse port forward through a Beacon SOCKS proxy:

# reverse port forward via SOCKS BIND
#
# java -jar sleep.jar relay.sl SOCKS_HOST SOCKS_PORT forward_host forward_port

debug(7 | 34);

# relay traffic from one connection to another
sub relay {
	local('$fromh $toh $data $check $last');
	($fromh, $toh) = @_;
	$last = ticks();
	while (!-eof $fromh) {
		$check = available($fromh);

		# if there's data available.. use it.
		if ($check > 0) {
			$data = readb($fromh, $check);
			writeb($toh, $data);
			$last = ticks();
		}
		# time out this relay if no data in past 2 minutes.
		else if ((ticks() - $last) > 120000) {
			break;
		}
		# sleep for 10ms if nothing to do.
		else {
			sleep(10);
		}
	}

	# clean up!
	closef($fromh);
	closef($toh);
} 

# function to start our relay
sub start {
	local('$handle $fhost $fport $ohandle');
	($handle, $fhost, $fport) = @_;

	# connect to our desired portforward place
	$ohandle = connect($fhost, $fport);

	# create a thread to read from our socket and send to our forward socket
	fork({
		relay($handle, $ohandle);
	}, \$handle, \$ohandle);

	# read from our forward socket and send to our original socket
	relay($ohandle, $handle);
}

# parse command line arguments
global('$phost $pport $fhost $fport $handle $vn $cd $dstport $dstip');
($phost, $pport, $fhost, $fport) = @ARGV;

# connect to SOCKS4 proxy server.
$handle = connect($phost, $pport);

# issue the "bind to whatever and wait for a connection message"
writeb($handle, pack("BBSIB", 4, 2, $fport, 0xFFFFFFFFL, 0));

# read a message, indicating we're connected
($vn, $cd, $dstport, $dstip) = bread($handle, "BBSI");
if ($cd == 90) {
	println("We have a client!");
	start($handle, $fhost, $fport);
}
else {
	println("Failed: $cd");
}

To use this script, you’ll want to create a SOCKS proxy server in Beacon and task Beacon to checkin multiple times each second (interactive mode):

socks 1234
sleep 0

To run this script, you’ll need to download sleep.jar. This script accepts four parameters. The first two are the host and port of the Beacon SOCKS proxy server. The second two are the host and port you want Cobalt Strike to forward the connection to. This second port is the same port the pivot system will wait for connections on.

java -jar sleep.jar relay.sl SOCKS_HOST SOCKS_PORT forward_host forward_port

Example:

java -jar sleep.jar relay.sl 127.0.0.1 1234 192.168.95.190 22

The above example connects to the Beacon SOCKS proxy at 127.0.0.1:1234. It creates a listening socket on the pivot host on port 22. When a connection hits that socket, the relay script connects to 192.168.95.190:22 and relays data between the two connections.

This script works and it demonstrates that reverse port forwards through Beacon are possible. I haven’t tested this elsewhere, but in theory, this same script should yield reverse port forwards for other SOCKS implementations.

Be aware that the BIND option in SOCKS is designed to wait for and forward one connection only. Once a client connects to the pivot host, the listening socket is tore down.

I’ve long understood the value of reverse port forwards. Cobalt Strike has pivot listeners to expose the Metasploit Framework’s ability to relay payload connections through a pivot host. My roadmap for Cobalt Strike 3.0 calls for a turn-key way to use reverse port forwards through Beacon.

My dream is to have a Beacon on a target system inside of an environment and to allow Beacons and other agents to call back to me through this pivot host and to host my malicious goodies through this trusted pivot host. For those of us interested in adversary simulations, this is a beautiful future. Almost as beautiful of a dream as a Washington, DC February spent in Puerto Rico. Almost.

There’s a lot of user experience work and other things to sort out before either dream becomes reality. In the mean time, the base mechanism is there.

If none of this makes sense, here’s an updated diagram to clarify:

reversesocksexplained

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s