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.

Monday, 9 July 2007

The SSAPI Patcher

In my first post about SourceSafe, I discussed how SourceSafe security can be bypassed by modifying an instruction in the SSAPI library.

As promised, I have now produced a tool to automate this process.

The tool has the following features:
  • Patches in-memory instances of SSAPI. You can use this if you do not wish to modify an on-disk copy of SSAPI.DLL.
  • Patches on-disk instances of SSAPI. This will permanently remove the password protection from SourceSafe on your PC.

Figure 1 shows a screenshot of the patcher tool.


To patch an in-memory copy of SSAPI, click the Patch Mem button. This will patch all running SourceSafe programs.

To patch an on-disk copy of SSAPI, click the Patch DLL button. You will need to browse to the DLL that needs patching. A backup copy of the DLL will be made by the program before a patch is made.

I have rather creatively named the tool the SourceSafe Password Patcher, and it can be downloaded from this location: http://www.memia.biz/blogs/c2o/sspp.exe.

The tool is written entirely in C# in Microsoft .NET 2.0. I may produce a C++6 version later on for greater compatibility, but only if someone asks for it.

If you would like the source code, please ask - but as with the previous tool, you will have much more fun coding a patch yourself from the description in my first SourceSafe article, 'Is SourceSafe "Safe"?'.

Enjoy!

Sunday, 8 July 2007

SourceSafe Password Tool

Well I had such a lot of fun over my previous articles playing with SourceSafe and seeing what we could do with passwords so I decided to produce a tool which demonstrates all of the previous SourceSafe password articles, with the exception of the SSAPI code patch (I might do that one later).

I've named the tool quite aptly, the SourceSafe Password Cracker, and it provides the following functionality:

  • Encrypt a password to a coded value
  • Attempt to crack a password from a coded value
  • Attempt to guess potential password lengths that would produce valid passwords
  • Attempt to break a SourceSafe UM.DAT user file
Figure 1 contains a screenshot of the main screen:

To Encrypt a Password:
Click the "Encrypt password" radio button, and enter the password you want to encrypt in the "Password" text box. Click the Go button and the encrypted password will be shown in the Output box.

To Attempt to Crack a Password from a Coded Value:
Click the "Crack password" radio button, and enter the coded password in the "Crypto code" text box. Click the Go button and all the potential solutions for that code will be displayed in the Output box.

To Guess Password Lengths from a Coded Value:
Click the "Guess lengths" radio button, and enter the coded password in the "Crypto code" text box. Click the Go button and all the potential lengths and coded values for the entered code will be displayed in the Output box.

To Attempt to Break a SourceSafe UM.DAT User File:
Click the "Crack password file" radio button, and click the Go button. On the browse dialog that appears, browse to the file you would like to break and click Open. Any user accounts in the file will be displayed along with potential solutions to the coded passwords.

Other Functions:
  • Click the About button to see some information about the tool.
  • Click the Clear button to clear the Output box.
You can download the file from this location:
http://www.memia.biz/blogs/c2o/sspc.exe.

Regarding the tool itself, it is a Microsoft .NET 2.0 application written entirely by me in C#. I might produce a .NET 1.1 version of the tool at some point.

If you are desparate for the source code, please contact me and I might be able to send it to you, although you will have much more fun writing your own implementation of the articles I published.

Enjoy!

Saturday, 7 July 2007

Decrypting SourceSafe User List Passwords

In my previous article ('SourceSafe Password Decryption' parts one and two) I discussed how to break SourceSafe passwords so that you could gain access to a SourceSafe database even if you didn't have the password for the user. I demonstrated that if you had the encrypted code of the password, you could generate a password that would produce the same code as this.

However, what do you do if you don't have the password code? To be honest, unless you had generated one yourself (using my 'SourceSafe Password Encryption' article) it seems unlikely that you would have it.

Well the good news is that the password code is stored and is freely available in the SourceSafe file um.dat, which is stored in the data directory under your SourceSafe repository root folder.

If you open the file using a hex editor (I recommend a purchased copy of UltraEdit) then you basically see the user database for SourceSafe.

If you refer to Figure 1, you will see a hex dump of the start of the file.

The first user account (in this case Admin) begins at offset 0x7C (124), and each user account in 0x40 (64) bytes in length. This means that there must be (file_length - 0x7c) / 0x40 users in each file. In the case of my um.date file, which is 2108 bytes, there are 31 users: (2108 - 124) / 64 = 31.

In Figure 1, the user account is highlighted by a green box.
Inside the user account, the user name is obvious, at +8 bytes, and the user name can occupy up to 31 bytes.
The actual password code is located at +0x28 (40) bytes and is shown in Figure 1 inside a red box. The password code is always 2 bytes in length, so in this case the password for the Admin user is 0x6DAF (28079).

Now we have ontained the password code we can decrypt it in accordance with my previous articles. This process can be repeated for each user in the file, if required.

SourceSafe Password Decryption Part 2

In my previous article I managed to demonstrate that the password in SourceSafe could be broken if the code for the actual password portion could be obtained.
This is easy if the length of the password is known, but of course this will not be the case most of the time.

In order to break the password, we need to ascertain the length of the password portion. I will again consider my admin password 'ADAD', which has been coded (in full) to 0x6DAF (28079).
I don't know the length of this password though, I just have the full code 28079.

If I subtract all possible filler codes from this password, I get the following list of values:

Pot LenFillerRemain
028304-255
12801267
227657422
3270741005
4259592120
5249973082
6234934586
7215396540
8198268253
91752110558
101556112518
111278315296
12977318306
13638821691
14318024899
15028079


Assuming that I don't know that 2120 is the correct code, I need a way of working out which remaining codes are valid. Obviously, 0 isn't valid (-255), so we know this is not a blank password.

The answer, as it turns out, is quite straight forward. Basically, if you consider all the characters between 0-9 and A-Z (remember all passwords are converted to upper case), and how they are coded (XOR 0x96), then the lowest possible password code is 160 (0xA0), for '6', and the highest is 223 (0xDF) for 'I'.
Now if, at each potential length, we work out the values of the equivalent lengths of '6's and 'I's, as so:

Pot LenMin (6)Max (I)
000
1160223
2480669
39601338
416002230
524003345
633604683
744806244
857608028
9720010035
10880012265
111056014718
121248017394
131456020293
141680023415
151920026760


It becomes clear that for the remaining code to be valid for a length 4 password, it has to fall between the range 1600 ('6666') and 2230 ('IIII').

If you consider our remaining codes from our coded password (28079), I have listed the codes that appear to fall within the valid ranges:

Pot LenFillerRemainValid?
028304-255No
12801267No
227657422No
3270741005Yes
4259592120Yes
5249973082Yes
6234934586Yes
7215396540No
8198268253No
91752110558No
101556112518No
111278315296No
12977318306No
13638821691No
14318024899No
15028079No


Based on the above list, we could actually have a valid password consisting of 3, 4, 5 and 6 characters for the code 28079.

From my example in my part one of this post, we know that a 4 character password could be 'KNSB'. There are many other 4 character passwords that would generate a code of 28079.

Based upon the above list though, I want to see if I can also generate 3, 5 and 6 character passwords.

Working with a 3 character password which has a target code of 1005, if I use the lowest possible password, '666', I get a value of 960, thus:

PosChar CodeCode ValueTotal
154 (0x36) '6'160 * 1160
254 (0x36) '6'160 * 2 = 320480 (160 + 320)
354 (0x36) '6'160 * 3 = 480960 (480 + 480)


This is exactly 45 less than our intended target code, 1005.
If I add a value of 1 to the character at position 1, this will increase the code by 1.
Adding a value of 1 to character position 2 will increase the code by 2, and so on.

So to make an additional 45, without causing any of the codes to pass above the maximum ('I', 223), the simplest solution is to add 15 to the coded value of position 3, so change the code value 160 to 175 (which is the coded value of '9'):

PosChar CodeCode ValueTotal
154 (0x36) '6'160 * 1160
254 (0x36) '6'160 * 2 = 320480 (160 + 320)
357 (0x39) '9'175 * 3 = 5251005 (480 + 525)


So this means a potential 3 character password could be '669'.

Taking this idea and applying it to the 5 and 6 character codes, we get the potential passwords '76PII' and '6XIIII' respectively.

I tried all of these in SourceSafe and was immensely pleased to discover that they all worked.

This article has demonstrated that it is possible to break SourceSafe passwords, and using the above method I could gain access to a SourceSafe repository using any user account... providing I know the password code.
Of course, as I am unlikely to have the code (without using a debugger), I am going to try and find a way to get the codes directly from SourceSafe in my next article...

Friday, 6 July 2007

SourceSafe Password Decryption Part 1

In my previous article, I set myself the challenge of trying to decrypt the administrator password in SourceSafe. In the article, I worked out and demonstrated how passwords are "encrypted" in SourceSafe.

Following on from this, I'm going to spend some time trying to work out how they could be decrypted.

To start, refer to the encryption formula again:
Sum (char_position(char XOR 0x96))

Sadly, I never managed to finish my maths A-level, let alone a degree, so I am not a maths wizard by any means. Trying to figure out a way to reverse this using a simple formula is not proving easy. The best I could come up with was:
n = p1(c1 XOR 150) + p2(c2 XOR 150) + p3(c3 XOR 150)... up to p15(c15 XOR 150)
c = char, p = position, n = final result

Frankly, I have absolutely no idea how to get px or cx when you only have n. I don't even know if it can be reversed (I would guess not without either p or c). Any suggestions are most welcome!

So this means that I am not going to be able to decrypt the password - the only choice I have is to break the password.

Thinking again about the encryption routine, it is obvious that there are severe weaknesses in the encryption.

If we consider that all passwords shorter than 15 characters have filling characters from the string "BrianDavidHarry" appended to them before encryption.
If we encrypted the filling characters to calculate their values at each particular password length, we can remove this portion from the coded value of a password to ensure we are only left with the coded portion of the password that represents the actual password, thus:

Pw LengthCoded PortionCode Value
0BrianDavidHarry28304 (0x6E90)
1BrianDavidHarr28012 (0x6D6C)
2BrianDavidHar27657 (0x6C09)
3BrianDavidHa27074 (0x69C2)
4BrianDavidH25959 (0x6567)
5BrianDavid24997 (0x61A5)
6BrianDavi23493 (0x5BC5)
7BrianDav21539 (0x5423)
8BrianDa19826 (0x4D72)
9BrianD17521 (0x4471)
10Brian15561 (0x3CC9)
11Bria12783 (0x31EF)
12Bri9773 (0x262D)
13Br6388 (0x18F4)
14B3180 (0x0C6C)
150 (0x0000)


Consider our current administrator password "adad", which is coded to 0x6DAF (28079). For now, I will assume that I know the length of the password, but not the contents.

If I remove the filler coded portion of the password (which will be 25959 for a length 4 password), I am left with a value of 0x0848 (2120).

Double checking, I know that this is the correct value by working out how it would be encrypted:
PosChar CodeCode ValueTotal
165 (0x41) 'A'215 * 1215
268 (0x44) 'D'210 * 2 = 420635 (215 + 420)
365 (0x41) 'A'215 * 3 = 6451280 (635 + 645)
468 (0x44) 'D'210 * 4 = 8402120 (1280 + 840)

So I know that 2120 is the correct value of the password portion of the code, but I have no idea what the actual characters are in it.

This doesn't actually matter though. I am not trying to decipher the original password, just figure out what I need to type into the login screen in SourceSafe to make it appear that I am typing in that users password.
For example, consider what happens if I enter the code 'KSNB':
PosChar CodeCode ValueTotal
175 (0x4B) 'K'221 * 1221
283 (0x53) 'S'197 * 2 = 394615 (221 + 394)
378 (0x4E) 'N'216 * 3 = 6571280 (615 + 657)
466 (0x42) 'B'212 * 4 = 8482120 (1272 + 848)

No way! KSNB is the same password code as ADAD?!

Upon brining up SourceSafe Admin and tapping in KSNB I am very pleased to see that I am logged in as administrator.

I can even change the password for the admin user, using KSNB as the old password and whatever I feel like as the new one!

This is good news, because it means that if I obtain the coded portion of a password, I can work out a sequence of characters that will generate that code and it will code to the the same value as the real password.

However, how am I going to obtain the coded portion of a password when I don't know the length of the password?

Finding the length of the password is going to prove to be more troublesome, I'm sure...

SourceSafe Password Encryption

Well it was fun getting administrative access to SourceSafe in my previous article, and if anyone ever forgot their password at least they could gain access to the tool, but it doesn't really provide a full solution because we still haven't got the password for the administrators account.

So my next challenge was to see if I could decrypt the administrator password, and to start down this road I needed to work out how the password is encrypted.

You might remember from my previous article, 'Is SourceSafe "Safe"', this call in SSAPI:
3DCE6 CALL SSAPI.3E6D0

And this seemed to take the password off the stack ("Password" in the above case) and set the value of EAX to a number (0x6A10 in this case).


I also notice that the comparison at 3DCEE compares this with the value 0x6DAF (which I assume is the coded version of the password "adad").

Well the only reasonable thing to do is see what is happening in the proc at 3E6D0.

I won't list the proc here (there's not much point - you can look yourself) but there are a few things to note in it:
  1. Whatever password I have entered is converted into upper case (at 3E6F2)
  2. The password must be 15 characters - if the entered password is shorter then letters from the string "BrianDavidHarry" will be appended to the end (see 3E6F7 to 3F70C). So if I entered "password", this will be changed to "PASSWORDBrianDa"
  3. If the password is empty, the full string "BrianDavidHarry" will be used
  4. The appended "BrianDavidHarry" string is not converted to upper case

So, now we get to 3E714, and this is where the actual codification takes place:
3E714 XOR EAX, EAX
-- 3E716 MOVSX DX, BYTE PTR SS:[ESP+EAX+8]
/ 3E71C XOR EDX, 0x96
/ 3E722 LEA ECX, DWORD PTR DS:[EAS+1]
/ 3E725 IMUL EDX, ECX
/ 3E728 ADD ESI, EDX
/ 3E72A INC EAX
/ 3E72B CMP EAX, 0xF
-- 3E72E JL SHORT SSAPI.3E716

So immediately you will see that there is a loop is betwen 3E716 and 3E72E, the counter is stored in EAX and there are 15 steps.

In 3E716, the next character value is read from the password and stored in DX.

The character value (in EDX) is the XORed with 0x96 (150) although I have no idea why.

In the next two lines the value in EDX is multiplied by the counter + 1.

The resulting value in EDX is then added to the value in ESI (which is, of course, 0 at the first loop iteration).

After we drop out of the loop, we see the value 0x6A10 in ESI, which is moved into EAX before the proc returns... as we expected from the call at 3DCE6!

So, the password code is encrypted in the following way:
Sum (char_position(char XOR 0x96))

In my opinion, hardly a fantastic way of securing the passwords. I know I have used XOR myself in the past to attempt to hide password data, but I wouldn't ever recommend it as a secure way of hiding anything.

In the case of SourceSafe though, I guess it is sufficient. Or is it...?

Thursday, 5 July 2007

Is SourceSafe "Safe"?

For some random reason, which I can't think of right now, I decided it would be fun to see how secure SourceSafe was, and whether access could be gained to the repository without a password. I am using Visual SourceSafe 6.0a (Build 8987) for this article.

To start with, I thought it would be useful to have a look at the SourceSafe Administration Tool, SSADMIN.EXE, and see if I could gain administrative access to it without having a password.

First of all, I load OllyDBG and open and run the SSADMIN.EXE application.

Finding the code that I was interested in was fairly straight forward:

  1. Entered a garbage password
  2. Clicked "OK" to attempt to log into the tool
  3. Saw the "Invalid password" dialogue screen
  4. Paused execution in OllyDBG
  5. Started debug in "Execute until user code" mode
  6. Went back to the tool and clicked "OK" on the dialog screen
  7. Breakpoint triggered in OllyDBG

It was then a simple case of setting a few breakpoints in different locations and attempting the login procedure a few times.

Eventually I managed to track down the procedure call to SSAPI where the password I had entered was coded and compared to the stored administrator password (which was coded).

I found the following code:

3DCE5 PUSH EAX
3DcE6 CALL SSAPI.3E6D0
3DCEB ADD ESP, 4
3DCEE CMP WORD PTR SS:[ESP+78], AX
3DCF3 JE SHORT SSAPI.3DD16

The call to a proc at 3DC36 seemed to be where the password was coded, which has been pushed onto the stack from EAX.
Stepping over the proc call causes EAX (or specifically AX) to have been changed, in this case to 0x6A10 (which seems to be the coded password).
At 3DCEE there is then a comparison between ESP+78 (which contains the value 0x6DAF) and AX (which now contains 0x6A10). These are definitely not equal, of course, so the JE at 3DCF3 is not taken and the result is that the "Invalid Password" dialog is displayed.

So, what will happen if which force the JE at 3DCF3 to be taken - surely this wouldn't be enough for the user to be allowed administrative access to the tool...?

Setting a breakpoint at 3DCF3, I re-enter the wrong password and am taken back to OllyDBG where the breakpoint has triggered, and again the jump will not be taken, which is quickly rectified by modifying the Z register to on (1), and now the jump will be taken.

I continue running the program, and now have full access to the tool!

So it turns out that gaining access to the SourceSafe Administration tool wasn't that difficult after all. The code portion in SSAPI is also used by SourceSafe itself too, so I can gain access to the repository using the same method.

Now all that remains is to decide whether to write an in-memory patcher for SSAPI or whether to permanently patch the SSAPI.dll...