Tuesday, October 9, 2012

Simple TCP Forwarder in C#

Most of our connections go over SSL (at least the most important ones) and the certificate would be invalidated in case a MITM would be on going.

There are some troubleshooting situations when one would use a TCP forwarding tool as a proxy from one box to another but on what basis this technique/tool is used can vary a lot.

There are many TCP forwarding tools available on the web. However, the truth is that no one wants to get a whole solution out of a compressed file, fire Visual Studio when accessing a computer via command line (read: reverse shell here?). On top of that, I wanted to have some fun, so I decided to write one.

And how complicated is to write a TCP Forwarding tool? Or a TCP proxy if you prefer, in C#?

It takes only 66 lines of code using plain Socket class. And it's fun!

No rocket science here: using both Asynchronous (good old CLR APM in this case) and Synchronous Socket programming, few C# lines of code with one method exposed as an entry point taking the endpoints as parameter.

When I say asynchronous and synchronous, it's because the code has three synchronous methods from the Socket class been called. The first is the Socket.Accept() which blocks the thread until a connection is received. I chose this technique so that the Start method would never return and the main thread would handle the main socket.

The second synchronous method used is Socket.Send. This method also blocks the thread (in this case will be a thread from the ThreadPool due to async I/O that fired the receive callback). When one socket receives data, it forwards to the second socket in a synchronous manner, before asynchronously restarting to receive data.

In fact, a few tests I ran (where one socket is only flushing all buffer to a second socket) using BeginSend (asynchronous Socket.Send) performed slower then the synchronous Send.

Third, the Socket.Connect() which initiates the connection with the remote endpoint, where you want the data you send to the program to be forwarded to.

Once a connection is established, APM is used with BeginReceive/EndReceive to receive data. This means each pair of sockets will receive data using APM and use the same thread from the pool that called the callback to send the data to the other socket.

Let's run it!

Previously, I just wrote a class, right? That's far from having an executable.
As I mentioned before, my idea here was not to have yet another TCP Forwarding tool on Github, codeplex or codeproject, with dozens of files, so that we could forward some data.

So I propose a small change to the code above:
Let's add a static Main method to that class and build it as a command-line application:

Notice the address bar contains localhost:12345, which makes sense considering we set up the tunnel as: 127.0.0.1 port 12345 as local endpoint. On the bottom of the screenshot there's the Firefox extension DNS Flusher bar that shows ::1 which is the loopback address in IPv6.

If you think I might have a copy of xkcd comics number 1118 on my hard drive (the whole page, actually) and a web server binding port 12345, that's not the case. :)

Now, we have a class file with 73 lines of code (after adding the static Main method) but there's still some manual job in order to get the tunnel working. So let's try to automate this a bit more. Perhaps scripting the whole thing?!

The code can be a lot smaller if using minification. Got a nice hint on Stack overflow using Visual Studio find and replace with Regex: :Wh+

We create a script, let's say buildTcpForwarder.cmd, not forgetting to escape the > sign with ^ so that the interpreter ignores it. Note I have the path to the C# compiler (csc.exe) on my PATH environment variable

If you set the connecting socket to the target host port 443 (assuming default ssl port), forwarding will happen through the forwarder process, with SSL. As I mention in the post, the certificate will be invalidated, and that's a good thing, right? You're performing a MITM. Is this what you wanted to know?

Sockets are not (always) getting closed when a remote node closes the connection. Tested it with a web server sending response with header "Connection: close" and closing the connection after the request.The proxy transferred the data and the browser got it all, but since the proxy did not close the socket, browser never finished and the "onload" event did not fire (plenty of js riding on this nowadays)...

The only case the connection is closed there is if there's an exception. And that would trigger Close on 1 socket and (if this one doesn't throw) close the second. This is not production quality code, as I mentioned in the other reply, it's a PoC. I would not go for that "instance creating itself" approach either. That was just to leave this small as possible and show the idea behind it.

both instances are passed in to the APM methods, which keep holding their references.. reason why u can cast the IAsyncResult back into that State.On Main there's a while(true), nothing get's out of scope there so memory will be cleared when you close the application (there's no way out of that while(true))It's a PoC

About Me

Works with Software development, graduated in Computer Networks, Computer Security hobbyist.
Interested in these three fields since the late 1990's when everyday, hours were spent in front of the computer (especially on IRC ;) looking for more.