📜 ⬆️ ⬇️

How I intercepted the traffic of the poker room or "Writing my MitM SSL proxy in C #"

Once I had an obsession: to see, and what is there such a poker client sends to the server. As you understand, large poker rooms use SSL to transfer data. Protocols based on asymmetric encryption are subject to only one type of attack known to me - MitM (Man in the middle - the man in the middle).

Having lamented with a ton of software designed to implement MitM on an SSL connection, I came to the conclusion that my hands do not grow from that place either from the developers of these tools or from me. But the idea was terribly obsessive, and it was decided to do everything manually. If it is interesting what came of all this, I ask for cat.


This article is enlightened by writing a simple tool for implementing MitM attacks. Those who are not familiar with what MitM is can read about it here .

purpose


A Cake Poker client was chosen as the test subject because of my lengthy acquaintance with him. It all started with the fact that I just started a poker client and got into the good old resource manager, in which I found a dozen connections from him.

After experimenting, I was able to isolate the compound that always holds. I took him on sight for the MitM attack.

The source of the connection is known, the final goal is known - lb6.playdata.co.uk.
')

Traffic redirection


Now it was necessary to interpose between the client and the server. I didn’t invent anything too clever, because there’s no need for that - I just added domain names to host that correlated with 127.0.0.1. It is not difficult to guess that if there is lb6.playdata.co.uk, that is, lb1.playdata.co.uk, and lb8.playdata.co.uk. I acted with them in the same way, bringing to the host, since the final instances, as I understand it, are selected by the location of the stars. When you start the poker client, it hangs waiting for a connection. Wonderful. This means that the traffic has been redirected to our typewriter. Go ahead.


Proxy


The next task was to write a proxy in C #. Yes, a simple proxy for preparing a future program. In order not to engage in the invention of the bike, I quickly googled the solution that suits me: TCP Proxy in C # using Task Parallel Library .
I did a bit of refactoring (I hate it when I have a lot of nesting), zahardkodil end point of connection and launched. I launch the poker client - everything works. In the resource manager we can see that the traffic from the poker client goes to my proxy, and from it to the server and back.

MitM to SSL


Next, we have to implement a MitM-attack on SSL. We divide it into two stages: the first is connecting the client to the proxy; the second is a proxy with the server.
To implement the first stage, when the client connects to the proxy, we will not send the incoming data further, but begin the so-called handshake procedure. In C #, this can be done using an instance of the SslStream class, built on top of the NetworkStream that has already been created. At the time of creation, information about the protocol and other specific information is transmitted.
After that, we transfer the certificate to the client. This is done using the AuthenticateAsServer method of the SslStream class, where we must pass the path to the certificate file.

The x509 certificate file was generated using the Makecert utility, which can be accessed from the Visual Studio developer console. I had to suffer a little with the parameters, but everything worked out. Here is a good description of how it can be used: SSL communication in C # . As the name we specify * .playdata.co.uk. This name covers all domains that are used by the poker client.
makecert -n CN=MyCA -cy authority -a sha1 -sv “MyCA.pvk” -r “MyCA.cer” //   certmgr -add -all -c “MyCA.cer” -s -r LocalMachine Root //      makecert -n CN=*.playdata.co.uk -ic MyCA.cer -iv MyCA.pvk -a sha1 -sky exchange -pe -sr currentuser -ss my SslServer.cer //   

We generated the server private key and the CA key (identification center), which signed our key. Key CA is placed in the "Trusted Root Certification Authorities", and voila! If you look at our server key with Windows key browsing tools, we will see that the system considers it valid, just like the poker client running on our system.


We pass the path to the received certificate to the AuthenticateAsServer method. If everything went well, then we will have an SSL connection from the client to the proxy to which the client will send data. Now it is necessary to give the client adequate answers to his requests. To do this, we need to implement the second stage of the MitM-attack, namely to build an SSL connection from the proxy to the server. We also build SslStream on top of NetworkStream before the server and log in using the AuthenticateAsClient method. The data coming from the SSL connection between the client and the server is sent to each other.
C # handshake process
 var certificate = new X509Certificate("SslServer.cer", "123"); var clientStream = new SslStream(client.GetStream(), false); clientStream.AuthenticateAsServer(certificate, false, System.Security.Authentication.SslProtocols.Default, false); var server = new TcpClient("200.26.205.63", 4520); var serverSslStream = new SslStream(server.GetStream(), false, SslValidationCallback, null); serverSslStream.AuthenticateAsClient("lb3.playdata.co.uk"); 


After some time of work, it will be possible to notice in the resource manager the difference in the number of bytes sent to and from the proxy. This is due to the fact that when encrypting different keys give different results in size.

Conclusion


What next? And then we will add the code to save the data in a text file so that they can be analyzed by what the poker client sends to the server. Actually, everything, MitM Proxy is written.

It remains to add a little blackjack to it. For example, for parsing the traffic going through it, pulling out the user's cards and sending it to us, etc.
I wrote a traffic parser on the fly, so that it would be convenient to monitor what the client sends, and relate it to my actions. Demonstration of what happened with me:


Mitm proxy sources
 using System; using System.Diagnostics; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using ConnectionAnalizer; namespace MITMProxy { class Program { static readonly TcpListener Listener = new TcpListener(IPAddress.Any, 4520); const int BufferSize = 4096; static void Main() { Listener.Start(); new Task(() => { while (true) { var client = Listener.AcceptTcpClient(); new Task(() => AcceptConnection(client)).Start(); } }).Start(); Debug.WriteLine("Server listening on port 4502. Press enter to exit."); Console.ReadLine(); Listener.Stop(); } private static void AcceptConnection(TcpClient client) { try { var certificate = new X509Certificate("SslServer.cer", "123"); var clientStream = new SslStream(client.GetStream(), false); clientStream.AuthenticateAsServer(certificate, false, System.Security.Authentication.SslProtocols.Default, false); var server = new TcpClient("200.26.205.63", 4520); var serverSslStream = new SslStream(server.GetStream(), false, SslValidationCallback, null); serverSslStream.AuthenticateAsClient("lb3.playdata.co.uk"); new Task(() => ReadFromClient(client, clientStream, serverSslStream)).Start(); new Task(() => ReadFromServer(serverSslStream, clientStream)).Start(); } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } } private static bool SslValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors) { return true; } private static void ReadFromServer(Stream serverStream, Stream clientStream) { var message = new byte[BufferSize]; while (true) { int serverBytes; try { serverBytes = serverStream.Read(message, 0, BufferSize); clientStream.Write(message, 0, serverBytes); } catch { break; } if (serverBytes == 0) { break; } } } private static void ReadFromClient(TcpClient client, Stream clientStream, Stream serverStream) { var message = new byte[BufferSize]; var fileInfo = new FileInfo("client"); if (!fileInfo.Exists) fileInfo.Create().Dispose(); using (var stream = fileInfo.OpenWrite()) { while (true) { int clientBytes; try { clientBytes = clientStream.Read(message, 0, BufferSize); } catch { break; } if (clientBytes == 0) { break; } serverStream.Write(message, 0, clientBytes); memoryStream.Write(message, 0, clientBytes); stream.Write(message, 0, clientBytes); } client.Close(); } } } } 

Source: https://habr.com/ru/post/213397/


All Articles