Skip to main content

SSL Relay Proxy: A Creative Solution to a Complex Issue

May 14, 2012

SSL Relay Proxy 1

I ran into a situation recently where I needed an SSL interception proxy. I was testing a thick client that spoke with a server (not HTTP) over SSL. I couldn't find anything on the Internet about a female-to-male (relay) non-HTTP SSL proxy. The situations where an SSL interception/relay proxy would be useful are fairly slim, but so are things that I can't find anything about on the Internet, so here you go.

The Restrictions

I didn't have the private key, and I was in an environment that wouldn't allow me to use any tools except BackTrack and Windows (which the client was running). I also could not actively man-in-the-middle the traffic (e.g., ARP Poison). The only things going for me were that I could tell the app what server to use and that the app was not validating the SSL certificate.

Dead Ends

A lot of tools assume that the traffic will be MITM'd (ettercap, SSL sniff), so packet forwarding just needs to be enabled and it will get to its destination. My iptables skills were probably limiting me, but I wasn't able to get the traffic routed to the server and get my backtrack box to see it. There may be a way to do this, but I couldn't figure it out. Iptables gets hard quickly (for me at least). I tried NCAT and Open SSL, but neither of them allow multi-thread connections -- basically they are only good for one TCP session. So, everything would be fine until the second TCP session decided to ruin things. NCAT has a "keep open" mode, but it never closes the output stream, so the client program would hang because it's waiting for the TCP session to close.

The Solution

Finally, I tried using stunnel, which is multi-threaded and would take care of the SSL striping, then a second instance would re-add SSL to keep the server happy. To get that working, I'd use two configuration files, one to bring it in, strip SSL and drop it on a port, then another to pick it up on a listening port and replay the traffic over SSL to the server. Yes, we'll need something in-between those two to actually log the traffic. More on that later. Here are the configuration files I ended up using. I also generated an SSL cert to be used (stunnel.pem, self-signed of course).

Generate stunnel.pem Certificate

openssl req -new -x509 -days 365 -nodes -out stunnel.pem -keyout stunnel.pem


client = no

debug = 3

foreground = yes

#chroot = /var/run/stunnel

#setuid = nobody

#setgid = nobody

pid = /

cert= ./cert.pem


accept = 3800

connect = 3801


client = yes

debug = 3

foreground = yes

#chroot = /var/run/stunnel

#setuid = nobody

#setgid = nobody

pid = /

cert= ./stunnel.pem


#change to 3801 to just relay the traffic without using the ruby tunnel

accept = 3802

#this is where the server is listening

connect =

The Logger

So everything is complete at this point, except we have to get the traffic logged, which is why we left the gap between ports 3801 and 3802. I got pretty far on a ruby proxy, but when I was working on the multi-threading, I found one that did exactly what I needed here by Amnon. Ruby threading is beautiful, by the way. I only added two lines, one to dump each "direction" of data to the console.

require 'socket' if ARGV.length < 1 $stderr.puts "Usage: #{$0} remoteHost:remotePort [ localPort [ localHost ] ]" exit 1 end $remoteHost, $remotePort = ARGV.shift.split(":") puts "target address: #{$remoteHost}:#{$remotePort}" localPort = ARGV.shift || $remotePort localHost = ARGV.shift $blockSize = 1024 server =, localPort) port = server.addr[1] addrs = server.addr[2..-1].uniq puts "*** listening on #{addrs.collect{|a|"#{a}:#{port}"}.join(' ')}" # abort on exceptions, otherwise threads will be silently killed in case # of unhandled exceptions Thread.abort_on_exception = true # have a thread just to process Ctrl-C events on Windows # (although Ctrl-Break always works) { loop { sleep 1 } } def connThread(local) port, name = local.peeraddr[1..2] puts "*** receiving from #{name}:#{port}" # open connection to remote server remote =$remoteHost, $remotePort) # start reading from both ends loop do ready = select([local, remote], nil, nil) if ready[0].include? local # local -> remote data = local.recv($blockSize) if data.empty? puts "local end closed connection" break end remote.write(data) puts(data) end if ready[0].include? remote # remote -&gt; local data = remote.recv($blockSize) if data.empty? puts "remote end closed connection" break end local.write(data) puts(data) end end local.close remote.close puts "*** done with #{name}:#{port}" end loop do # whenever server.accept returns a new connection, start # a handler thread for that connection Thread.start(server.accept) { |local| connThread(local) } end

OK, now we are finally ready to do something that shouldn't be that hard in the first place. All we need to do is run the stunnel with the two conference files and then run the ruby proxy to dump the traffic.

stunnel listener.conf & stunnel client.conf & ruby tunnel.rb 3801 > logfile 

SSL Relay Proxy 2

Of course, you can tee your log file if you want to view it on the fly. There are limitless solutions to this (e.g., implementing SSL in ruby -- probably isn't hard), but this is what I ended with. Let me know if you come up with a different solution. I'd love to hear about it.

Related Blogs

March 14, 2018

Observations on Smoke Tests – Part 1

Smoke testing in the traditional definition is most often used to assess the functionality of key software features to determine if they work or perfo...

See Details

How Can We Help?

Let us know what you need, and we will have an Optiv professional contact you shortly.

Privacy Policy


May 09, 2018

Application Security

Learn how Optiv can help protect your most critical enterprise applications from both internal and external threats.

See Details

April 30, 2019

Privileged Access Managed Service

Learn how Optiv can help protect and manage your most vulnerable identities.

See Details

Stay in the Know

For all the latest cybersecurity and Optiv news, subscribe to our blog and connect with us on Social.


Join our Email List

We take your privacy seriously and promise never to share your email with anyone.

Stay Connected

Find cyber security Events in your area.