Thomas Bakker

musings on poker bots and more

Insecurity Through Security: Decrypting SSL by Adding 4 Lines of Code

Protecting a poker site from bots has many different sides. It requires active detection, both on the server and on the client side. However, it also requires passive protection: you need to make it difficult for bot writers to circumvent your security measures. In this article we will study a way around the security measures used by the CEREUS poker software.

Since Black Friday, the CEREUS poker network has pretty much gone away. So, I’m going to share this story here. As some of you might remember, CEREUS poker had a lot of scandals back in the day. One of these was an encryption scandal. Technicians from PokerTableRatings determined that the CEREUS poker software was not properly encrypting the data stream between poker server and client. CEREUS fixed this shortly after the discovery by implementing some SSL protocol. From then on, all communications between the client software and the server were encrypted, and very difficult for anyone (including bot writers) to intercept. Right?

Consider for a moment what it would mean if a bot writer could simply intercept network traffic: he would get the game state sent directly to his program, without having to do any scraping or memory reading ((See the other articles in the poker bot series to learn what these words mean.))! Now suppose he could also change the network traffic: he could suppress or fake any security data being sent, he could send his decisions directly to the server, et cetera. Having full control over the network traffic, one can completely bypass all client side security. So, lets see what we can do with CEREUS’ client…

Looking at their implementation

After CEREUS switched to the new encryption, I thought I’d study their implementation. Going into the directory where the client was installed, two files caught my eye:

  1. libeay32.dll
  2. ssleay32.dll

These files belong to OpenSSL, an open-source SSL/TLS-implementation. While this is a secure implementation, choosing this specific implementation happens to be very interesting for botters. Why? Let’s take a detour.

CEREUS never did too much against bots, but did they put in some effort. As far as I know ((As I never actually ran bots myself, I can’t be certain.))they scanned the running processes for known bots, and about a year ago they even added something called ”WinRing0” ((As far as I can see, winring0 used to be open-source, hosted on http://openlibsys.org/ – it’s no longer on there now.)), which is basically a kernel driver that allows the client deeper access to your PC for scanning for bots and such. However, at the same time they were still using OpenSSL.

The Trojan-Horse approach

So, what can we do with an open-source DLL that is used by a poker site to stream its entire network protocol through? Do what open-source is best for: look at the source-code, and change it to our likings!

I downloaded the source code for OpenSSL from its official website, http://www.openssl.org/source/ (make sure you get the same version as the .dll file you’re trying to replace). Then I looked for the source file that contains the code that’s used to encrypt and decrypt the traffic. This wasn’t especially hard to find, since there’s only 2,215 files in the source-code archive…

Anyway, after some digging through the reference manuals, the file we’re looking for is called “ssl_lib.c”, and can be found in the “openssl-X.X.XX/ssl”-directory. This file contains two functions we’re interested in:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int SSL_read(SSL *s,void *buf,int num)
  {
  if (s->handshake_func == 0)
      {
      SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
      return -1;
      }

  if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
      {
      s->rwstate=SSL_NOTHING;
      return(0);
      }
  return(s->method->ssl_read(s,buf,num));
  }

and

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int SSL_write(SSL *s,const void *buf,int num)
  {
  if (s->handshake_func == 0)
      {
      SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
      return -1;
      }

  if (s->shutdown & SSL_SENT_SHUTDOWN)
      {
      s->rwstate=SSL_NOTHING;
      SSLerr(SSL_F_SSL_WRITE,SSL_R_PROTOCOL_IS_SHUTDOWN);
      return(-1);
      }
  return(s->method->ssl_write(s,buf,num));
  }

Since CEREUS was using this library to encrypt and decrypt their network traffic, all of that data passed through these two functions. So, if one wanted to intercept the unencrypted data to build a poker bot, this would be an easy place to do so. Just add some code to both functions that exports all data in the buffer, and you can start reverse-engineering their network protocol. (Which, of course, is going to take a lot of time.)

In less technical words: by adding a few simple lines of code, we can locally intercept the poker client’s network traffic in an extremely reliable and unobtrusive way. ((Just to make it clear to less technical readers: this has no impact on the security of CEREUS’ encrypted traffic for regular players. It only makes it easy for people to decrypt CEREUS’ traffic locally on their own computers.))

Anyway, this DLL also gives us another opportunity besides the mere interception of data. One fun example would be to simply put our entire bot into it (or some code that connects to our AI on another computer.) This way, the Absolute poker client is not going to find any malicious processes running: the bot is running inside their own process!

So what should they have done instead?

There’s a few things. For one, they should have statically linked OpenSSL. ((Assuming the OpenSSL license allows this. I believe that it does.)) This would have integrated the OpenSSL code (now in a DLL) into the main poker client .exe file. This way, it would be impossible for us to recompile SSL and replace CEREUS’ version.

Suppose for a moment that changing compiler options to use static linking was too complex. Something they could at least have done was check if the code they are loading is unchanged, e.g. by calculating some checksum over the DLL and comparing it to the known checksum. If they are not equal, download the original DLL from the internet and load that one. This is what some other sites, like iPoker, do to many of their files.

“But you can circumvent that!”

Yes. Pretty much any client-side security can be circumvented: no matter how many layers of encryption you use, at some point the data will have to be decrypted to be shown to the user. However, one can at least attempt to make it difficult. This way, you will keep away some of the less motivated people, or those who are good at writing poker bots but not at reverse-engineering poker clients. Make subtle changes frequently, breaking bots every time.

CEREUS made no such attempt. No memory reading was required to find used encryption keys. No hooking was required to intercept data inside the client. One simply had to add a few lines to an open-source code file and hit “compile”.

If a poker site wants to take poker security seriously, it needs to analyze every potential consequence of every single component of a poker client. If a poker site has any weakness, botters will find and exploit it. The financial incentive to do so is huge. It is time for poker sites to start taking security more seriously.

To stay informed, please follow me on twitter, or subscribe to my RSS feed. To respond to this article, send me an email or contact me on twitter. To read the other articles in this series, go to the top of the page.