Thursday, March 28, 2013

Give a man a fish...


I guess ArenaNet has had time enough to react and fix their broken security, so it's
time to explain what exactly they messed up.

As I showed in a previous post, the game connection uses diffie hellman to negotiate the RC4 session key but stores the server's side pre-calculated in the client.

So how in hell did I calculate the server's secret?! ie. For the current release (17368) where do I get this from:

const unsigned char p[] = {
0xa1, 0xc5, 0x67, 0x7b, 0x95, 0xef, 0x74, 0x12, 0xcf, 0x58, 0xab, 0xef, 0xb0, 0x60, 0x9e, 0xa7,
0xab, 0x6c, 0x15, 0x3c, 0x6d, 0xf0, 0x24, 0xac, 0x0d, 0x02, 0x26, 0x66, 0xd1, 0x65, 0x28, 0x53,
0x29, 0xc7, 0xb4, 0xc4, 0x7b, 0xdd, 0xbc, 0x4c, 0x8d, 0xab, 0x7d, 0x6a, 0x7e, 0x26, 0xd7, 0x3c,
0x62, 0xe5, 0x66, 0x5f, 0x38, 0x9f, 0x49, 0x44, 0x6b, 0x18, 0x74, 0x9c, 0x43, 0x7a, 0xf4, 0x17,
};


const unsigned char b[] = {
0x8e, 0xe7, 0x79, 0xf0, 0x00, 0x0d, 0x31, 0xc9, 0xda, 0x45, 0x77, 0x44, 0xd3, 0x47, 0x0a, 0x26,
0x8d, 0x7e, 0xe3, 0x03, 0x02, 0x55, 0x6b, 0x0d, 0x88, 0xc7, 0x65, 0x32, 0x29, 0xbe, 0x1d, 0x71,
0x9f, 0x49, 0x00, 0xf9, 0x65, 0x97, 0xe6, 0x05, 0xda, 0x3b, 0x8f, 0xc0, 0xc7, 0x0b, 0x3a, 0x49,
0xe3, 0xfa, 0x6e, 0x2e, 0x27, 0x54, 0xab, 0x13, 0xae, 0xf5, 0x54, 0x61, 0x29, 0x4f, 0x37, 0x35,
};



To explain it.. we have to look at how the game does it's updates.

ArenaNet is using a content delivery network to distribute game updates. At startup, the game patcher will query an URL on the CDN which contains information about what the current live version is.

This information is at:
  http://assetcdn.101.ArenaNetworks.com/latest/101


Now, if you try to access this with your browser, you'll get an authentication error. To pass the authentication check, a header called 'authCookie' has to be passed. Older clients had this header clearly visible in the executable, ie:

$ strings gw2.exe.524178 |grep md5=|cut -c1-
authCookie=access=/latest/*!/manifest/program/*!/program/*~md5=4e51ad868f87201ad93e428ff30c6691

In newer clients it's build through printf style formatting, so it's a bit more effort to get it:

$ strings gw2.exe.570713 |grep md5=|cut -c1-
authCookie=access=/latest/*!/manifest/program/*!/program/*~md5=%s

However, the md5 value is always the same (haven't verified this on the latest clients anymore), so you can just use this value.

$ curl http://assetcdn.101.ArenaNetworks.com/latest/101 -b 'authCookie=access=/latest/*!/manifest/program/*!/program/*~md5=4e51ad868f87201ad93e428ff30c6691'
17368 570713 22680128 570709 5108


This tells us the latest release is 17368, has a fileid of 570713 on the CDN and is 22Mb in size. Equipped with this information, we can download the latest gw2 executable:

$ curl http://assetcdn.101.ArenaNetworks.com/program/101/1/0/570713 -b 'authCookie=access=/latest/*!/manifest/program/*!/program/*~md5=4e51ad868f87201ad93e428ff30c6691' -o gw2.exe

Easy enough...


An update contains much more than just the gw2 executable, there's also patches for the data files and other stuff.

And this is where ArenaNet made a gigantic mistake in my opinion. If you take the previous link and  increment the filenumber by one, you get something VERY interesting! For some unknown reason,  the actual server code and authentication code is also on the CDN and it's even accessible to everyone that wants a copy!!

If you take fileid 570714 and run it through objdump, you will see it's actually called GwSrv.dll and fileid 570715 is called AuthSrv.dll

Imagine my surprise when I discovered this. By that time, I had already reversed the encryption protocols used on both connections, so it didn't help me for that part, but I also knew one of those 2 DLLs would need access to the server side secret and after some investigating, it was clear the key was contained inside the DLL itself (it could aswell have been loaded from an external file).

Equipped with that info, I wrote a small tool using libbfd which looks for the keys and just dumps them. I later verified they were in fact correct.


To this day, I'm still gobsmacked that a company can make such an error. Makes you wonder how they store all the credit card information of people!

The GwSrv.dll will be particularly interesting for people trying to write an emulator, but it's also nice to get an idea of how their backend is setup.

ie.

$ strings GwSrv.dll |grep -P '^[A-Z].*Srv$'
FileSrv
BuildSrv
DllSrv
AuthSrv
GwSrv
DbSqlSrv
DbCacheSrv
StreamSrv
SiteSrv
DistSrv
AcctHttpSrv
AcctMailSrv
CrashDumpSrv
EventLogSrv
LogQuerySrv
BeaconSrv
CrashSrv
UTournSrv
ConfigSrv
DbNameSrv
BugMailSrv
LogImportSrv
CensusSrv
DummyCliSrv
DbNameTestSrv
DbSrv
RankSrv
FileIdChkSrv
IpBlockSrv
PitchingSrv
ConfigSrv
ObsCtrlSrv
GuildSrv
ReplicationSrv
AssetSrv
EconDataSrv
EconSrv
ClientErrorLogSrv
TournSrv
EmptySrv
PlayerlessSrv
BrokerSrv
ExchangeSrv
GemStoreSrv
TradeSrv
CharUserDataSrv
PortalSrv
HealthSrv
ClientErrorSrv
MetricsSrv
ItemSearchSrv
ItemDataSrv
RestoreSrv
ListTaskSrv
TournSearchSrv
ContentSrv

Pity they didn't put them all on the CDN ;-)


Tuesday, March 12, 2013

Proximus fail!

I got a Nexus4 the other day, but since it uses a micro sim whereas my old phone used a normal sim card, I had to get a replacement for it.
Much to my surpise, the only info I needed to provide, was my current phone number! No id card, no proof of ownership, no pin number, not even the old sim card I was replacing, .. nothing!

What's this proximus?! Social engineering courses for dummies?!

Monday, March 11, 2013

Portal Connection - update

Something I just noticed today when investigating an IMAP SSL connection issue (using openssl's s_client), is that the handshake packets looked quite similar to the SSL setup of the gw2 portal connection.

ie. what I originally had:

0x14 = ack
0x15 = server error
0x16 = auth phase
0x17 = game packet

is actually:


enum {
       change_cipher_spec(20), alert(21), handshake(22),
       application_data(23), (255)
   } ContentType;
 
As shown in RFC5246 - The Transport Layer Security (TLS) Protocol, makes sense actually that they used a library for that instead of rolling their own TLS version.

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.

Tuesday, March 5, 2013

Laptop repair

With the repair done on my motherboard, I figured I'd take a look at an old laptop I still had laying around. It's an old Acer Aspire 1510 which has an nvidia graphics chip. The problem with it, was that the display output was all garbled. It was possible to boot it, but when it went into graphics mode, it would usually lock up pretty fast.
This is something that happens to many laptops with nvidia chips. The issue, from what I understand, is that due to the way the chipset heats up, the forces on it cause the solder joints to fracture.
These are BGA (Ball Grid Array) chips, reworking those needs specialized equipment although you can find BGA rework equipment pretty cheap on sites like aliexpress. However for a one off on an old laptop, it would still be too much and I doubt it will be easy the first time you try to reball a BGA.

Luckily, there's a cheaper and much easier way!

Basically what you can do is remove the PCB with the GFX chip and just put it in a normal oven at 200 degrees Celcius for 10 minutes. This will cause the solder joints to reflow and fix the fractures. There's plenty of youtube videos demostrating the effect. So I figured I'd give it a shot... 10 minutes later my freshly baked laptop was resurrected!

Monday, March 4, 2013

Upgrade from hell

About two weeks ago, I decided to finally take the time to upgrade an old Ubuntu 10.04 on a home server. This ofcourse involves a couple of upgrades, since that release is too old to bump to the latest and greatest.
The first upgrade step went rather uneventful, albeit slow. However, my weekend plans were quickly interrupted when after booting the new release, the machine decided to insta power off after 2 minutes. *sigh*

Mind you, this machine did give the occasional warning about temperature issues before the upgrade, so my first reaction was to think too much dust had collected on the CPU cooler. I opened the machine and tried to clear the dirt that had settled between the cooler and the CPU heat sink.. however while doing that, I accidentally broke one of the fan supports.. doh!

This was starting to get annoying. Good thing I had some super glue lying around. Couple of minutes later, the support was firmly reattached and I could continue (though the fan wasn't 100% aligned, causing it to scratch the sides a bit, making a wonderful whining noise)

After this operation, I could boot the board again and it seemed to stay up. Just to be safe, I kept it running overnight before continuing my upgrade fiasco.

The next day, still no reboot issues. So I prepared to do the remaining upgrades. It didn't take long for new issues to pop up. One or two minutes after starting the update manager, the machine again went completely dead. However this time, I couldn't power on the machine anymore. The hardware had completely failed this time. Just my luck again...

Now it just so happens that I recently picked up my interest in electronics again. Therefor instead of throwing out the board, I had a look at what I could do or find about what was wrong.

First investigation showed that I could power it on if only the 20 pin ATX connector was attached, but when the 4 pin ATX connector was also connected, it refused to work for more than 1-2 seconds.

That 4-pin ATX connection supplies 12V to the VRM section of the motherboard. When looking closer, I noticed 2 capacitors which were bulging, which is usually a dead giveaway that they are damaged.

This looked promising...

I had some old CD and DVD audio player I wasn't using anymore, so used those to find some spare parts. Desoldered a couple of capacitors from them and put them in the motherboard. However, while turning the motherboard around a couple of times to see what I was doing, I accidentally also turned one of the caps around. Needless to say the repair didn't work. To add insult to injury, I also took the wrong cap for 1 of the replacements, picking a 6.3V in a place that had a 16V cap.

Some swearing ensued...

When I corrected the error, the board still didn't work (maybe it would have, if I didn't screw up the first fix).

Since working without a schematic is fairly hard, especially for a novice in electronics. I decided to just check on google if there was any info to be found for this motherboard (MSI 6728). To my surprise the service manual with a full schematic turned up. Nice!

Anyway in order to pinpoint the issue, I hooked up my lab power supply and put some juice on the 12V circuit. This immediately showed that there was a short circuit on that rail. When I turned up the amps, one of the MOSFETs quickly heated up, while the neighbouring ones which were for the other phases didn't. So I decided to desolder that MOSFET and check again.

With that one removed, the short on the rail was gone and the lab supply showed a steady 12V. To double check, I reconnected the original PSU, but nothing happened. It seemed the PSU had died due to the short, good thing I still had another PSU around and decided to try that one. This time the board booted again!

Next problem was actually finding a replacement part. I could only find the old part on mouser, but it was EOL and out of stock, but they did have a similar part (I made sure the rise and fall times were the same or better, since I figured that was important.. for details, google for multiphase buck converter). The part was only 60 euro cent, but of course shipping was a biatch, but I offset that by ordering some more goodies :-)

Few days later, the order arrived and a couple of minutes later, I was enjoying the fruits of my labor... my board was booting again! Victory!