Tuesday, 21 June 2011

Stealing CoreFTP Passwords with Metasploit

Well folks, I'm at it again. The next client to fall is the CoreFTP client. CoreFTP stores it's saved password in the Windows Registry.

They Can be found under HKEY_USERS\\Software\FTPWare\CoreFTP\Sites, with numbered keys for each saved site. The passwords are stored as ascii representations of their hex values(like most of the others we have seen). The ciphertext is encrypted using AES-128-ECB with a static key of "hdfzpysvpzimorhk".

So once again we rely on our ruby openssl implementations to do our decoding for us. First we pack the text from the registry:
               cipher =[encoded].pack("H*")
Then we set up our AES implementation:

                aes = OpenSSL::Cipher::Cipher.new("AES-128-ECB")
aes.padding = 0
aes.key = "hdfzpysvpzimorhk"
password= aes.update(cipher) + aes.final
return password

The  import thing to note here is the aes.padding property. This MUST be set to 0 or you will get bad decrypt errors. It took me quite a while to figure that out. The result, as usual, is an easily decrypted password. This once again highlights that static key encryption in a product like this is next to useless. Products that are going to save sensitive passwords should prompt a user to pick a master password, and sue that as an encryption key. This forever separates the encryption key from the software. It's the only real way to keep that data secure.

I submitted this module today, so it should hopefully get committed sometime in next couple of days. Keep your eyes peeled for post/windows/gather/enum_coreftp_passwords.rb

Sunday, 19 June 2011

SmartFTP Password Recovery with Metasploit - The details

So last night I briefly mentioned the new additions I submitted to Metasploit. It looks like they will get merged after the 3.7.2 Release. Metasploit is in a feature freeze at the moment for that release. I wanted to take the opportunity to discuss how the SmartFTP Password recovery module works. It might help other who want to write similar modules in the future.

The Module Can be seen from the Metasploit Website here:

So let's get the simple stuff out of the way first. We pull the OS information and the root System drive information from the Meterpreter stdapi. We then check the OS to see whether we need to be looking for "Documents and Settings" or "Users" off the system root. We then drop into the appropriate users directory and enumerate the individual user Directories. We build the Directory paths based off the combination of all of these factors.

The enum_subdirs function then takes each of these potential SmartFTP data folder paths. If the path does not exist, or we do not have permission to access it, it will throw an exception caught by the rescue statement and will move on to the next path. If it can access the path, then it will enumerate all of the items in that directory.  If the item ends in .xml then it is added to the list of XML files to be parsed. If it is not an XML file, it is assumed to be a directory and is recursively passed back to the enum_subdirs function. In the rare case that this item is not actually a directory, it should throw an exception which will still be caught by the rescue. Once everything has been recursively enumerated, we should have a list of xmlfiles in the session array @xmlfiles.

For each xml file in the array we then run get_xml.  In get_xml we first try to open the file for reading. If for any reason we cannot do that, we catch an exception  let the users know, and move on to the next file. If we can open it, then we read all of the data into memory and send it to the parse_xml function.  parse_xml uses the Metasploit rexml library to parse the XML. We pull the host, port, username, and encrypted password. If no encrypted password is found, we skip this item and move to the next one since there is no password to steal. Once we have the encrypted password we pass it to the real meat and potatoes, our decryption routine.

The first thing we do, is unpack this encoded data as a series of hex bytes. The string is in fact a series of bytes.  So if the encoded string is "9722972FC57CAE5A78DBD64E23968440C794" then it is actually \x97\x22\x97 etc.

So now let's take a moment to look at the new Railgun function definition I have added. These functions come from Advapi32.dll. This DLL is already defined in Railgun so we just have to add the functions to it's definition:

#Functions for Windows CryptoAPI
railgun.add_function('advapi32', 'CryptAcquireContextW', 'BOOL',[
['PDWORD', 'phProv', 'out'],
['PWCHAR', 'pszContainer', 'in'],
['PWCHAR', 'pszProvider', 'in'],
['DWORD', 'dwProvType', 'in'],
['DWORD', 'dwflags', 'in']])

railgun.add_function('advapi32', 'CryptCreateHash', 'BOOL',[
['LPVOID', 'hProv', 'in'],
['DWORD', 'Algid', 'in'],
['DWORD', 'hKey', 'in'],
['DWORD', 'dwFlags', 'in'],
['PDWORD', 'phHash', 'out']])

railgun.add_function('advapi32', 'CryptHashData', 'BOOL',[
['LPVOID', 'hHash', 'in'],
['PWCHAR', 'pbData', 'in'],
['DWORD', 'dwDataLen', 'in'],
['DWORD', 'dwFlags', 'in']])

railgun.add_function('advapi32', 'CryptDeriveKey', 'BOOL',[
['LPVOID', 'hProv', 'in'],
['DWORD', 'Algid', 'in'],
['LPVOID', 'hBaseData', 'in'],
['DWORD', 'dwFlags', 'in'],
['PDWORD', 'phKey', 'inout']])

railgun.add_function('advapi32', 'CryptDecrypt', 'BOOL',[
['LPVOID', 'hKey', 'in'],
['LPVOID', 'hHash', 'in'],
['BOOL', 'Final', 'in'],
['DWORD', 'dwFlags', 'in'],
['PBLOB', 'pbData', 'inout'],
['PDWORD', 'pdwDataLen', 'inout']])

railgun.add_function('advapi32', 'CryptDestroyHash', 'BOOL',[
['LPVOID', 'hHash', 'in']])

railgun.add_function('advapi32', 'CryptDestroyKey', 'BOOL',[
['LPVOID', 'hKey', 'in']])

railgun.add_function('advapi32', 'CryptReleaseContext', 'BOOL',[
['LPVOID', 'hProv', 'in'],
['DWORD', 'dwFlags', 'in']])

There is a lot going on here. So we'll take it a little slow.
For those who don't know, Railgun is a part of Meterpreter that allows a user to hook Windows libraries and access their functions. In this case we are hooking the Advapi32.dll to gain access to the Windows CryptoAPI(CAPI) functions.

CryptAcquireContextW is the Unicode version of the AcquireContext function. This creates the Cryptographic context we will be working in. The first parameter is a pointer to the provider object. the provider object is, in of itself, a pointer to a data structure that will be initialised by this function. So we pass it a pointer to a DWORD for the pointer to be placed in, and set it as an out parameter so the function will return the pointer information to us. We are not using the container object in this case, so we pass it nil. We then tell it what provider to use in this case it is the Microsoft Enhanced Cryptographic Provider. This is passed as a pointer to a string. We then pass it a value to tell it what type of provider to use. WinCrypt.h normally provides Constants for this, but since we don't have access to those constants we pass it the raw numerical value of that constant. In this case we are passing it the value for the RSA_FULL provider. Finally we pass it the appropriate flags. Like the provider type this expects a constant so we need to pass it a numerical value. We pass it CRYPT_VERIFY_CONTEXT(0xF0000000). For more details on the available flags I suggest you look at the MSDN Doc.

CryptCreateHash creates a hash object for us to user in much the same way that AcquireContext created a provider object. We pass it the provider object as the first parameter. Remembering that this object is a pointer to an abstracted in-memory data structure. Then we pass it the algorithm id for what kind of hash algorithm we will be using. Again, this is typically expecting a constant we don't have so we pass it a numerical value. If this hashing algorithm is expecting a key we pass it a key object. Since we are using md5 we pass it a 0 to tell it we are not using a key. We pass it a 0 for the flags. Finally we pass it a pointer to a place in memory for it to store the hash object. Just like the provider object, this is actually a pointer to a memory structure intialised by this function.

CryptHashData is what will actually create the hash for us and put it in the hash object. The first thing we do is pass it our hash object. We then pass it the data to be hashed. In this case we are hashing the string "SmartFTP". We then pass it the data length of 16, and again we pass it no flags with a 0. This is the first step to deriving our Encryption Key.

CryptDeriveKey is going to take our hash and derive an encryption key from it. We pass it our provider object, an integer value for our encryption algorithm(RC4), the Hash object, our flag, and a pointer to a key object. This key object works the same way as the hash and provider objects did before it. The function derives an RC4 key for us and puts it in the memory structure pointed to by our key object.

CryptDecrypt is where the magic finally happens. We pass it our key object as the first parameter. If the data was to be decrypted and hashed at the same time we would pass it a hash object. Since we do not want to hash the results we pass it a 0. The next parameter is whether this is the final section to be decrypted. We pass this a value as true. We pass no flags, and a pointer to the data to be decrypted. Finally  we pass it the length of the data to be decrypted.

The remaining three functions are eseentialy just garbage collection. They close out the memory structures we initalised along the way.

Some of the parameters in these function calls are still not set up in the most ideal fashion. One of the big tricks to remember is that in the end, a pointer is just a number. So even though ruby has no pointer, just treat them as a numbers and pass them back to LPVOIDS.  I will be smoothing out any wrinkles in these function defs soon, and adding the other CAPI functions that I didn't need for this particular module.

Once the decryption is complete. The module displays the results back to the console. It also reports the data back to the backend database. This means the credentials will be stored for the target machines. If you use MetaSploit Pro (which if you are a professional Penetration Tester, I cannot recommend it enough) this will be especially useful. If the remote machines are in your project scope, those credentials will show up in the host information, and can be used for further module usage.

So there you have it. I hope you find this detailed breakdown useful and/or informative. Stay tuned for further updates and developments. I am continuing on my goal of making it into the Metasploit.com Top contributors list, but I suspect I still have a ways to go.

Saturday, 18 June 2011

Windows Cryptography with Metasploit and SmartFTP Password Recovery

I have submitted two new additions to Metasploit tonight. The first is a series of function definitions for Railgun. These functions are some of the core Windows CryptoAPI functions. It is not a complete list yet. I only added the ones i needed to complete the other piece I'll tell you about in a minute. I will be working voer the next week to get all of the other CAPI functions defined within Metasploit Railgun. In addition to that, I will try to write a library that will server as an abstraction layer for these function calls. This library will wrap the Windows CAPI Functions as well as serve up alot of the same constants provided by the WinCrypt.h header file. I hope that this will make it easier for other module writers to make use of the windows CryptoAPI whenever they may need it in a Post Module.

The second bit of business is what actually spawned this work. I have submitted a module for Extracting/Recovering saved Passwords from the SmartFTP Client. Like the other modules I have submitted, it finds the passwords saved by users, decrypts them and reports them back to the backend database as well as to the display screen.

I want to take a moment to especially thank jduck and chao-mu who helped me talk through some things while I was working on this. As always the support of the community in the #metasploit IRC channel is amazing.

Thursday, 16 June 2011

Metasploit Activities

Well, i know i have been pretty quiet lately, so I thought i'd provide an update. I am very tempted to try and stake a claim on one of the Metasploit bounties , but I don't think I'm quite up to that challenge yet. Instead i will continue to work on some of my other Metasploit Projects:

  1. Build Railgun support for the Windows Crypto API(CAPI)
  2. Finish my SmartFTP password recovery module
  3. Build Meterperter NetStat support for Windows
  4. Some other things that have not solidifed yet.
I hope to get those first 3 items completely done in the next month or so. I want to have them completed and committed before Black Hat. It looks like i will be attending Black Hat courtesy of Rapid 7 this year, but only for the briefings. I unfortunately do not have the means at my disposal to stay for DefCon this year. I look forward to meeting some people in person.

Thursday, 2 June 2011

Stealing Passwords from mRemote

If you don't know mRemote is a tabbed remote connection manager for Windows. It can store and manage a number of different connections, chief among them RDP,VNC, and SSH. It is a popular tool among IT Support people who have to remote into a lot of machines.

When you save connections in mRemote it outputs all of that data into an XML report in your local AppData folder. The passwords are saved in an encrypted format, however this is trivial to circumvent. The passwords are encrypted with AES-128-CBC Rijndael Encryption, and then the IV is pre-pended to the encoded passwords and the whole thing is base64 encoded for output into the XML. The encryption key that is used is the md5 hash of the string "mR3m". So to decrypt these passwords we follow a simple process:

example password:  28kQ15DF4kdW34Mx2+fh+NWZODNSoSPek7ug+ILvyPE=

  1. Get the md5 hash of mR3m and convert it into byte values: \xc8\xa3\x9d\xe2\xa5\x47\x66\xa0\xda\x87\x5f\x79\xaa\xf1\xaa\x8c
  2. base64 decode the saved password data
  3. Take the first 16 bytes of the decoded data and set that as you Initialization vector(IV)
  4. Run AES-128-CBC Decryption feeding your Cipher Text(the remaining bytes from the decoded text), your IV (that first 16 bytes), and your key (\xc8\xa3\x9d\xe2\xa5\x47\x66\xa0\xda\x87\x5f\x79\xaa\xf1\xaa\x8c)
  5. You should get a decrypted password of: password1
Simple and easy, you are now ready to decrypt all of those delicious RDP,VNC, and SSH passwords. To make it all that much easier I have written a new Metasploit POST module that will find the XML files on a compromised machine and decrypt those passwords for you. I just submitted it to Redmine so it hasn't been added yet, but keep your eyes peeled. I suspect it will be in there soon.