Showing posts with label encryption. Show all posts
Showing posts with label encryption. Show all posts

Friday, March 8, 2013

Game connection

So last time I talked about the portal connection, now it's time to go over the security on the game connection.

The guildwars2 game connection is encrypted with RC4. Both the send and receive direction start from the same key.

The session key is randomly generated. The exchange of the session key is done using Diffie Hellman key exchange. The server's B value (gb mod p) is pre-computed and stored inside the game client, therefor isn't transmitted during the setup of the connection.


When the connection is established, the client will send a packet with version information and then send it's diffie hellman component to the server, ie. value A ( ga mod p). The value for g is fixed in all versions upto now and is always 4. The value p is changed on each new build of the game.

The actual session key is the computed diffie hellman shared secret xor'ed with the 20 bytes block the server sends at connection setup. However the RC4 initialization function uses a hash function on the key. I haven't been able to identify the hash function, so had to extract the one from the client to be able to initialize my RC4 routine. (search for "b3 98 b4 9f" and you'll find it)

After that, each byte send/received is just encrypted/decrypted with normal RC4.

As for the actual game packets. Every packet type has a predefined structure, which is handled by a MsgPack / Unpack function. Those functions use a table structure to define the types of fields. The actual msgtype numeric value for a packet can change between 2 revisions of the client, so hard coding those is a bad idea for anyone interested in writing an emulator. It is however fairly easy to extract the structure from the game client. While fooling around with it, I wrote a small program using libbfd to parse the executable and dump a header file with the structure of the packets, enabling me to decode a wireshark capture.

ie. example extract:

struct netFieldI serverMsgWvwCliObjectiveMgr_273[] = {
        NETFIELD_MSGID(0x273, "serverMsgWvwCliObjectiveMgr_273"),
                NETFIELD_BYTE(),
        NETFIELD_END()
};



Since they still have that security issue I referred to a while ago, you don't need any hacks to decode the wireshark. I still haven't heard anything back from them, so I'll probably spill the beans about it one of these days.

Just to help anyone fooling around with it, here are the DH params for the current client (16974) :

const unsigned char p[] = {
0xe7, 0x6f, 0x21, 0x5a, 0x30, 0x4c, 0x56, 0x37, 0x83, 0x1b, 0x17, 0x9c, 0xde, 0x5d, 0xc7, 0x1e,
0x10, 0xec, 0xac, 0xbd, 0xd1, 0x96, 0x72, 0xe3, 0xd3, 0xcc, 0x73, 0x49, 0x0a, 0xfb, 0xb9, 0x97,
0x60, 0x49, 0x02, 0xe4, 0x96, 0xac, 0x4c, 0x8a, 0x39, 0xa7, 0xb2, 0xfa, 0xe4, 0x9d, 0x75, 0x98,
0xc6, 0x81, 0xd1, 0xa1, 0x28, 0x1a, 0x6a, 0x57, 0xb6, 0xf9, 0xa5, 0x1a, 0xf5, 0x11, 0x00, 0x89,
};
const unsigned char b[] = {
0x69, 0xa9, 0x48, 0xfe, 0x6b, 0xe4, 0x4e, 0xd4, 0xc3, 0x85, 0x8e, 0xdf, 0xc6, 0xc9, 0xd4, 0xd1,
0x82, 0x10, 0x9e, 0xce, 0x41, 0xcc, 0x34, 0x36, 0x9f, 0x13, 0xad, 0x37, 0x78, 0x05, 0x08, 0x59,
0xd5, 0x68, 0x2e, 0xe1, 0xf8, 0x34, 0xf3, 0x05, 0x9d, 0x12, 0x85, 0x85, 0x24, 0x7a, 0xa4, 0x69,
0xa9, 0x30, 0x98, 0xd4, 0x21, 0x22, 0xb6, 0xa0, 0x7c, 0x4f, 0xbf, 0x5e, 0x8d, 0x4b, 0x34, 0xe8,
};


g ofcourse is 4.


Another useful tip.. the protocol for this game connection is almost identical to how the GPLv3-licensed CyanWorlds.com Engine (Headspin/Plasma) functions. I'm actually fairly sure, they share a common origin, especially since some of the error messages and constant values of a certain template function are identical to this. The message pack/unpack is also similar, but that one isn't an exact copy.

Friday, December 21, 2012

Portal connection

Portal connection


Time to dig into the specifics of Guild Wars 2's connection...

The portal connection starts off in clear text. The game client will connect, then send a /Sts/Connect command which will include information about the game client.

Example:


P /Sts/Connect STS/1.0
l:252

<Connect>
<ConnType>400</ConnType>
<Address>192.168.1.1</Address>
<ProductType>0</ProductType>
<ProductName>gw2</ProductName>
<AppIndex>1</AppIndex>
<Epoch>999999999</Epoch>
<Program>101</Program>
<Build>1002</Build>
<Process>9999</Process>
</Connect>
P /Auth/StartTls STS/1.0
s:1
l:11

This looks similar to how HTTP requests work. Th
e 'l:' specifies the length of the request and the 's:' is a sequence number. The server will reply and include a reference to this sequence number.

Example:

STS/1.0 400 Success
s:1R
l:46


<Error server="1001" module="2" line="1518"/>

The 's:1R' here, refers to the original client request. The 
/Auth/StartTls command starts the encryption handshake. From here the connection will switch from text to a binary protocol.

The client will begin by sending a buffer starting with:

16 03 03 xx xx

The first byte indicates what kind of packet this is:

14 = ack
15 = server error
16 = auth phase
17 = game packet

The 2 last bytes are the size of the sub buffer that follows.


So looking at the first response the client sends:
 

16 03 03 00 4e
01 00 00 4a 03 03 xx xx xx ...

Shows a subbuffer of size 0x4e (78 bytes). The first byte is the type of the buffer. If you look closely, it's apparent this buffer is also split up (ie. 0x00 0x4a is yet another size indicator of a sub part). I'm going to skip on some details, if you fire up wireshark you can more easily look at what's there.
There's 1 part that is important in this 0x01 sub buffer and that is a client seed that will be used further on. We need to save 0x20 bytes starting at xx as indicated above.

Also important, is that these sub buffers are used in the HMAC calculation, so we need to keep a sha256 hash of them, excluding the 0x14 sub buffer for digest1.

In code:

if (packet[0] != 0x14)
   digest1.process(packet);

digest2.process(packet);
The server will reply using a similar packet format. The first response is:
16 03 03 00 34

So we already know 00 34 is the size of the sub buffer, which contains:

02 00 00 30 03 03 xx xx xx
Like before, sub buffer 0x02 with a size of 0x30. Also similar as the client buffer, is that these first 0x20 bytes are a server seed, followed by some extra parameters which I'm going to skip here.

For what follows now, it's useful to read RFC5054 paragraph 2.2. and have a look at the SRP demo page.

The server follows up with a new large packet:

16 03 03 01 14
0c 00 01 10
   00 80 xx xx xx .....
   00 01 02
   08 yy yy yy yy yy yy yy yy
   00 80 zz zz zz .....
These are actually multi precision integers used for the SRP session server key exchange, more specifically the values N, g, s, B.
N = xx xx xx ...
g = 2
s = yy yy yy yy yy yy yy yy
B = zz zz zz ...
After these the server sends: 
16 03 03 00 04
   0e 00 00 00
The client will in return send it's A key to the server:
16 03 03 00 86
   10 00 00 82
      00 80 xx xx xx xx

 with A = xx xx xx ...


If you look at the SRP demo page (SRP-6a), you can see how all these values fit together. However GuildWars 2 uses a slightly different way to calculate value x, the RFC version uses:

x = H(salt || H(username||':'||password))

whereas Guild Wars 2 uses:

passhash = H(lowercase(unicode_pass||unicode_login))
Then converts this passhash buffer using htonl() and hashes it to form the password field to use in the calculation:
x = H(salt || H(lowercase(username)||':'||H(passhash)))

With all these values, we're able to calculate the shared key S.

The client will now activate encryption by sending the packet:

14 03 03 00 01 01
  
From now on, the buffers will be encrypted, however the shared key S isn't used as-is for the encryption. First a master key is generated from this and then a key expansion function is used to generate a send and a receive key.

But that's for another post...