Back

The Way Back Machine – Microsoft Word for Windows 1.1a

On March 25, 2014, Microsoft released the source code for Microsoft Word for Windows 1.1a. They said they released it “to help future generations of technologists better understand the roots of personal computing.

I thought it would be interesting to perform an automated code review on it using CheckMarx, to see how they did related to security. The source consisted mainly of C++ code (376,545 lines of code) as well as code written in assembler. The assembler code was not scanned because CheckMarx (or any other automated code scanners) does not support assembler. What came out of the tool was interesting.

CheckMarx indicated that the risk in the code is:

Sk Wayback

The distribution of risk from Informational to High:

Sk Wayback

You have to remember that this code is from the 1980s. Many people did not have a concept of secure code and the development tools did not address security at all.

The top five vulnerabilities are as follows:

Sk Wayback

From the code that I looked at, most of the issues come from the use of unsafe functions. For example:

	if (!strcmp(szClass, "BEGDATA")) 		strcpy(szNameSeg, "Data"); 	else 		strcpy(szNameSeg, szName); 	nSegCur = nSeg;

The function strcpy has been replaced by a safe function strncpy. The function strncpy combats buffer overflow by requiring you to put a length in it. The function strncpy did not exist in the 1980s. The code also contains 123 instances of the goto statement. For example:

LError:  		cmdRet = cmdError; 		goto LRet; 		} 	pdod = PdodDoc(doc);

From the MSDN web site, Microsoft states, “It is good programming style to use the break, continue, and return statements instead of the goto statement whenever possible. However, because the break statement exits from only one level of a loop, you might have to use a goto statement to exit a deeply nested loop.” I am not sure of the C++ syntax back in the 1980s, but maybe break, continue, and return statements did not exist.

You can get a copy of the code for both MS Word and MS-DOS from here: https://www.computerhistory.org/press/ms-source-code.html. Just remember there now are better ways to write code.

Below is the complete list of issues found in the code:

Vulnerability TypeOccurrencesSeverity
Buffer Overflow unbounded180High
Buffer Overflow StrcpyStrcat22High
Format String Attack18High
Buffer Overflow OutOfBound12High
Buffer Overflow cpycat3High
Use of Uninitialized Pointer135Medium
Dangerous Functions58Medium
Use of Uninitialized Variable41Medium
Char Overflow35Medium
Stored Format String Attack19Medium
Stored Buffer Overflow cpycat11Medium
MemoryFree on StackVariable4Medium
Short Overflow2Medium
Integer Overflow1Medium
Memory Leak1Medium
NULL Pointer Dereference341Low
Potential Path Traversal24Low
Unchecked Array Index18Low
Unchecked Return Value11Low
Potential Off by One Error in Loops6Low
Use of Insufficiently Random Values3Low
Potential Precision Problem2Low
Size of Pointer Argument1Low
Methods Without ReturnType500Information
Unused Variable310Information
GOTO Statement132Information
Empty Methods9Information
Potential Off by One Error in Loops6Information

This code is a good example of what not to do.

Programming languages and tools have evolved to make your application much more secure, but only if you teach your developers the concepts of secure coding.

Back

GPU Password Cracking – Building a Better Methodology

In an attempt to speed up our password cracking process, we have run a number of tests to better match our guesses with the passwords that are being used by our clients. This is by no means a definitive cracking methodology, as it will probably change next month, but here’s a look at what worked for us on a recent cracking test.

For a little background, these hashes were pulled from a domain controller in the last six months. The DC still had some hashes stored in the older LanManager (LM) format in addition to NTLM. The password cracking process is also helped by using any cleartext passwords, recovered during the penetration test, as a dictionary.

For this sample, there were:

  • 1000 total hashes (159 LM/NTLM, 841 NTLM-Only)
  • 828 unique hashes
  • 172 accounts with duplicate* passwords (*shared with one or more accounts)

Since LM hashes are weaker, we cracked those first. Initial attacks cracked all of the LM/NTLM hashes, giving us a nice head start (130/828 unique hashes or 15.7% cracked) and a good list to feed back into our other attacks.

The General Methodology:

1. Use the dictionary and rules (Three minutes*) – Remaining Unique Hashes 698

Our dictionary file will typically catch the simple passwords. Our dictionary includes previously cracked passwords and most dictionary-word-based passwords will be in here. Add in a couple of simple rules (d3ad0ne, passwordspro, etc.) and this will catch a few of the “smarter” users with passwords like “1qaz2wsx%“. As for the starting rules, we’re currently using a mix of the default oclHashcat rules and some of the rules from KoreLogic’s 2010 rule list – https://contest-2010.korelogic.com/rules-hashcat.html For our sample set of data, the dictionary attack (with a couple of rules) caught 372 of the remaining 698 hashes (53%).

2. Start with the masking attacks (Fifteen minutes*) – Remaining Unique Hashes 326

Using mask attacks allows us to match common password patterns. Based on the passwords that we’ve cracked in the past, we identified the fifty most common password patterns (that our clients use). Here’s a handy perl script for identifying those patterns – https://pastebin.com/Sybzwf3K.

Due to the excessive time that some of these masks take, we’ve trimmed our list down to forty-three masks. The masks are based on the types of characters being used for the password They follow the following format:

?u?l?l?l?l?d?d?d

This is equivalent to (1 Uppercase Character) (4 Lowercase Characters) (3 Decimals). Or a more practical example would be “Netsp199

For more information on masking attacks with oclHashcat – https://hashcat.net/wiki/doku.php?id=mask_attack

Our top forty-three masks take about fifteen minutes to run through and caught (29/326) 8% of the remaining uncracked hashes from this sample.

3. Go back to the dictionary, this time with more ammunition (10 minutes*) – Remaining Unique Hashes 297

After we’ve cracked some of the passwords, we will want to funnel those results back into our mangling attacks. It’s not hard for us to guess “!123Acme123!” after we’ve already cracked “Acme123“. Just use the cracked passwords as your dictionary and repeat your rule-based attacks. This is also a good point to combine rules. oclHashcat allows you to combine rule sets to do a multi-vector mangle on your dictionary words. I’ve had pretty good luck with combining the best64 and the d3ad0neV3 rules, but your mileage may vary.

Using this technique, we were able to crack four of the remaining 297 (1.3%) uncracked hashes.

4. Double your dictionary, double your fun? (20-35 minutes)

At this point, we’re hitting our limits and need to start getting creative. Along with our hefty primary dictionary, we have a number of shorter dictionaries that are small enough that we can combine them to catch repeaters (e.g. “P@ssword P@ssword“). The attack is pretty simple: a word from the first dictionary will be appended with a word from the second.

This style of attack is known as the combinator attack and is run with the -a 1 mode of oclHashcat. Additional rules can be applied to each dictionary to catch some common word delineation patterns (“Super-Secret!“). The example here would append a dash to the first word and an exclamation mark to the second.

To be honest, this did not work for this sample set. Normally, we catch a few with this and it can be really handy in some scenarios, but that was not the case here.

At this point, we will (typically) be about an hour into our cracking process. From the uniqued sample set, we were able to crack 530 of the 828 hashes (64%) within one hour. From the complete set (including duplicates), we were able to crack 701 of the 1,000 total hashes (70.1%).

5. When all else fails, brute force

Take a look at the company password policy. Seven characters is the minimum? That will take us about forty minutes to go through. Eight characters? A little over two and a half days. What does that mean for our cracking? It means we can easily go after any remaining seven character passwords (where applicable). For those with eight character minimums (or higher), it doesn’t hurt for us to run a brute-force overnight on the hashes. Anything we get out of the brute-force can always be pulled back in to the wordlist for the rule-based attacks.

Given that a fair amount of our cracking happens during a well-defined project timeframe, we’ve found that it’s best for us to limit the cracking efforts to about twenty-four hours. This prevents us from wasting too much time on a single hash and it frees up our cracking rig for our other projects. If we really need to crack a hash, we’ll extend this time limit out, but a day is usually enough to catch most of the hashes we’re trying to crack.

With the overall efforts that we put in here (~24 hours), we ended up cracking 757 of the 1,000 hashes (75.7%).

As luck would have it, I wrote up all of the stats for this blog and immediately proceeded to crack two new sets of NTLM hashes. One was close to 800 hashes (90% cracked) and another had over 5000 hashes (84% cracked). So your results will vary based on the hashes you’re trying to crack.

*All times are based on our current setup (Four 7950 cards running OclHashcat 1.01)

One final item to note. This is not the definitive password cracking methodology. This will probably change for us in the next year, month, week… People are always changing up how they create passwords and that will continue to influence the way we attack their hashes. I’ll try to remember to come back to this next year and update with any changes. Did we miss any key cracking strategies? Let me know in the comments.

Back

Detective control testing during penetration tests Scott Sutherland Guest Blogs for Secure360

If you can’t wait until the Secure360 conference to see Scott Sutherland’s “Attack all the Layers! Again!” presentation or take his class, “Introduction to Penetration Testing” well then here’s a guest blog he did for Secure360 to help tide you over…

Detective control testing during penetration tests

Back

Decrypting MSSQL Database Link Server Passwords

Extracting cleartext credentials from critical systems is always fun. While MSSQL server hashes local SQL credentials in the database, linked server credentials are stored encrypted. And if MSSQL can decrypt them, so can you using the PowerShell script released along with this blog. From the offensive point of view, this is pretty far into post exploitation as sysadmin privileges are needed on the SQL server and local administrator privileges are needed on the Windows server. From the defensive point of view, this is just another reminder that unnecessary database links, database links with excessive privileges, and the use of SQL server authentication rather than integrated authentication can result in unnecessary risk. This blog should be interesting to database hackers and admins interested in learning more.

Linked Servers

Microsoft SQL Server allows users to create links to external data sources, typically to other MSSQL servers. When these links are created, they can be configured to use the current security context or static SQL server credentials. If SQL server credentials are used, the user account and password are saved to the database encrypted and thus they are stored in a reversible format. A one-way hash cannot be used, because the SQL server has to be able to access the cleartext credentials to authenticate to other servers. So, if the credentials are encrypted and not hashed, there must be a way for the SQL server to decrypt them prior to use. The remainder of this blog will focus on how that happens.

Linked Server Password Storage

MSSQL stores link server information, including the encrypted password, in master.sys.syslnklgns table. Specifically, the encrypted password is stored in the “pwdhash” column (even though it’s not a hash). Below is an example:

Ar Mssql

The master.sys.syslnklgns table cannot be accessed using a normal SQL connection, but rather a Dedicated Administrative Connection (DAC) is needed (more information about DAC at https://technet.microsoft.com/en-us/library/ms178068%28v=sql.105%29.aspx). Sysadmin privileges are needed to start a DAC connection, but as local administrator privileges are needed anyways, that shouldn’t be a problem. If local administrators don’t have sysadmin privileges you’ll just have to impersonate the MSSQL server account or local SYSTEM account. More details on this can be found on Scott’s blog at https://www.netspi.com/blog/entryid/133/sql-server-local-authorization-bypass.

MSSQL Encryption

Time to introduce some MSSQL encryption basics. To move ahead, access to the Service Master Key (SMK) is required (more information about SMK at https://technet.microsoft.com/en-us/library/ms189060.aspx). According to microsoft.com “The Service Master Key is the root of the SQL Server encryption hierarchy. It is generated automatically the first time it is needed to encrypt another key.” SMK is stored in master.sys.key_encryptions table and it can be identified by the key_id 102. SMK is encrypted using Windows Data Protection API (DPAPI) and there are two versions of it in the database; one encrypted as LocalMachine and the other in the context of CurrentUser (meaning the SQL Server service account here). We’ll choose the former to extract the key as LocalMachine encryption uses the Machinekey for encryption and it can be decrypted without impersonating the service account. Below is an example of what that looks like:

Ar Mssql

Additional entropy is added to strengthen the encryption but the entropy bytes can be found in the registry at HKLM:SOFTWAREMicrosoftMicrosoft SQL Server[instancename]SecurityEntropy. Once again, local administrator privileges are needed to access the registry key. The entropy is stored in the registry for each MSSQL instance as shown below:

Ar Mssql

After that (and removing some padding / metadata from the encrypted value) we can decrypt the SMK using DPAPI.

Decrypting Linked Server Passwords

Based on the length of the SMK (or the MSSQL version) we can determine the encryption algorithm: MSSQL 2012 uses AES, earlier versions use 3DES. In additional, the pwdhash value has to be parsed a bit to find the encrypted password. The first answer referring Pro T-SQL Programmer’s guide at https://stackoverflow.com/questions/2822592/how-to-get-compatibility-between-c-sharp-and-sql2k8-aes-encryption got me on the right track; even though the byte format didn’t seem to match exactly like detailed on the page, it wasn’t too hard to find the right bytes to encrypt. So now, using the SMK, it is possible to extract all of the link credentials (when SQL Server account is used, not Windows authentication) in cleartext.

Decrypting Linked Server Passwords with PowerShell – Get-MSSQLLinkPasswords.psm1

To automate the decryption of linked server credentials I wrote a PowerShell script called “Get-MSSQLLinkPasswords.psm1”. It can be download from GitHub here:
https://github.com/NetSPI/Powershell-Modules/blob/master/Get-MSSQLLinkPasswords.psm1

The script must be run locally on the MSSQL server (as DPAPI requires access to the local machine key). The user executing the script must also have sysadmin access to all the database instances (for the DAC connection) and local admin privileges on the Windows server (to access the entropy bytes in registry). In addition, if UAC is enabled, the script must be ran as an administrator. Below is a summary of the process used by the script.

  1. Identify all of the MSSQL instances on the server.
  2. Attempt to create a DAC connection to each instance.
  3. Select the encrypted linked server credentials from the “pwdhash” column of the “mas-ter.sys.syslnklgns” table for each instance.
  4. Select the encrypted Service Master Key (SMK) from the “master.sys.key_encryptions” table of each instance where the “key_id” column is equal to 102. Select the version that has been encrypted as LocalMachine based on the “thumbprint” column.
  5. Extract the entropy value from the registry location HKLM:SOFTWAREMicrosoftMicrosoft SQL Server[instancename]SecurityEntropy.
  6. Use the information to decrypt the SMK.
  7. The script determines the encryption algorithm (AES or 3DES) used to encrypt the SMK based on SQL Server version and SMK key length.
  8. Use the SMK to decrypt the linked server credentials.
  9. If successful, the script displays the cleartext linked server credentials. Below is an example of the end result:

Ar Mssql

I’ve tested the script with MSSQL 2005, 2008, 2012, 2008 Express, and 2012 Express. There might be some bugs, but it appears to work reliably. Please let me know if you notice any errors or if I did not account for certain situations etc.

Back

DeKrypto – Padding Oracle attack against IBM WebSphere Commerce (CVE-2013-05230)

Background

IBM WebSphere Commerce or WebSphere Commerce Suite (WCS), developed by IBM, is a software platform framework for e-commerce and is actively being used by giant retailers.

While working on an engagement last year, I stumbled upon a crypto vulnerability in the IBM Websphere Commerce framework, originally found by VSR Security (CVE-2013-05230). Essentially the krypto parameter found in some URLs could be decrypted using a padding oracle attack. Since no public exploit has been published as time of this writing, I figured it might be an interesting exercise to write one.

IBM uses their own crypto library for Cipher Block Chaining (CBC) ciphers, but my guess is that the implementation will be approximate to the OpenJDK snippet found at: https://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/com/sun/crypto/provider/CipherCore.java

 if (decrypting) {

  if (outputCapacity < paddedLen) {
      cipher.save();
  }
  // create temporary output buffer so that only "real"
  // data bytes are passed to user's output buffer.
  byte[] outWithPadding = new byte[totalLen];
  totalLen = finalNoPadding(finalBuf, finalOffset, outWithPadding,
                            0, totalLen);

  if (padding != null) {
      int padStart = padding.unpad(outWithPadding, 0, totalLen);
      if (padStart < 0) {
          throw new BadPaddingException("Given final block not "
                                        + "properly padded");
      }

This crypto library will throw a BadPaddingException when invalid padding is encountered. It is then up to the code that is using this library to handle this exception. In this case, IBM WebSphere Commerce framework seems to leak the information about the padding byte by returning a different response when invalid padding occurs.

Detection

Once you have found a page with krypto URL parameter, differentiate between the following conditions:

  1. Valid ciphertext decrypted
  2. Valid padding – You will need this one to de-krypto 🙂
  3. Invalid padding error

In real world scenario, I found condition (1) and (2) are the same for most of the time. Here is how to test it:

Let us assume we have this valid krypto value:

krypto=rKPqPoqBmZV96l9Ot5GLUtgQwuEYt4oDEG[TRUNCATED]
Kt Dekrypto

Record the normal response – this is condition (1)

Replacing first few characters and run it again, record the response – this is condition (2):

krypto=AAAqPoqBmZV96l9Ot5GLUtgQwuEYt4oDEGrhpdNbubd[TRUNCATED]
Kt Dekrypto

Delete random characters and run it one final time, record the response – this is condition (3):

krypto=qPoqBmZV96l9Ot5GLUtgQwuEYt4oDEGrhpdNbubd[TRUNCATED]
Kt Dekrypto

You can use Burp’s Comparer tool to compare those responses. If (3) is different from (2) and (1) then it may be possible to decrypt this parameter.

Exploitation

Padding oracle attack is not specific to any cipher, rather it is a generic attack against CBC ciphers. Therefore any padding oracle implementations will work in this scenario. I have looked at several padding oracle algorithms, and Ron Bowes’ algorithm by far is the fastest one. The reason is, most padding oracle algorithms iterate over the ciphertext bytes of [Block (n-1)] randomly (bytes ranging from 0-255) to find the plaintext of [Block n]. Ron’s algorithm also iterates over the ciphertext bytes of [Block (n-1)]; but instead of doing so randomly, it loops over a defined character set first (which is composed of ASCII characters, bytes ranging from 32-126), then the rest of the possible byte values (0-31 and 127-255). This greatly reduces number of requests sent, since most meaningful string is composed of ASCII characters.

In addition, I made the following adaptations to Ron’s poracle framework in order for the exploit to work with this particular case:

Encoding/decoding

Ron’s Bowes’ script assumes the payload is in hexadecimal format. So extra encoding/decoding of the krypto parameter is required. The decoding process is as follow:

  1. URL decode key characters (including newline)
  2. Base64 decode
  3. ASCII encode

Encoding steps:

  1. ASCII decode
  2. Insert newline character at every 77th character (RFC 2045 or 4880)
  3. Base64 encode
  4. URL encode key characters

Format of payload

Ron’s original script is made on the assumption that the server will decrypt any two-block payload provided by the attacker. Let us assume that our valid ciphertext blocks is:

[Block 0] [Block 1] [Block 2] [Block 3]

To decrypt [Block 2], we need to send

[Block 1] [Block 2*] 

and wait until the server returns padding error.

However, with IBM Web Commerce, the server does not decrypt any arbitrary two-block payload. It seems to require a valid header or expect certain values at the beginning of the block. Therefore, in order to decrypt [Block 3], we need to send:

[Block 0] [Block 1] [Block 2*] [Block 3]

This is an easy fix, I only needed to append the early blocks to the payload.

Parallelization

  • I added support for multi-threading. The script uses Meh’s Ruby thread pool library to reduce the overhead of creating and destroying threads.
  • I also added the ability to skip already-decrypted blocks and save temporary results to a session file. In situations where the connection ends abruptly, the script only needs to work off the remaining blocks.

Usage

Usage: Usage: Dekrypto.rb [options]

Specific options:
    -s, --sort                       Sort temporary results
    -v, --verbose                    Show debug messages
    -t, --threads SIZE               Set threadpool size
    -f, --file FILE                  Save temporary results to file
    -h, --help                       Show this message

Example

Running test server:

ruby KryptoTestServer.rb

Running Dekrypto script with verbose output, ten threads, saving temporary results to a text file
(decrypted.txt)

ruby DeKryptoDemo.rb -v -f decrypted.txt -t 10

Ouput

Temporal Result:
0,
1,1996&use
2,rName=de
3,rp%20&pa
4,ssword=t
5,his+is+a
6,+secure+
7,password
8,&promoti
9,onCode=S
10,PRING+20
11,13

DECRYPTED: 1996&userName=derp%20&password=this+is+a+secure+password&promotionCode=SPRING+2013
DURATION: 12.66 seconds

Limitation

When testing against real applications, I notice that some blocks may not be decrypted properly. My guess is that the server may catch earlier exception in the decoding phase (at either the URL decoding step or the UTF-8 decoding step) and return valid response. Currently, I do not know how to overcome this limitation so any suggestions will be much appreciated.

The source code could be found at: https://github.com/NetSPI/Dekrypto

References

Discover how NetSPI ASM solution helps organizations identify, inventory, and reduce risk to both known and unknown assets.

X