Showing posts with label SourceSafe. Show all posts
Showing posts with label SourceSafe. Show all posts

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...