POKE 1,52
Tuesday, August 13, 2013
It's no IDA, yet?
Tuesday, July 23, 2013
Central Heating - ROM Dump
I had been meaning to try and dump the ROM image of the main cpu of my central heating, but wanted to wait doing that until the weather was a bit better, afterall I didn't want to blow up the chip in the middle of winter.
I actually didn't expect it was going to be possible to dump it, since most devices have a fuse which you can blow to prevent reading out the image, but it was worth the shot.
So took the CPU to work today, since I have access to a universal chip flasher here. To my surprise, the thing read out the chip without problems! So I now have a dump which I can start to reverse. The processor is an ST62T25, unfortunately I don't have a disassembler for that chip, so that will be the next step, writing one.
I actually didn't expect it was going to be possible to dump it, since most devices have a fuse which you can blow to prevent reading out the image, but it was worth the shot.
So took the CPU to work today, since I have access to a universal chip flasher here. To my surprise, the thing read out the chip without problems! So I now have a dump which I can start to reverse. The processor is an ST62T25, unfortunately I don't have a disassembler for that chip, so that will be the next step, writing one.
Saturday, July 20, 2013
Riglol
So a while back, people discovered the Rigol DS2xxx scope firmware contained a developer key to activate all the extra features. This attracted attention from a couple of people to examine the firmware in more detail.
The firmware was reversed by cybernet. He found that the license check was based on ECDSA. The Elliptic Curve implementation was from MIRACL. He then wrote a tool that took the serial number and options + license key and ran the same verification steps to show if the license was correct or not.
This piqued my interest, so I got involved. Read up on Elliptic Curves and gathered the necessary tools. One of the first paths I tried was to check if they were as stupid as Sony, ie. instead of using a random number, they always used the same value, which was how the PS3 security was broken.
Reason why I wanted to check this, was that the MIRACL library only contains a pseudo random number generator, which is seeded by asking the users for a 9 digit seed. If Rigol was lazy, they might have used the same value each time... worth checking out.
However, for this I needed 2 valid license codes, which was a problem...
So I forgot about that and started looking to trying to solve the elliptic curve discrete logarithm problem. I didn't expect to get very far, I mean.. what would be the chance of Rigol screwing up their Elliptic Curve implementation? Right?!
Well it seems the odds were in my favour :-)
After entering all the curve params in a ECDLP Solver, I was greeted with the private key value in less than a second!!
Now here's the weird thing... the values they used are suspiciously similar to a crackme on the net.
To double check my finding, I used the ecsign from the MIRACL SDK to generate a new signature for a fake serial number. Converted the signature values to the license code format, then ran it through cybernet's tool to see if the license was accepted. The last line of the output says it all:
Anyway it was a fun challenge and I learned quite a lot about Elliptic Curves from it.
The firmware was reversed by cybernet. He found that the license check was based on ECDSA. The Elliptic Curve implementation was from MIRACL. He then wrote a tool that took the serial number and options + license key and ran the same verification steps to show if the license was correct or not.
This piqued my interest, so I got involved. Read up on Elliptic Curves and gathered the necessary tools. One of the first paths I tried was to check if they were as stupid as Sony, ie. instead of using a random number, they always used the same value, which was how the PS3 security was broken.
Reason why I wanted to check this, was that the MIRACL library only contains a pseudo random number generator, which is seeded by asking the users for a 9 digit seed. If Rigol was lazy, they might have used the same value each time... worth checking out.
However, for this I needed 2 valid license codes, which was a problem...
So I forgot about that and started looking to trying to solve the elliptic curve discrete logarithm problem. I didn't expect to get very far, I mean.. what would be the chance of Rigol screwing up their Elliptic Curve implementation? Right?!
Well it seems the odds were in my favour :-)
After entering all the curve params in a ECDLP Solver, I was greeted with the private key value in less than a second!!
Now here's the weird thing... the values they used are suspiciously similar to a crackme on the net.
To double check my finding, I used the ecsign from the MIRACL SDK to generate a new signature for a fake serial number. Converted the signature values to the license code format, then ran it through cybernet's tool to see if the license was accepted. The last line of the output says it all:
License Key is VALID
Anyway it was a fun challenge and I learned quite a lot about Elliptic Curves from it.
Tuesday, July 16, 2013
Central Heating - Decoding
After staring some time at the logic capture of my central heating, I was able to decode the way data is encoded by the unit.
The smallest unit in the capture is 6.80ms. It takes 4 units to make up 1 bit/symbol, not exactly a high speed bus. There are 3 different patterns that show up in the cap:
MARK MARK SPACE SPACE
MARK SPACE SPACE SPACE
MARK SPACE MARK SPACE
The transmission has 56 of these patterns, followed by a silence period. This means that each transmission totals 7 bytes. I used the arduino to decode this sequence and output the result on the serial. The MARK SPACE MARK SPACE pattern is decoded as a set bit, while the other 2 decode to a 0 bit. I have no clue as to why there's 2 patterns to indicated a zero, ie. MARK MARK SPACE SPACE and a MARK SPACE SPACE SPACE, maybe it has something to do with providing the remote unit enough power to load up it's internal capacitor, since that unit is completely powered from the 2 wire bus.
I found that to debug the timing of the code, it's quite useful to use an extra IO pin on the arduino, hooked up the the 2nd channel of the oscilloscope and then toggling the line when something goes wrong. By displaying both the CV signal and the debug channel signal on the scope, it was quite easy to see where the code lost track of the signal.
After some fiddling, this is what I got out of the signal:
The communication gives 4 sets of 7 bytes, then repeats. Now it was time to play with the heating and see which values changed...
The smallest unit in the capture is 6.80ms. It takes 4 units to make up 1 bit/symbol, not exactly a high speed bus. There are 3 different patterns that show up in the cap:
MARK MARK SPACE SPACE
MARK SPACE SPACE SPACE
MARK SPACE MARK SPACE
The transmission has 56 of these patterns, followed by a silence period. This means that each transmission totals 7 bytes. I used the arduino to decode this sequence and output the result on the serial. The MARK SPACE MARK SPACE pattern is decoded as a set bit, while the other 2 decode to a 0 bit. I have no clue as to why there's 2 patterns to indicated a zero, ie. MARK MARK SPACE SPACE and a MARK SPACE SPACE SPACE, maybe it has something to do with providing the remote unit enough power to load up it's internal capacitor, since that unit is completely powered from the 2 wire bus.
I found that to debug the timing of the code, it's quite useful to use an extra IO pin on the arduino, hooked up the the 2nd channel of the oscilloscope and then toggling the line when something goes wrong. By displaying both the CV signal and the debug channel signal on the scope, it was quite easy to see where the code lost track of the signal.
After some fiddling, this is what I got out of the signal:
26 66 74 24 02 7B 0A 0010_0110 0110_0110 0111_0100 0010_0100 0000_0010 0111_1011 0000_1010
60 66 75 FF FF 00 20 0110_0000 0110_0110 0111_0101 1111_1111 1111_1111 0000_0000 0010_0000
26 06 77 FF FF 00 20 0010_0110 0000_0110 0111_0111 1111_1111 1111_1111 0000_0000 0010_0000
60 FF 76 25 02 78 0A 0110_0000 1111_1111 0111_0110 0010_0101 0000_0010 0111_1000 0000_1010
The communication gives 4 sets of 7 bytes, then repeats. Now it was time to play with the heating and see which values changed...
Monday, July 15, 2013
DAoC - The middle man
We've already seen that the key generation isn't up to par, neither is the actual way how the RC4 encryption is used... but there's an even bigger issue. The game is susceptible to a man-in-the-middle attack (MITM).
The game client has no way of knowing if the traffic it receives is indeed coming from the official servers. Games like Guild Wars2 use Diffie-Hellman to exchange the encryption key, but they have the server part baked into the client binary. Therefor in a game like that, you can't impersonate the server without changing the client binary (unless they leak their server binary ofcourse *wink*).
Now, in Mythic's defense, the DAoC client does use RSA to transmit the RC4 session key to the server, which means a man in the middle attacker won't be able to decrypt this packet and sniff the encryption key (unless you found a solution for the factoring problem).
So... where's the problem then?
The issue is with the initial connection setup. The client connects to the server and sends a packet with it's info. The server then responds with the following packet:
0000: 22 01 31 01 0a 03
Which tells the client what version the server is running, but more importantly, tells the client to switch to encrypted communication mode. Yes, there's actually 2 modes the client can work in! Encrypted and non-encrypted mode.
This opens the possibility for a MITM attack. If we proxy the data between the client and the server and change the 01 into 00, we can trick the client to work in non-encrypted mode. To the server, we respond with an RSA encrypted RC4 key, which the proxy creates itself. From then on, it's just passing traffic while encrypting/decrypting the data between the 2.
Another big problem is that the communication protocol doesn't use anything like SRP to prevent people from sniffing and reusing the password. Therefor, the attacker will be able to grab the login and plain text password from the intercepted session.
As a proof of concept, I wrote a small proxy that did just that. It ran on a linux machine in between the client and the server and used the transparent proxying (TPROXY) feature of the linux kernel to redirect the traffic to the proxy program. Worked like a charm.
The game client has no way of knowing if the traffic it receives is indeed coming from the official servers. Games like Guild Wars2 use Diffie-Hellman to exchange the encryption key, but they have the server part baked into the client binary. Therefor in a game like that, you can't impersonate the server without changing the client binary (unless they leak their server binary ofcourse *wink*).
Now, in Mythic's defense, the DAoC client does use RSA to transmit the RC4 session key to the server, which means a man in the middle attacker won't be able to decrypt this packet and sniff the encryption key (unless you found a solution for the factoring problem).
So... where's the problem then?
The issue is with the initial connection setup. The client connects to the server and sends a packet with it's info. The server then responds with the following packet:
0000: 22 01 31 01 0a 03
Which tells the client what version the server is running, but more importantly, tells the client to switch to encrypted communication mode. Yes, there's actually 2 modes the client can work in! Encrypted and non-encrypted mode.
This opens the possibility for a MITM attack. If we proxy the data between the client and the server and change the 01 into 00, we can trick the client to work in non-encrypted mode. To the server, we respond with an RSA encrypted RC4 key, which the proxy creates itself. From then on, it's just passing traffic while encrypting/decrypting the data between the 2.
Another big problem is that the communication protocol doesn't use anything like SRP to prevent people from sniffing and reusing the password. Therefor, the attacker will be able to grab the login and plain text password from the intercepted session.
As a proof of concept, I wrote a small proxy that did just that. It ran on a linux machine in between the client and the server and used the transparent proxying (TPROXY) feature of the linux kernel to redirect the traffic to the proxy program. Worked like a charm.
Friday, May 24, 2013
DAoC Random function
As I mentioned before, the generation of the RC4 key in this game can easily be instrumented to generate the secret we want.
The pseudo code to generate the RC4 key looks something like this:
They are also feeding back the input into the RC4 state, by incrementing the j variable by the unencrypted input byte.
Another issue with just using the rdtsc instruction to generate random data, is that this instruction can be made priviledged by setting the TSD flag in CR4, ie. cause a system trap to occur when executed in userspace / ring3, which means there's full control over what this RC4 key generator produces without even having to alter the game binary or redirecting system APIs. Example code to do something like this, can be easily found, ie. here.
The pseudo code to generate the RC4 key looks something like this:
repeat 0x40 timesThis block is then RSA encrypted and exchanged with the server. From then on, all packets get encrypted with this RC4 key. One interesting thing also, is that the game doesn't use RC4 as a continuous stream cipher, instead each packet resets the RC4 cipher to the initial state. This stems from the fact that the game can use UDP for communication and therefor needs to handle the case where packetloss occurs, which would desync the state, but it also makes this less secure. I'm not an expert in cryptography, but I'm sure this enables some interesting crypto attacks to decipher the content. From what I've read, the first few bytes of RC4 are already less random than they should be, which is why it's suggested to advance the RC4 state a couple of bytes before actually using it on your data, which this game doesn't do. Couple that with knowledge of some of the payloads' fixed bytes and I'm sure a real cryptographer can decipher a stream without much effort. Now there's 1 thing they did to try and counter some of this. Instead of starting the packet encrypt from the first byte of the packet, they start it from the middle of the packet, which helps a bit with the known byte value issue.
use rdtsc to generate 1 byte
verify the resulting byte isn't 0
sleep 1
They are also feeding back the input into the RC4 state, by incrementing the j variable by the unencrypted input byte.
Another issue with just using the rdtsc instruction to generate random data, is that this instruction can be made priviledged by setting the TSD flag in CR4, ie. cause a system trap to occur when executed in userspace / ring3, which means there's full control over what this RC4 key generator produces without even having to alter the game binary or redirecting system APIs. Example code to do something like this, can be easily found, ie. here.
Tuesday, April 16, 2013
DAoC vulnerability update
So I got a mail back from the janitor at Mythic regarding my vulnerability report:
Oh boy... what can I say... FAIL!
Hello Karl,
Thank you for contacting Dark Age of Camelot Support.
With regard to your appeal, Ticket#: [XXXXX], we cannot field feedback or suggestions regarding how the game may be altered or improved. However, your opinions and thoughts are always valued!
To appropriately submit your suggestions and feedback regarding game content, mechanics, or design, please go to http://darkageofcamelot.com/contact. On this page, you will find a form which will allow you to submit your suggestions and opinions directly to our development team.
This email address is only for issues of a billing or technical nature, and not issues related to feedback or concerns regarding elements of the game.
Thank you for playing Dark Age of Camelot!
XXXX
Oh boy... what can I say... FAIL!
Subscribe to:
Posts (Atom)