Building Custom Modules for Core Impact, Part 3 of n-1

In our last installment, I gave you a final hunk of code with several function calls and decided to let you stew for a week before revealing what was going on under the hood. Well, you’ve stewed for a week, so let’s review.

while DoneWithCrack == False:
    if not self.getTasks(str(self.getHashCatPath()).split("\\")[-1]):
        DoneWithCrack=True
    if os.path.exists(outputFile):
        f=open(outputFile)
        self.logMed("Reading Output")
        for l in f:
            if ':' in l:
                hash,password = l.split(":")
                #Find the identity that matched the hash
                #self.logMed("Finding Identity for hash %s" % hash)
                ident = self.__findIdentityWithHash(self._not_cracked_identities,hash)
                if ident:
                    self.logMed("Updating Identity")
                    update_ident = self.__UpdateIdentity(ident,password)  
        f.close()
    else:
        self.logMed("No Output yet. This may take a while. ")
    time.sleep(int(self.getPollingInterval()))

We open up with a while loop that will continue looping until we signal that we’re done cracking the passwords.

Immediately below that, we call a function named getTasks() and pass in the last part of the Hashcat path— specifically the executable name. getTasks() is pretty straightforward.

def getTasks(self,name):

    r = impact.lig.GetWindowsProcessList()
    for i in range(len(r)):
        s = r[i]
        if name in r[i]:
            return r[i]
    return []

We start out by getting a list of running tasks via one of Impact’s local information gathering routines, by calling impact.lig.GetWindowsProcessList(). As you may infer, “lig” stands for Local Information Gathering.

We then search through the results looking for the name we passed in. If it’s found, we return it. Otherwise, we return an empty list.

This serves as a check to verify that Hashcat is still running. Since Hashcat will terminate when it has exhausted the keyspace it was checking or it’s cracked all the supplied hashes. Checking if it’s still running is a fairly accurate mechanism for detecting if it’s worth continuing to poll the output.

Next, we check to see if the output file exists at all – as it can take Hashcat a bit of time before it starts cracking and generate a file, even if it’s empty.

If the file exists, we open it and read through the lines.

hash,password = l.split(":")

The default output format from Hashcat is in the form of hash:password, so we’ll go ahead and split it into two variables above.

Now, we have the fun part. We query against the list of identities that haven’t been cracked yet, stored in _not_cracked_identities within our __findIdentityWithHash() function.

def __findIdentityWithHash(self,NotCracked,hash):
    ##TODO: This assumes that only one identity will have a given hash. Need to update this to handle multiple identities containing the hash in question
    self.logMed("Looking for identity that goes with %s" % hash)
    for i in NotCracked:
        #self.logMed("Current ident hash: %s " % i["NTLM hash"])
        storedhashes = IdentityHashesRetriever.get_hash(i).split(":")
        if hash in storedhashes:
            self.logMed("Found identity for hash: hash")
            username = i.getPropertyOrDefault(Identity.USERNAME, "")
            self.logMed("Hash matched for %s" % username)
            return i
    return []

 

Pretty straightforward code here – we loop through the identities that haven’t been cracked,\ and call out the hash from the Identity Manager for comparison. If the cracked hash matches any of the hashes retrieved, we’ll return the identity. Otherwise, we’ll return an empty list.

If we got something back out of that function, we’ll call down to __UpdateIdentity()

def __UpdateIdentity(self,ident,password):
    identity_copy = ident.copy()
    identity_copy.addProperty(Identity.PASSWORD, password)
    identity_src_host = ident.getPropertyOrDefault(Identity.SRC_HOST, None)
    identity_manager = manager.getImpactIdentityManager()
    self.addIdentity(identity_copy, identity_src_host, False)
    new_identity_with_password = identity_manager.getIdentityFromStorage(identity_copy.storage_uid)
              
    self._not_cracked_identities.remove(ident)
    self._cracked_identities.add(new_identity_with_password)
    identity_manager.delete(ident)

The Impact Identity Manager is a little goofy in that it’s a lot easier to update an entry by modifying it in memory and saving a new one, than to edit an existing entry.

So the first thing we do is make a copy of the identity and add a new property to the entity with an Identity.PASSWORD type to it. Next, we create a blank Source Host property. Then, we instantiate a new Identity Manager by calling manager.getImpactIdentityManager(). To insert the updated entity, we call the addIdentity() function that we inherited from the IdentityCopier class.

To wrap up, we pull the identity back out to make sure it’s there, we remove the original identity from _not_cracked_identities, insert the new identity with the cracked password into _cracked_identities, and then finish it all up by using the Identity Manager that we instantiated to delete the original, uncracked identity.

We should be done, and able to go ahead and hit save in our editor.

Now, we need to test the thing, right? While I do keep a couple of gigabytes of hashes around as a normal thing, it’d probably be much simpler to generate out a known dataset. I like using Steve Thomas’s tool at https://www.tobtu.com/lmntlm.php. It gives you options for what character set, and length you want to use, then gives you a preformatted PWDUMP output. What’s nice about this dataset generator is that it’s easy to relate the usernames to the passwords: The usernames are their own password.

Image
password dump generator

 

 

 

 

 

 

 

 

 

 

 

 

 

Go ahead and copy and paste the PWDUMP format output into a text file.

In Impact, open up a workspace, then look under modules for Import-Export…Identities…Import Identities from PWDUMP

 

Image
import hashes

 

 

 

Point the module at the file you saved with the PWDUMP, and they’ll be imported into impact.

Flip over to the Identities view, and highlight a couple to crack.

Image
select pws

 

 

 

 

 

 

 

Back in the modules view, our module, if you were following along, will be under Tools…Cracking…Crack NTLM using Hashcat

Image
cracking module

 

 

 

Double-click on the module to run it.

Double-check that there’s more than one item in the TARGET field, that the HashCatPath points to your executable, then you’re ready to rock and roll. Click OK...and cross your fingers.

Image
cracking module

 

 

 

If everything goes well (and don’t be upset if it doesn’t), you’ll get Hashcat running, and your machine will start getting warm.

Image
hashcat

 

 

 

 

 

 

 

After a minute or two, the Module Log will start disgorging things like this as they’re cracked.

Image
module log

 

 

 

And you’ll see the passwords start to populate into the Identities list as well.

Image
cracked pws

 

 

 

 

And just like that, we’ve gone and built a minimally functional Impact module. *Ta Da*

 

<< Return to part 2