mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
Added enum_avproducts module, fixed module logging
- Modules now do not print output of commands called from their protocol - Added the enum_avproducts module - Fixed the mimikatz_enum_vault_creds to not display creds with invalid passwords - Added an export command to the SMB protocols DB navigator (as suggested by @hatredshapedlikeaman) - Misc output fixes
This commit is contained in:
+1
-1
@@ -102,7 +102,7 @@ class CMEDatabaseNavigator(cmd.Cmd):
|
||||
self.write_configfile()
|
||||
|
||||
self.workspace = line
|
||||
self.prompt = 'cmedb ({}) >'.format(line)
|
||||
self.prompt = 'cmedb ({}) > '.format(line)
|
||||
|
||||
def do_exit(self, line):
|
||||
sys.exit(0)
|
||||
|
||||
+2
-2
@@ -146,12 +146,12 @@ def main():
|
||||
exit(1)
|
||||
|
||||
if getattr(module, 'opsec_safe') is False:
|
||||
ans = raw_input(highlight('[!] Module is not opsec safe, are you sure you want to run this? [Y/n]', 'red'))
|
||||
ans = raw_input(highlight('[!] Module is not opsec safe, are you sure you want to run this? [Y/n] ', 'red'))
|
||||
if ans.lower() not in ['y', 'yes', '']:
|
||||
sys.exit(1)
|
||||
|
||||
if getattr(module, 'multiple_hosts') is False and len(targets) > 1:
|
||||
ans = raw_input(highlight("[!] Running this module on multiple hosts doesn't really make any sense, are you sure you want to continue? [Y/n]", 'red'))
|
||||
ans = raw_input(highlight("[!] Running this module on multiple hosts doesn't really make any sense, are you sure you want to continue? [Y/n] ", 'red'))
|
||||
if ans.lower() not in ['y', 'yes', '']:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import random
|
||||
import string
|
||||
import re
|
||||
import inspect
|
||||
|
||||
def gen_random_string(length=10):
|
||||
return ''.join(random.sample(string.ascii_letters, int(length)))
|
||||
@@ -11,3 +12,13 @@ def validate_ntlm(data):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def called_from_cmd_args():
|
||||
for stack in inspect.stack():
|
||||
if stack[3] == 'print_host_info':
|
||||
return True
|
||||
if stack[3] == 'plaintext_login' or stack[3] == 'hash_login':
|
||||
return True
|
||||
if stack[3] == 'call_cmd_args':
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import sys
|
||||
import re
|
||||
from cme.helpers.misc import called_from_cmd_args
|
||||
from termcolor import colored
|
||||
from datetime import datetime
|
||||
|
||||
@@ -59,6 +60,12 @@ class CMEAdapter(logging.LoggerAdapter):
|
||||
msg), kwargs
|
||||
|
||||
def info(self, msg, *args, **kwargs):
|
||||
try:
|
||||
if 'protocol' in self.extra.keys() and not called_from_cmd_args():
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
msg, kwargs = self.process(u'{} {}'.format(colored("[*]", 'blue', attrs=['bold']), msg), kwargs)
|
||||
self.logger.info(msg, *args, **kwargs)
|
||||
|
||||
@@ -70,10 +77,22 @@ class CMEAdapter(logging.LoggerAdapter):
|
||||
pass
|
||||
|
||||
def success(self, msg, *args, **kwargs):
|
||||
try:
|
||||
if 'protocol' in self.extra.keys() and not called_from_cmd_args():
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
msg, kwargs = self.process(u'{} {}'.format(colored("[+]", 'green', attrs=['bold']), msg), kwargs)
|
||||
self.logger.info(msg, *args, **kwargs)
|
||||
|
||||
def highlight(self, msg, *args, **kwargs):
|
||||
try:
|
||||
if 'protocol' in self.extra.keys() and not called_from_cmd_args():
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
msg, kwargs = self.process(u'{}'.format(colored(msg, 'yellow', attrs=['bold'])), kwargs)
|
||||
self.logger.info(msg, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
class CMEModule:
|
||||
'''
|
||||
Uses WMI to gather information on all endpoint protection solutions installed on the the remote host(s)
|
||||
Module by @byt3bl33d3r
|
||||
|
||||
'''
|
||||
|
||||
name = 'enum_avproducts'
|
||||
description = 'Gathers information on all endpoint protection solutions installed on the the remote host(s) via WMI'
|
||||
supported_protocols = ['smb']
|
||||
opsec_safe= True
|
||||
multiple_hosts = True
|
||||
|
||||
def options(self, context, module_options):
|
||||
pass
|
||||
|
||||
def on_admin_login(self, context, connection):
|
||||
output = connection.wmi('Select * From AntiSpywareProduct', 'root\\SecurityCenter2')
|
||||
if output:
|
||||
context.log.success('Found Anti-Spyware product:')
|
||||
for entry in output:
|
||||
for k,v in entry.iteritems():
|
||||
context.log.highlight('{} => {}'.format(k,v['value']))
|
||||
|
||||
output = connection.wmi('Select * from AntiVirusProduct', 'root\\SecurityCenter2')
|
||||
if output:
|
||||
context.log.success('Found Anti-Virus product:')
|
||||
for entry in output:
|
||||
for k,v in entry.iteritems():
|
||||
context.log.highlight('{} => {}'.format(k,v['value']))
|
||||
@@ -22,9 +22,14 @@ class CMEModule:
|
||||
for share in shares:
|
||||
if share['name'] == 'SYSVOL' and 'READ' in share['access']:
|
||||
|
||||
context.log.success('Found SYSVOL share')
|
||||
context.log.info('Searching for Registry.xml')
|
||||
|
||||
paths = connection.spider('SYSVOL', pattern=['Registry.xml'])
|
||||
|
||||
for path in paths:
|
||||
context.log.info('Found {}'.format(path))
|
||||
|
||||
buf = StringIO()
|
||||
connection.conn.getFile('SYSVOL', path, buf.write)
|
||||
xml = ET.fromstring(buf.getvalue())
|
||||
|
||||
@@ -25,9 +25,14 @@ class CMEModule:
|
||||
for share in shares:
|
||||
if share['name'] == 'SYSVOL' and 'READ' in share['access']:
|
||||
|
||||
context.log.success('Found SYSVOL share')
|
||||
context.log.info('Searching for potential XML files containing passwords')
|
||||
|
||||
paths = connection.spider('SYSVOL', pattern=['Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml'])
|
||||
|
||||
for path in paths:
|
||||
context.log.info('Found {}'.format(path))
|
||||
|
||||
buf = StringIO()
|
||||
connection.conn.getFile('SYSVOL', path, buf.write)
|
||||
xml = ET.fromstring(buf.getvalue())
|
||||
|
||||
@@ -76,7 +76,8 @@ class CMEModule:
|
||||
user = buf[i+1].split(':', 1)[1].strip().replace('[STRING]', '')
|
||||
passw = buf[i+4].split(':', 1)[1].strip().replace('[STRING]', '')
|
||||
|
||||
creds.append({'url': url, 'user': user, 'passw': passw})
|
||||
if '[BYTE*]' not in passw:
|
||||
creds.append({'url': url, 'user': user, 'passw': passw})
|
||||
|
||||
i += 1
|
||||
except:
|
||||
|
||||
@@ -49,6 +49,7 @@ class CMEModule:
|
||||
shares = connection.shares()
|
||||
for share in shares:
|
||||
if 'WRITE' in share['access'] and share['name'] not in ['C$', 'ADMIN$']:
|
||||
context.log.success('Found writable share: {}'.format(share['name']))
|
||||
if not self.cleanup:
|
||||
with open(self.lnk_path, 'rb') as lnk:
|
||||
try:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import requests
|
||||
import os
|
||||
from requests import ConnectionError
|
||||
#The following disables the InsecureRequests warning and the 'Starting new HTTPS connection' log message
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
@@ -26,6 +27,28 @@ class navigator(cmd.Cmd):
|
||||
def do_exit(self, line):
|
||||
exit(0)
|
||||
|
||||
def do_export(self, line):
|
||||
if not line:
|
||||
return
|
||||
|
||||
line = line.split()
|
||||
|
||||
if len(line) < 3:
|
||||
return
|
||||
|
||||
if line[0].lower() == 'creds':
|
||||
if line[1].lower() == 'plaintext':
|
||||
creds = self.db.get_credentials(credtype="plaintext")
|
||||
elif line[1].lower()== 'hashes':
|
||||
creds = self.db.get_credentials(credtype="hash")
|
||||
else:
|
||||
return
|
||||
|
||||
with open(os.path.expanduser(line[2]), 'w') as export_file:
|
||||
for cred in creds:
|
||||
_,_,_,password,_,_ = cred
|
||||
export_file.write('{}\n'.format(password))
|
||||
|
||||
def do_import(self, line):
|
||||
|
||||
if not line:
|
||||
@@ -437,3 +460,12 @@ class navigator(cmd.Cmd):
|
||||
mline = line.partition(' ')[2]
|
||||
offs = len(mline) - len(text)
|
||||
return [s[offs:] for s in commands if s.startswith(mline)]
|
||||
|
||||
def complete_export(self, text, line, begidx, endidx):
|
||||
"Tab-complete 'creds' commands."
|
||||
|
||||
commands = [ "creds"]
|
||||
|
||||
mline = line.partition(' ')[2]
|
||||
offs = len(mline) - len(text)
|
||||
return [s[offs:] for s in commands if s.startswith(mline)]
|
||||
|
||||
Reference in New Issue
Block a user