Showing posts with label Outlook. Show all posts
Showing posts with label Outlook. Show all posts

Thursday, 12 July 2007

Outlook PST Password Decryption

In my previous article I looked at how encryption worked for Microsoft Outlook PSTs. In this article I am going to see if the encryption is reversable and if coded passwords can be decrypted.

Lets look again at the encryption of 'adad' (based on the content of my previous article):

ItCPVBVPSVMNV
1'a' 0x61 (97)0x000000000x000x61 (97)0x000000000x3AB551CE0x3AB551CE
2'd' 0x64 (100)0x3AB551CE0xCE0xAA (170)0x003AB5510x36034AF60x3639FFA7
3'a' 0x61 (97)0x3639FFA70xA70xC6 (198)0x003639FF0x720767850x72315E7A
4'd' 0x64 (100)0x72315E7A0x7A0x1E (30)0x0072315E0xFA0F3D630xFA7D0C3D

As can be seen, 'adad' is encrypted to 0xFA7D0C3D in 4 steps.

So, how can we get from 0xFA7D0C3D to 'adad'? At first glance I think it isn't possible.

Consider the way the password is encrypted. After iteration 1, we have a NV of 0x3AB551CE, which is then right-shifted in iteration 2 so that the 0xCE component is lost. It simply isn't possible to get from the NV 0x3639FFA7 in iteration 2 back to a PV of 0x3AB551CE. The best we could possibly do is get to 0x3AB551??. In addition, there is no way to calculate BV or C at any iteration, because we need two parts of either P, BV or C.

Unfortunately, it appears the only way to decrypt the password is to break it. The encryption is not reversible.

To start the break, I have the value 0xFA7D0C3D, and a list of potential modifier (M) values. Now remember, as I am reversing and breaking the encryption, I am working backwards. The first value I am using is for the last character of the password.

The first thing I do is work out all the possible modifier values that could have been applied to the value I have. This is easy to work out - because my value (NV) starts with 0xFA, I just need to find any modifiers that start with 0xFA, which yields the following:

  1. 0xFA0F3D63 - 0x001E
  2. 0xFAF83322 - 0x0177

Now we already know that modifiers at positions higher than 0xFF cannot be generated with the ASCII character set (from my previous article on encryption), so I can discard modifier number 2, which leaves me with a single possible modifier, 0xFA0F3D63.

Right, so I now have a value, a modifier and a position. From these, I can calculate a shifted value, which is 0x0072315E (V XOR M), which will give me a PV of 0x72315E?? (left-shift the SV by 8 bits). This gives me the following:

ItCPVBVPSVMNV
?'?' 0x??0x72315e??0x??0x1e0x0072315e0xfa0f3d630xfa7d0c3d

Now I still have no chance of calculating BV or C from P alone, but I can extrapolate potential values for these. I am going to substitute C for various different characters, and then XOR these with P to get an assumed BV. Technically, I should submit C for any valid character from the ASCII character set, but for the purposes of this article I am only going to work with the characters 'a' and 'd'. Any final decryption method would clearly need to implement a much larger character set.

Lets have a look at what results we get with each character:

  • 'a' is character code 0x61, which would give BV = 0x61 XOR 0x1E (C XOR P), which gives a BV of 0x7F. This would result in a PV of 0x72315E7F.
  • 'd' is character code 0x64, which would give BV = 0x7A. This would result in a PV of 0x72315E7A.

Because I have no way of knowing which PV is the correct value, I need to check each of them.

So, I use the first PV, 0x72315E7F (which came from character 'a'). I repeat the same process for this value as I did above for the first value (0xFA7D0C3D). This gives only one potential modifier, 0x72076785 from position 0xC6. I now calculate a potential SV and PV as so:

ItCPVBVPSVMNV
-1'?' 0x??0x3639fa??0x??0xc60x003639fa0x720767850x72315e7f
?'a' 0x610x72315e7f0x7f0x1e0x0072315e0xfa0f3d630xfa7d0c3d

And again I repeat the same process of calculating the BV through character substitution, which gives the following:

  • C = 'a', BV = 0x61 XOR 0xC6, BV = 0xA7, PV = 0x3639FAA7
  • C = 'd', BV = 0x64 XOR 0xC6, BV = 0xA2, PV = 0x3639FAA2

Following this I now take the PV 0x3639FAA7 and run it through the same process. This results in the following modifiers:

  1. 0x36034AF6 - 0x00AA
  2. 0x36b8DEAF - 0x01B7

Now I know that modifier positions above 0xFF aren't permitted so I can discard modifier 2, but again modifer 1 is valid so I calculate SV and potential PV with this:

ItCPVBVPSVMNV
-2'?' 0x??0x3ab051??0x??0xaa0x003ab0510x36034af60x3639faa7
-1'a' 0x610x3639faa70xa70xc60x003639fa0x720767850x72315e7f
?'a' 0x610x72315e7f0x7f0x1e0x0072315e0xfa0f3d630xfa7d0c3d

And again I repeat the same process of calculating the BV, which gives the following possibilities:

  • C = 'a', BV = 0x61 XOR 0xAA, BV = 0xCB, PV = 0x3ab051CB
  • C = 'd', BV = 0x64 XOR 0xAA, BV = 0xCE, PV = 0x3ab051CE

So I take the PV ox 0x3AB051CB and run it again through the same process. This gives a single potential modifier of 0x3AB551ce at position 0x61.

If I repeat the SV and PV calculations with this modifier, it gives me the following:

ItCPVBVPSVMNV
-3'?' 0x??0x050005??0x??0x610x000500050x3ab551ce0x3ab051cb
-2'a' 0x610x3ab051cb0xcb0xaa0x003ab0510x36034af60x3639faa7
-1'a' 0x610x3639faa70xa70xc60x003639fa0x720767850x72315e7f
?'a' 0x610x72315e7f0x7f0x1e0x0072315e0xfa0f3d630xfa7d0c3d

I recalcaulte BV, which gives these possibilites:

  • C = 'a', BV = 0x61 XOR 0x61, BV = 0x00, PV = 0x05000500
  • C = 'd', BV = 0x64 XOR 0x61, BV = 0xCE, PV = 0x05000505

Lets again take the first PV, 0x05000500, and run it through the same process, which yields a single modifier of 0x05005713 at position 0xC7.

This time, if I calculate the SV and PV values, I get:

ItCPVBVPSVMNV
-4'?' 0x??0x005213??0x??0xc70x000052130x050057130x05000500
-3'a' 0x610x050005000x000x610x000500050x3ab551ce0x3ab051cb
-2'a' 0x610x3ab051cb0xcb0xaa0x003ab0510x36034af60x3639faa7
-1'a' 0x610x3639faa70xa70xc60x003639fa0x720767850x72315e7f
?'a' 0x610x72315e7f0x7f0x1e0x0072315e0xfa0f3d630xfa7d0c3d

However, this time I know there aren't any possibilites. A PV of less than 0x01000000 will not yield any modifiers, because there are none that start with 0x00. This means that I know there are no valid letter combinations below where I am now, '?aaaa'.

So I can discard this particular path and move back up to the next possibility, which is at '?daaa'. This has an identical modifier list (because it also starts with a NV of 0x05) and I already know that this will not yield a valid PV, so I can also discard this possibility.

This means I now need to move on to the next possibility, which begins at '?daa'.

I repeat the same process over and over, moving through the other potentials, until I manage to dismiss all possibilites that start '?a'. So I know that the password must be '?d', that is it ends with a 'd'.

So now if I go back to where I started, but work with a 'd' instead of an 'a', I get the following:

ItCPVBVPSVMNV
-1'?' 0x??0x3639ff??0x??0xc60x003639ff0x720767850x72315e7a
?'d' 0x640x72315e7a0x7a0x1e0x0072315e0xfa0f3d630xfa7d0c3d

I then reapply the same rules as before, which dismisses the combinations 'aaad' and 'daad', until I reach '?dad':

ItCPVBVPSVMNV
-3'?' 0x??0x000000??0x??0x610x000000000x3ab551ce0x3ab551ce
-2'd' 0x640x3ab551ce0xce0xaa0x003ab5510x36034af60x3639ffa7
-1'a' 0x610x3639ffa70xa70xc60x003639ff0x720767850x72315e7a
?'d' 0x640x72315e7a0x7a0x1e0x0072315e0xfa0f3d630xfa7d0c3d

Now you'll see we have a P of 0x61, and a SV of 0x0. Look what happens if I calculate the possible BV by using character substitution of C:

  • C = 'a', BV = 0x61 XOR 0x61, BV = 0x00, PV = 0x00000000
  • C = 'd', BV = 0x64 XOR 0x61, BV = 0x05, PV = 0x00000005

We know the 'd' cannot be valid because a PV of 0x5 is below the minimum allowed, which is 0x01000000, but look at the 'a' - it results in a PV of 0x0. This means there are no further calculations to do - we have broken the password - and given a final result of 'adad':

ItCPVBVPSVMNV
-3'a' 0x610x00000000x000x610x000000000x3ab551ce0x3ab551ce
-2'd' 0x640x3ab551ce0xce0xaa0x003ab5510x36034af60x3639ffa7
-1'a' 0x610x3639ffa70xa70xc60x003639ff0x720767850x72315e7a
?'d' 0x640x72315e7a0x7a0x1e0x0072315e0xfa0f3d630xfa7d0c3d

Now, I have demonstrated that the password encryption can be broken, and we can definitely get the valid password from the final coded value.

However, breaking the password in this way is very expensive. I have listed some important points that can affect the performance of the break:

CHARACTER SET
If you consider that at each level there are 223 (0xDF) ASCII character possibilities (assuming that control characters below 0x20 are ignored), and that there may be many possible modifiers at each level (up to 4), this means that at each level there could be 892 possibilities.

This is ok if the password is very short, but for a password of length 5 there are 564,708,431,199,232 combinations (over 564 trillion). At length 10 there are 318,895,612,267,497,741,289,677,389,824 (over 318 trillion trillion)!

We can reduce the cost of breaking passwords significantly if we make assumptions during the character substitution stage. We could work with specific character sets, which would reduce the cost as so:

SetPoss (1)Poss (length 5)Poss (length 10)
All 223892564,708,431,199,232318,895,612,267,497,741,289,677,389,824
0-9A-Za-z248938,120,019,968880,069,171,864,760,718,721,024
a-z10412,166,529,024148,024,428,491,834,392,576

As you can see, reducing the available character set would make a huge difference to the number of possibilities. The scenario listed above, however, assumes the worst case - that there are 4 valid modifiers at each level, which is unlikely. For most PV there are 1 or 2 modifier values.

CHARACTER POSITIONING
In the English alphabet, certain letters are much more likely to appear in words than others.

Using this information, we could order the characters so the most likely characters to be used come first, which means more likely letter combinations are broken earlier in the process.

A good example would be to put the letter 'e' before all others, because it is the most common letter used in English words. Letters such as 'q' could be placed at the end of the list or maybe excluded altogether - just taking 'j' and 'q' out of the character set 'a-z' would reduce the possibilities in a 10 letter password by 55% - 80,000 trillion.

PASSWORD LENGTH
We know that the maximum password length for a PST password is 15 characters.

Using this knowledge, we can ensure that we do not waste time calculating impossible passwords. As soon as we reach a 16th decryption step, we can assume that this is not a possible password.

Additionally, we can save significant time in processing if we make an assumption about the password length.

Consider the following, if I have to calculate all the possible passwords for the character set 'a-z' to a length of 15 characters with the maximum 4 modifiers at each level, there are ((26 * 4) to the 15) possibilities - an amazing 1,800,943,505,506,915,684,277,314,125,824!

However, if I assume the maximum password size is 8, then this becomes ((26 * 4) to the 8) possibilities - a mere 13,685,690,504,052,736. This is over 131 trillion times less possibilities.

Obviously this is several orders of magniture less, and will require significantly less effort to break.

LOWEST LEVEL LETTER SUBSTITUTION
At the bottom level of a decryption break, where there is a NV of 0, we might have a remaining character that is not part of our character set.

A good example is the password 'fred', which encrypts to 0x1B6D2E42.

This password can be broken using the standard method, but by allowing the lowest letter of the password to be substituted by any valid ASCII character, it is actually possible to break this faster. The result is the password '¹mrzab', which can be copied and pasted into Outlook.

If we have assumed our password length is 8 or less characters, this will result in a significantly faster break (over 50%) for passwords such as these, and there is no additional cost involved for us in allowing this.

The only issue is that you may not necessarily obtain the original password.

 

Well that concludes my work on Outlook PST password decryption. I believe I have successfully demonstrated that Outlook PST passwords are vulnerable.

Although, as with SourceSafe passwords, I wonder whether there is really a problem that the passwords are vulnerable. Anyone who is concerned about keeping the e-mail very secure will no doubt implement Microsoft Exchange with Active Directory integrated security - which is infinitely more secure than a PST on the desktop.

As always, if you want to keep your data secure use a long password with mixed case letters, numbers and symbols (if permitted). Using such a technique with Outlook PSTs would significantly increase the amount of work required to perform a break by several orders of magnitude. You have been warned...

Wednesday, 11 July 2007

Outlook PST Password Encryption

In my previous article about Microsoft Outlook, I demonstrated how secured Outlook Data Files (PSTs) could be accessed without having the password for them.

During the article, I noticed a call that took my entered password as a criteria and returned a coded value that was then compared to a value on the stack.

I believe that this is where the password is encrypted and today I want to take a look at how this works.

First of all, referring to my previous article, there is a call at +523B2 in MSPST32, which has a parameter of my previous password:

+523B1PUSHEAX
+523B2CALLMSPST32.+55AAF

In this case, EAX contains the password I entered, 'fred'. When I step over the CALL at +523B2, I notice that EAX now contains the value 0x1B6D2E42 which, for now, I will assume is the coded value of my password.

Then, later on in the proc, at +523CC, this value (which, in the mean time, has been copied to EBX) is compared with the value at ESI-1C, which is 0xFA7D0C3D.

The result is that they are not equal and a dialog is displayed informing me that the password I entered is incorrect.

Now to double check that I am looking in the right place, I enter what I know to be the correct password, 'adad'. The CALL at +523B2 this time sets EAX to 0xFA7D0C3D, which is the same as the value that it will be compared with at +523CC, so I know that this must be where the encryption takes place. If I run the code from here, I see that the incorrect password dialog is skipped over and the PST file is opened.

So, to start looking at the encryption, I set a breakpoint at +523B2 in OllyDBG, and then step into the proc that is called.

The proc has the following code:

+55AAFPUSHDWORD PTR SS:[ESP+4]
+55AB3CALL<&MSVCRT.strlen>
+55AB8CMPEAX, 0F
+55ABBPOPECX
+55ABCJBEMSPST32.+55AC1
+55ABEPUSH0F
+55AC0POPEAX
+55AC1PUSHEAX
+55AC2PUSHDWORD PTR SS:[ESP+8]
+55AC6PUSH0
+55AC8CALLMSPST32.+2AF7
+55ACDRETN4

You will quickly see that all this proc is doing is calculating the password length. If the password is longer than the maximum (0xF), the length is set to 0xF (and stored in EAX).

The proc then calls another proc at +2AF7, which I step into.

This proc has the following code:

+2AF7PUSHEBP
+2AF8MOVEBP, ESP
+2AFAMOVECX, DWORD PTR SS:[EBP+10]
+2AFDMOVEAX, DWORD PTR SS:[EBP+C]
+2B00TESTECX, ECX
+2B02JBEMSPST32.+2B25
+2B04PUSHESI
+2B05MOVZXEDX, BYTE PTR DS:[EAX]
+2B08MOVZXESI, BYTE PTR SS:[EBP+8]
+2B0CXOREDX, ESI
+2B0EMOVESI, DWORD PTR SS:[EBP+8]
+2B11SHRESI, 8
+2B14MOVEDX, DWORD PTR DS:[EDX*4+7100C]
+2B1BXOREDX, ESI
+2B1DINCEAX
+2B1EDECECX
+2B1FMOVDWORD PTR SS:[EBP+8], EDX
+2B22JNZMSPST32.+2B05
+2B24POPESI
+2B25MOVEAX, DWORD PTR SS:[EBP+8]
+2B28POPEBP
+2B29RETN0C

Now this is starting to look more like it.

The first few lines, in +2AF8 to +2B02 simply check to see whether the password has a length and sets ECX to the length of the password.

There is a loop between +2B05 to +2B22. If I examine the loop in detail, we can see the following occuring:

  • +2B05 - The next character code for the next character from my password is moved into EDX.
  • +2B08 - The lowest order byte of the DWORD value held at EBP+8 is moved into ESI. This is 0 on the first iteration of the loop.
  • +2B0C - The character code of the current letter (which is in EDX) is XORed with the byte in ESI and is stored in EDX.
  • +2B0E - The value held at EBP+8 is moved into ESI. This is 0 on the first iteration of the loop.
  • +2B11 - The value in ESI is right-shifted 8 bits.
  • +2B14 - A 32-bit modifier value is loaded into EDX from the data segment of the MSPST module (I will talk more about this in a minute). The position of the value is offset by 4*EDX (or essentialy EDX DWORDs). EDX contains the character code which was XORed at +2B0C.
  • +2B1B - The value in EDX (the modifier) is XORed with value in ESI, and the result is stored in EDX
  • +2B1D - The position of the next character is incremented
  • +2B1E - The loop counter is decremented
  • +2B1F - The value in EDX is stored back in EBP+8 for the next loop iteration.
  • +2B22 - Loop unless ECX = 0

This process takes place for each character in the entered password.

The modifier value I mentioned, which is loaded into EDX at +2B14, is used to "encrypt" each character in the password. There is a predifined list of 575 32-bit values in the list. All are different, with the exception of the last 128 values, which are all 0xAAAAAAAA.

It is important to note though, that as I am using the ASCII character set, it is only possible to use the first 256 values (0-0xFF), as any value in the range 0-0xFF XORed with any value in the range 0-0xFF can only yield a result of 0-0xFF.

So, based on what I have discovered in the above loop, lets look at how 'adad' will be encrypted:

ItCPVBVPSVMNV
1'a' 0x61 (97)0x000000000x000x61 (97)0x000000000x3AB551CE0x3AB551CE
2'd' 0x64 (100)0x3AB551CE0xCE0xAA (170)0x003AB5510x36034AF60x3639FFA7
3'a' 0x61 (97)0x3639FFA70xA70xC6 (198)0x003639FF0x720767850x72315E7A
4'd' 0x64 (100)0x72315E7A0x7A0x1E (30)0x0072315E0xFA0F3D630xFA7D0C3D
 It = loop iteration
 C = character
 PV = previous value (from previous iteration), EBP+8
 BV = lowest order byte of PV (PV = EBP+8)
 P = Position for modifier value, result of C XOR BV (at +2B0C)
 SV = Shifted value, result of PV >> 8 (at +2B11)
 M = Modifier value, looked up from position of data segment + P * 4 (at +2B14)
 NV = New value, result of SV XOR M (at +2B1B)

So you will see from the table above, the 'adad' will give a final value of 0xFA7D0C3D, which is as expected.

In conclusion, I have managed to understand how Outlook PST password encryption takes place. As with SourceSafe's password encryption, this has some potential weaknesses, although it does appear that the encryption for Outlook PST passwords is slightly stronger than SourceSafe's.

In my next article, I hope to look at the weaknesses in the encryption and see if there may be a way to decrypt the password from the encrypted password code.

Tuesday, 10 July 2007

Microsoft Outlook PSTs: Safe or not?

Well I had such a lot of fun looking at SourceSafe password protection, I thought I'd move on to another product that uses password protection, Microsoft Outlook.

I am working with Microsoft Outlook 2002 (10.6516.6626) SP3 at the moment, so I can't guarantee that any of the information included in this article will work for any other version.

The protection I am interested in today is protection on the Outlook Data (.PST) Files. I want to know if I can access the PST file data without a password, even if it is "secured" with one.

I have created a new PST file and set it to use password protection, with a password of 'adad'.

Upon opening Outlook, I try to open the PST (File -> Open -> Outlook Data File...) at which point I am presented with a password request dialog.

I type in a password ('fred') and click OK, to be presented with a message box telling me the password is incorrect.

At this point, I attach to Outlook using OllyDBG and start having a look around:

  1. Start Debug in "Execute until user code" mode

  2. Click OK on the wrong password dialog

  3. Breakpoint hit in OllyDBG in a message proc in the module MSPST32

  4. I want to get out of the message proc into something more useful so I start Debug again in "Execute until Return" mode

  5. Return from the proc, and the next one (it is the same thing)

  6. Find myself in the proc +2390 which is starting to look more interesting

  7. Notice a call to GetDlgItemTextA in the proc, which I guess is when the password I have entered is read, so set a breakpoint on the next line (+23AE)

  8. Run the code, and retry the password

  9. Breakpoint hits at +23AE, and notice my password ('fred') at EBP-10

The code looks like this in the proc I am examining:

+23A8CALLNEAR DWORD PTR DS:[<&USER32.GetDlgItemTextA>]
+23AELEAEAX, DWORD PTR SS:[EBP-10]
+23B1PUSHEAX
+23B2CALLMSPST32.+5AAF
+23B7MOVEBX, EAX
+23B9PUSH10
+23BBLEAEAX, DWORD PTR SS:[EBP-10]
+23BEPUSH0A
+23C0PUSHEAX
+23C1CALL<&MSVCRT.memset>
+23C6MOVESI, DWORD PTR SS:[EBP+C]
+23C9ADDESP, 0C
+23CCCMPDWORD PTR DS:[esi+1C], EBX
+23CFJEMSPST32.+2410

Upon stepping through the code, I can see my password being passed into the proc called at +23B2, and a value being returned in EAX from this. I presume that this proc is where the password is coded to whatever format is used by Outlook (I may explore this another day).

If I step down to the CMP at +23CC, I notice that the value in EAX (which was moved to EBX), is compared with a value at ESI+1C. If the value is different (which it will be), the JE is not taken at +23CF. If the JE is not taken, it is in the code following this point that the invalid password dialog is displayed to me. This leads me to concluce the ESI+1C must contain the password that is associated with the PST file.

To see if this is where the password is verified, I force the JE at +23CF by changing the Z register to on (1) and then continue execution - and the PST file opens in Outlook, and I have full access to it!

What is also interesting is that if I close the PST, and then reopen it (without closing Outlook) I am not presented with the password dialog again - it just opens as it did the first time. Outlook seems to cache the fact that the PST can be opened during this session and doesn't recheck the password security.

Just to see whether I can remove the security without manually forcing the JE at +23CF every time, I modify the JE to a JMP. I can then open any password protected PST by entering any password I want.

However, it is worth noting that modfiying the JE to a JMP doesn't always work. Sometimes the MSPST32 module is unloaded and reloaded into memory (by MSMAPI32) and the modified JE is overwritten.

I'm sure a memory patcher could be produced that would monitor and correct this automatically, or of course the actual DLL itself could be patched.

In conclusion, it appears that the PST password security could be relatively easily overcome in Outlook and that any password-protected PSTs cannot necessarily be considered secure.