Skip to content
This repository was archived by the owner on Dec 6, 2023. It is now read-only.

Commit 23d8a65

Browse files
author
byt3bl33d3r
committed
Refactoring for packiging is now complete!
1 parent 68a9085 commit 23d8a65

19 files changed

+118
-69
lines changed

cme/cmedb.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
class CMEDatabaseNavigator(cmd.Cmd):
1818

19-
def __init__(self):
19+
def __init__(self, db_path):
2020
cmd.Cmd.__init__(self)
2121
self.prompt = 'cmedb > '
2222
try:
2323
# set the database connection to autocommit w/ isolation level
24-
conn = sqlite3.connect('data/cme.db', check_same_thread=False)
24+
conn = sqlite3.connect(db_path, check_same_thread=False)
2525
conn.text_factory = str
2626
conn.isolation_level = None
2727
self.db = CMEDatabase(conn)
@@ -300,15 +300,18 @@ def complete_creds(self, text, line, begidx, endidx):
300300
def main():
301301

302302
parser = argparse.ArgumentParser()
303-
parser.add_argument("path", nargs='?', type=str, default='data/cme.db', help="path to CME database (default: data/cme.db)")
303+
parser.add_argument("path", nargs='?', type=str, default=None, help="path to CME database (default: data/cme.db)")
304304
args = parser.parse_args()
305305

306-
if not os.path.exists(args.path):
306+
db_path = os.path.join(os.path.expanduser('~/.cme'), 'cme.db')
307+
308+
if args.path:
309+
db_path = os.path.expanduser(args.path)
307310
print 'Path to CME database invalid'
308311
sys.exit(1)
309312

310313
try:
311-
cmedbnav = CMEDatabaseNavigator()
314+
cmedbnav = CMEDatabaseNavigator(db_path)
312315
cmedbnav.cmdloop()
313316
except KeyboardInterrupt:
314317
pass

cme/cmeserver.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import BaseHTTPServer
22
import threading
33
import ssl
4+
import os
5+
import sys
6+
from getpass import getuser
47
from BaseHTTPServer import BaseHTTPRequestHandler
58
from logging import getLogger
69
from gevent import sleep
@@ -36,7 +39,11 @@ def stop_tracking_host(self):
3639

3740
class CMEServer(threading.Thread):
3841

39-
def __init__(self, module, context, srv_host, port, server_type='https'):
42+
def __init__(self, module, context, logger, srv_host, port, server_type='https'):
43+
44+
if port <= 1024 and os.geteuid() != 0:
45+
logger.error("I'm sorry {}, I'm afraid I can't let you do that".format(getuser()))
46+
sys.exit(1)
4047

4148
try:
4249
threading.Thread.__init__(self)
@@ -46,12 +53,19 @@ def __init__(self, module, context, srv_host, port, server_type='https'):
4653
self.server.module = module
4754
self.server.context = context
4855
self.server.log = context.log
56+
self.cert_path = os.path.join(os.path.expanduser('~/.cme'), 'cme.pem')
4957

5058
if server_type == 'https':
51-
self.server.socket = ssl.wrap_socket(self.server.socket, certfile='data/cme.pem', server_side=True)
59+
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.cert_path, server_side=True)
5260

5361
except Exception as e:
54-
print 'Error starting CME Server: {}'.format(e)
62+
errno, message = e.args
63+
if errno == 98 and message == 'Address already in use':
64+
logger.error('Error starting CME server: the port is already in use, try specifying a diffrent port using --server-port')
65+
else:
66+
logger.error('Error starting CME server: {}'.format(message))
67+
68+
sys.exit(1)
5569

5670
def base_server(self):
5771
return self.server

cme/crackmapexec.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def main():
4343
@pentestgeek's smbexec https://github.com/pentestgeek/smbexec
4444
4545
{}: {}
46-
{}: {}
46+
{}: {}
4747
""".format(highlight('Version', 'red'),
4848
highlight(VERSION),
4949
highlight('Codename', 'red'),
@@ -63,8 +63,8 @@ def main():
6363
msgroup.add_argument("-H", metavar="HASH", dest='hash', nargs='*', default=[], help='NTLM hash(es) or file(s) containing NTLM hashes')
6464
parser.add_argument("-M", "--module", metavar='MODULE', dest='module', help='Payload module to use')
6565
parser.add_argument('-o', metavar='MODULE_OPTION', nargs='*', default=[], dest='module_options', help='Payload module options')
66-
parser.add_argument('--module-info', action='store_true', dest='module_info', help='Display module info')
67-
parser.add_argument('--list-modules', action='store_true', help='List available modules')
66+
parser.add_argument('-L', '--list-modules', action='store_true', help='List available modules')
67+
parser.add_argument('--show-options', action='store_true', dest='show_options', help='Display module options')
6868
parser.add_argument("--share", metavar="SHARE", dest='share', default="C$", help="Specify a share (default: C$)")
6969
parser.add_argument("--smb-port", dest='smb_port', type=int, choices={139, 445}, default=445, help="SMB port (default: 445)")
7070
parser.add_argument("--mssql-port", dest='mssql_port', default=1433, type=int, metavar='PORT', help='MSSQL port (default: 1433)')
@@ -190,14 +190,16 @@ def main():
190190
modules = loader.get_modules()
191191

192192
if args.list_modules:
193-
for module in modules:
194-
print module
195-
196-
elif args.modules:
197-
for module in modules.keys():
198-
if args.module.lower() == module.lower():
199-
module, context, server = loader.init_module(modules[module]['path'])
200-
break
193+
for m in modules:
194+
logger.info('{:<20} {}'.format(m, modules[m]['description']))
195+
196+
elif args.module:
197+
for m in modules.keys():
198+
if args.module.lower() == m.lower():
199+
if args.show_options:
200+
logger.info('{} module options:\n{}'.format(m, modules[m]['options']))
201+
elif not args.show_options:
202+
module, context, server = loader.init_module(modules[m]['path'])
201203

202204
try:
203205
'''

cme/credentials/secretsdump.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from cme.credentials.ntds import NTDSHashes
88
from impacket.dcerpc.v5.rpcrt import DCERPCException
99
import traceback
10+
import os
1011
import logging
1112

1213
class DumpSecrets:
@@ -28,7 +29,7 @@ def __init__(self, connection, logger):
2829
self.__history = False
2930
self.__noLMHash = True
3031
self.__isRemote = True
31-
self.__outputFileName = 'logs/{}_{}'.format(connection.hostname, connection.host)
32+
self.__outputFileName = os.path.join(os.path.expanduser('~/.cme'), 'logs/{}_{}'.format(connection.hostname, connection.host))
3233
self.__doKerberos = False
3334
self.__justDC = False
3435
self.__justDCNTLM = False

cme/helpers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import random
22
import string
33
import re
4+
import cme
5+
import os
46
from base64 import b64encode
57
from termcolor import colored
68

@@ -14,6 +16,14 @@ def validate_ntlm(data):
1416
else:
1517
return False
1618

19+
def get_ps_script(path):
20+
return os.path.join(os.path.dirname(cme.__file__), 'data', 'PowerSploit', path)
21+
22+
def write_log(data, log_name):
23+
logs_dir = os.path.join(os.path.expanduser('~/.cme'), 'logs')
24+
with open(os.path.join(logs_dir, log_name), 'w') as mimikatz_output:
25+
mimikatz_output.write(data)
26+
1727
def obfs_ps_script(script, function_name=None):
1828
"""
1929
Strip block comments, line comments, empty lines, verbose statements,

cme/moduleloader.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import os
33
import sys
44
import cme
5-
from getpass import getuser
65
from logging import getLogger
76
from cme.context import Context
87
from cme.logger import CMEAdapter
@@ -24,9 +23,13 @@ def module_is_sane(self, module, module_path):
2423
self.logger.error('{} missing the name variable'.format(module_path))
2524
module_error = True
2625

26+
elif not hasattr(module, 'description'):
27+
self.logger.error('{} missing the description variable'.format(module_path))
28+
module_error = True
29+
2730
elif not hasattr(module, 'options'):
2831
self.logger.error('{} missing the options function'.format(module_path))
29-
module_error = True
32+
module_error = True
3033

3134
elif not hasattr(module, 'on_login') and not (module, 'on_admin_login'):
3235
self.logger.error('{} missing the on_login/on_admin_login function(s)'.format(module_path))
@@ -48,19 +51,19 @@ def get_modules(self):
4851

4952
modules_path = os.path.join(os.path.dirname(cme.__file__), 'modules')
5053
for module in os.listdir(modules_path):
51-
if module[-3:] == '.py':
54+
if module[-3:] == '.py' and module != 'example_module.py':
5255
module_path = os.path.join(modules_path, module)
5356
m = self.load_module(os.path.join(modules_path, module))
5457
if m:
55-
modules[m.name] = {'path': module, 'description': m.__doc__, 'options': m.options.__doc__}
58+
modules[m.name] = {'path': module_path, 'description': m.description, 'options': m.options.__doc__}
5659

5760
modules_path = os.path.join(self.cme_path, 'modules')
5861
for module in os.listdir(modules_path):
59-
if module[-3:] == '.py':
62+
if module[-3:] == '.py' and module != 'example_module.py':
6063
module_path = os.path.join(modules_path, module)
6164
m = self.load_module(module_path)
6265
if m:
63-
modules[m.name] = {'path': module_path, 'description': m.__doc__, 'options': m.options.__doc__}
66+
modules[m.name] = {'path': module_path, 'description': m.description, 'options': m.options.__doc__}
6467

6568
return modules
6669

@@ -90,13 +93,9 @@ def init_module(self, module_path):
9093
args.server = getattr(module, 'required_server')
9194

9295
if not self.server_port:
93-
if self.args.server_port <= 1024 and os.geteuid() is not 0:
94-
self.logger.error("I'm sorry {}, I'm afraid I can't let you do that".format(getuser()))
95-
sys.exit(1)
96-
9796
self. server_port = self.args.server_port
9897

99-
server = CMEServer(module, context, self.args.server_host, self.server_port, self.args.server)
98+
server = CMEServer(module, context, self.logger, self.args.server_host, self.server_port, self.args.server)
10099
server.start()
101100

102101
return module, context, server

cme/modules/com_exec.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class CMEModule:
1515

1616
name='com_exec'
1717

18+
description = 'Executes a command using a COM scriptlet to bypass whitelisting'
19+
1820
required_server='http'
1921

2022
def options(self, context, module_options):

cme/modules/empire_agent_exec.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ class CMEModule:
1111
Module by @byt3bl33d3r
1212
'''
1313

14-
name='Empire_Exec'
14+
name='empire_exec'
15+
16+
description = "Uses Empire's RESTful API to generate a launcher for the specified listener and executes it"
1517

1618
def options(self, context, module_options):
1719
'''

cme/modules/example_module.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ class CMEModule:
55
66
'''
77

8-
name = 'Example'
8+
name = 'example module'
9+
10+
description = 'Something Something'
911

1012
def options(self, context, module_options):
1113
'''Required. Module options get parsed here. Additionally, put the modules usage here as well'''

cme/modules/get_computers.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from cme.helpers import create_ps_command, obfs_ps_script
1+
from cme.helpers import create_ps_command, obfs_ps_script, get_ps_script, write_log
22
from StringIO import StringIO
33
from datetime import datetime
44

@@ -8,7 +8,9 @@ class CMEModule:
88
Module by @byt3bl33d3r
99
'''
1010

11-
name = 'GetComputers'
11+
name = 'getcomputers'
12+
13+
description = "Wrapper for PowerView's Get-NetGroup function"
1214

1315
def options(self, context, module_options):
1416
'''
@@ -71,7 +73,7 @@ def on_request(self, context, request):
7173
request.send_response(200)
7274
request.end_headers()
7375

74-
with open('data/PowerSploit/Recon/PowerView.ps1', 'r') as ps_script:
76+
with open(get_ps_script('Recon/PowerView.ps1'), 'r') as ps_script:
7577
ps_script = obfs_ps_script(ps_script.read())
7678
request.wfile.write(ps_script)
7779

@@ -97,6 +99,5 @@ def print_post_data(data):
9799
print_post_data(data)
98100

99101
log_name = 'Computers-{}-{}.log'.format(response.client_address[0], datetime.now().strftime("%Y-%m-%d_%H%M%S"))
100-
with open('logs/' + log_name, 'w') as log_file:
101-
log_file.write(data)
102+
write_log(data, log_name)
102103
context.log.info("Saved output to {}".format(log_name))

0 commit comments

Comments
 (0)