EmpireProject / Empire

Empire is a PowerShell and Python post-exploitation agent.
http://www.powershellempire.com/
BSD 3-Clause "New" or "Revised" License
7.43k stars 2.81k forks source link

LaZagne on Empire ? #968

Closed AlessandroZ closed 6 years ago

AlessandroZ commented 6 years ago

Hi guys,

Some times ago, I did a tool called LaZagne to dump lots of credentials from a remote target. It has been easy to add it to the pupy project because it interprets the python code all in memory so nothing is dropped on the disk. However, to be embedded in non python project was quite difficult (except using the binary but it's not really cool).

For forensic purpose, I have developed another tool called LaZagneForensic to retrieve passwords from another host. At fisrt passwords were retrieved from a mounted disk (for forensic analysis) but then I did a powershell script to dump all configuration files from a remote host. Then this new folder should be downloaded to our Linux host and passwords could be decrypted offline.

Lots of passwords can be decrypted without needed the user Windows password but some need it. However, the password could be retrieved using mimikatz or other technics.

I didn't do a pull request because I don't know if it's a good idea and I don't how your manage external tools. In pupy, we use git submodules to be able to update it if needed. Moreover, I didn't analyse your code to check how you could download folders from a remote host (I'm quite bad in powershell).

Here are all steps needed:

Then integrating lazagne will be easy. Here is an example of script to integrate it. It's an adaptation to the following script:

import laZagneForensic

def print_lsa(creds):
    for cred in creds:
        for name, value in cred.iteritems():
            print name
            print dump(value, length=16)
            print 

# print hex value
def dump(src, length=8):
    FILTER = ''.join([
        (len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)
    ])
    if type(src) == unicode:
        src = src.encode('latin1')
    N=0; result=''
    while src:
        s,src = src[:length],src[length:]
        hexa = ' '.join(["%02X"%ord(x) for x in s])
        s = s.translate(FILTER)
        result += "%04X   %-*s   %s\n" % (N, length*3, hexa, s)
        N += length
    return result

def hashdump_to_dict(creds):
    results = []
    for cred in creds:
        for pwd in cred:
            try:
                user, rid, lm, nt, _, _, _ = pwd.split(':')
                results.append({
                    'Category' : 'hashdump',
                    'CredType' : 'hash',
                    'Login'    : user,
                    'Hash'     : '%s:%s' % (str(lm), str(nt))
                })
            except:
                pass

    return results

def cachedump_to_dict(creds):
    results = []

    for cred in creds:
        for pwd in creds[0]:
            try:
                user, d, dn, h = pwd.split(':')
                results.append({
                    'Category' : 'cachedump',
                    'CredType' : 'hash',
                    'Login'    : user,
                    'Hash'     : '%s:%s:%s:%s' % (user.lower(), h.encode('hex'), d.lower(), dn.lower())
                })
            except:
                pass

    return results

def print_results(success, module, creds):
    if not success:
        print '{module}: {error}'.format(module=module, error=str(creds))
        return

    if not creds or all(not cred for cred in creds):
        return

    print '\n------------------- {title} -------------------\n'.format(title=module)

    if 'lsa' in module.lower():
        print_lsa(creds)
    else:
        if 'hashes' in module.lower():
            creds = hashdump_to_dict(creds)

        elif 'cachedump' in module.lower() :
            creds = cachedump_to_dict(creds)

        for cred in creds:
            for k, v in cred.iteritems():
                print u'{key}: {value}'.format(key=k, value=v)
            print

if __name__ == '__main__':

    # password retrieved from the database or specified by the user
    password        = 'SecurePassword'

    # folder dumped using the powershell script (https://github.com/AlessandroZ/LaZagneForensic/blob/master/dump/dump.ps1)
    dump_folder     = '/tmp/dump'

    category        = 'all'
    first_user      = True
    passwordsFound  = False 

    results = laZagneForensic.runLaZagne(category_choosed='all', password=password, dump='remote', root_dump=dump_folder, quiet_mode=True)
    for result in results:

        # get user
        if result[0] == 'User':
            if not passwordsFound and not first_user:
                print 'no passwords found !'

            first_user      = False
            passwordsFound  = False
            print '\n########## User: {user} ##########'.format(user=result[1])

        # get passwords
        elif result[2]:
            passwordsFound = True
            print_results(success=result[0], module=result[1], creds=result[2])

So If you are interested about integrating LaZagne to Empire, it will be great. Otherwise, no problems, I understand very well.

Keep going, I like your works !

DanMcInerney commented 6 years ago

This would be great.

gearcapitan commented 6 years ago

lol

xorrior commented 6 years ago

@AlessandroZ I'd say go for it. Please submit the PR to the dev branch.

AlessandroZ commented 6 years ago

I have checked the empire code and I didn't find an easily way to do it. Because, each modules are able to load a powershell script and get the output back (using the generate function). But in my case, the module would be more complexe. I should be able to launch a script, download the new directory created (or a zip file), and then execute some python code (in order to launch lazagne locally). So the generate function is to limited for my task. So I don't know how to process without changing the core (I don't want to change the core, I do not have enough time).

I was also looking to know a way to download a file from the remote host (for example how to use this kind of function).

You know better your code as I do, so maybe you will be able to find an easy way to do it. I don't think it would be as easy as I supposed.

Let me know, if you have an idea, otherwise I don't think to do a PR. Sorry.

jpluimers commented 6 years ago

@xorrior I think @AlessandroZ needs some help here. I'm not qualified enough to assist here. Do you know anybody who can provide help out?