Initial commit of Egress-Assess
parent
6d2a830ba0
commit
692fd3e9d1
|
@ -0,0 +1,459 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# This tool is designed to be an easy way to test exfiltrating data
|
||||
# from the network you are currently plugged into. Used for red or
|
||||
# blue teams that want to test network boundary egress detection
|
||||
# capabilities.
|
||||
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import ssl
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
import urllib2
|
||||
from ftplib import FTP
|
||||
from ftplib import error_perm
|
||||
from SocketServer import ThreadingMixIn
|
||||
from threading import Thread
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler
|
||||
from BaseHTTPServer import HTTPServer
|
||||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import FTPServer
|
||||
|
||||
|
||||
class GetHandler(BaseHTTPRequestHandler):
|
||||
# Some of the http server code came from Dave Kennedy's AES shell
|
||||
# over http - the server specific code
|
||||
|
||||
# should be performing GET requests Help from
|
||||
# http://pymotw.com/2/BaseHTTPServer/
|
||||
def do_GET(self):
|
||||
|
||||
# 404 since we aren't serving up any pages, only receiving data
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
# handle post request
|
||||
def do_POST(self):
|
||||
|
||||
# Gather the Posted URI from the agent/browser
|
||||
# parsed_path = urlparse.urlparse(self.path)
|
||||
uri_posted = self.path
|
||||
uri_posted = uri_posted.replace("/", "")
|
||||
#incoming_ip = self.client_address[0]
|
||||
# current directory
|
||||
exfil_directory = os.path.join(os.getcwd(), "data")
|
||||
loot_path = exfil_directory + "/"
|
||||
|
||||
# Info for this from -
|
||||
# http://stackoverflow.com/questions/13146064/simple-
|
||||
# python-webserver-to-save-file
|
||||
if uri_posted == "ccdata.php":
|
||||
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
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)
|
||||
|
||||
# Get the date info
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
screenshot_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "ccdata.txt"
|
||||
|
||||
# Read the length of the screenshot file being uploaded
|
||||
screen_length = self.headers['content-length']
|
||||
screen_data = self.rfile.read(int(screen_length))
|
||||
|
||||
# Write out the file
|
||||
with open(loot_path + screenshot_name, 'w') as cc_data_file:
|
||||
cc_data_file.write(screen_data)
|
||||
|
||||
elif uri_posted == "ssndata.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)
|
||||
|
||||
# Get the date info
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
screenshot_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "ssndata.txt"
|
||||
|
||||
# Read the length of the screenshot file being uploaded
|
||||
screen_length = self.headers['content-length']
|
||||
screen_data = self.rfile.read(int(screen_length))
|
||||
|
||||
# Write out the file
|
||||
with open(loot_path + screenshot_name, 'w') as cc_data_file:
|
||||
cc_data_file.write(screen_data)
|
||||
|
||||
# All other Post requests
|
||||
else:
|
||||
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
|
||||
print "Odd... someone else is trying to access this web server..."
|
||||
print "Might want to check that out..."
|
||||
return
|
||||
|
||||
|
||||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
pass
|
||||
|
||||
|
||||
def cli_parser():
|
||||
# Command line argument parser
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
description="The Egress-Assess is a tool used to assess egress filters\
|
||||
protecting a network")
|
||||
parser.add_argument(
|
||||
'-h', '-?', '--h', '-help', '--help', action="store_true",
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
protocols = parser.add_argument_group('Client Protocol Options')
|
||||
protocols.add_argument(
|
||||
"--ftp", default=False, action='store_true',
|
||||
help="Extract data over FTP.")
|
||||
protocols.add_argument("--http", default=False, action='store_true',
|
||||
help="Extract data over http.")
|
||||
protocols.add_argument("--https", default=False, action='store_true',
|
||||
help="Extract data over https.")
|
||||
protocols.add_argument("--ip", metavar="192.168.1.2", default=None,
|
||||
help="IP to extract data to.")
|
||||
|
||||
servers = parser.add_argument_group('Server Protocol Options')
|
||||
servers.add_argument(
|
||||
"--ftp-server", default=False, action='store_true',
|
||||
help="FTP Server that receives client data.")
|
||||
servers.add_argument("--http-server", default=False, action='store_true',
|
||||
help="HTTP and HTTPS server, receives POST data.")
|
||||
|
||||
ftp_options = parser.add_argument_group('FTP Options')
|
||||
ftp_options.add_argument(
|
||||
"--username", metavar="testuser", default=None,
|
||||
help="Username for FTP server authentication.")
|
||||
ftp_options.add_argument(
|
||||
"--password", metavar="pass123", default=None,
|
||||
help="Password for FTP server authentication.")
|
||||
|
||||
data_content = parser.add_argument_group('Data Content Options')
|
||||
data_content.add_argument(
|
||||
"--data-size", default=1, type=int,
|
||||
help="Number of megs to send")
|
||||
data_content.add_argument(
|
||||
"--ssn", default=False, action='store_true',
|
||||
help="Extract data containing fake social security numbers.")
|
||||
data_content.add_argument(
|
||||
'--cc', default=False, action='store_true',
|
||||
help="Extract data containing fake credit card numbers")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.h:
|
||||
parser.print_help()
|
||||
sys.exit()
|
||||
|
||||
# If using FTP, check to make sure a username and pass is provided
|
||||
if args.ftp and (args.password is None or args.username is None):
|
||||
print "[*] Error: FTP Server requires a username and password!"
|
||||
print "[*] Error: Please re-run and provide the required info!"
|
||||
sys.exit()
|
||||
|
||||
if (args.ftp or args.http or args.https) and args.ip is None:
|
||||
print "[*] Error: You said to act like a client, but provided no ip"
|
||||
print "[*] Error: to connect to. Please re-run with required info!"
|
||||
sys.exit()
|
||||
|
||||
if not (
|
||||
args.ftp or args.http or args.https or args.http_server or
|
||||
args.ftp_server):
|
||||
print "[*] Error: You didn't tell Egress-Assess to act like\
|
||||
a server or client!".replace(' ', '')
|
||||
print "[*] Error: Please re-run and provide an action to perform!"
|
||||
sys.exit()
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def completed_number(prefix, length, the_generator):
|
||||
"""
|
||||
'prefix' is the start of the CC number as a string, any number of digits.
|
||||
'length' is the length of the CC number to generate. Typically 13 or 16
|
||||
"""
|
||||
|
||||
ccnumber = prefix
|
||||
|
||||
# generate digits
|
||||
while len(ccnumber) < (length - 1):
|
||||
digit = str(the_generator.choice(range(0, 10)))
|
||||
ccnumber.append(digit)
|
||||
|
||||
# Calculate sum
|
||||
sum = 0
|
||||
pos = 0
|
||||
|
||||
reversedCCnumber = []
|
||||
reversedCCnumber.extend(ccnumber)
|
||||
reversedCCnumber.reverse()
|
||||
|
||||
while pos < length - 1:
|
||||
odd = int(reversedCCnumber[pos]) * 2
|
||||
if odd > 9:
|
||||
odd -= 9
|
||||
|
||||
sum += odd
|
||||
|
||||
if pos != (length - 2):
|
||||
sum += int(reversedCCnumber[pos + 1])
|
||||
pos += 2
|
||||
|
||||
# Calculate check digit
|
||||
checkdigit = ((sum / 10 + 1) * 10 - sum) % 10
|
||||
ccnumber.append(str(checkdigit))
|
||||
return ''.join(ccnumber)
|
||||
|
||||
|
||||
def credit_card_number(prefixList, length, howMany):
|
||||
|
||||
generator = random.Random()
|
||||
generator.seed()
|
||||
|
||||
result = []
|
||||
|
||||
while len(result) < howMany:
|
||||
ccnumber = copy.copy(generator.choice(prefixList))
|
||||
result.append(completed_number(ccnumber, length, generator))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def ftp_client_connect(command_line_object):
|
||||
# Create FTP objects that connects to the ftp server
|
||||
# with the provided username and password
|
||||
try:
|
||||
ftp = FTP(command_line_object.ip)
|
||||
except socket.gaierror:
|
||||
print "[*] Error: Cannot connect to FTP server. Checking provided ip!"
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
ftp.login(command_line_object.username, command_line_object.password)
|
||||
except error_perm:
|
||||
print "[*] Error: Username or password is incorrect! Please re-run."
|
||||
sys.exit()
|
||||
|
||||
# Create file to upload
|
||||
if command_line_object.ssn:
|
||||
# Get the date info
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
ftp_file_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "ssndata.txt"
|
||||
|
||||
# Generate 150000 SSNs for http(s) transfer
|
||||
# This is about 1.9 megs
|
||||
ssns = ''
|
||||
for single_ssn in range(0, 81500 * command_line_object.data_size):
|
||||
ssns += generate_ssn() + ', '
|
||||
with open(os.getcwd() + "/" + ftp_file_name, 'w') as ssn_temp_file:
|
||||
ssn_temp_file.write(ssns)
|
||||
|
||||
elif command_line_object.cc:
|
||||
# Get the date info
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
ftp_file_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "ccdata.txt"
|
||||
|
||||
all_ccs = ''
|
||||
credit_cards = generate_credit_cards(command_line_object)
|
||||
for card in credit_cards:
|
||||
all_ccs += card + ', '
|
||||
with open(os.getcwd() + "/" + ftp_file_name, 'w') as cc_temp_file:
|
||||
cc_temp_file.write(all_ccs)
|
||||
|
||||
ftp.storlines("STOR " + ftp_file_name, open(ftp_file_name))
|
||||
ftp.quit()
|
||||
os.remove(ftp_file_name)
|
||||
print "[*] File sent!!!"
|
||||
return
|
||||
|
||||
|
||||
def ftp_server(command_line_object):
|
||||
# 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)
|
||||
|
||||
try:
|
||||
authorizer = DummyAuthorizer()
|
||||
authorizer.add_user(
|
||||
command_line_object.username, command_line_object.password,
|
||||
loot_path, perm="lrw")
|
||||
|
||||
handler = FTPHandler
|
||||
handler.authorizer = authorizer
|
||||
|
||||
# Define a customized banner (string returned when client connects)
|
||||
handler.banner = "Connecting to Egress-Assess's FTP server!"
|
||||
|
||||
server = FTPServer(('', 21), handler)
|
||||
server.serve_forever()
|
||||
except ValueError:
|
||||
print "[*] Error: The directory you provided may not exist!"
|
||||
print "[*] Error: Please re-run with a valid FTP directory."
|
||||
sys.exit()
|
||||
|
||||
|
||||
def generate_credit_cards(command_object):
|
||||
# Fake credit card generation code came from:
|
||||
# https://github.com/grahamking/darkcoding-credit-card
|
||||
|
||||
# credit card constants
|
||||
visaPrefixList = [
|
||||
['4', '5', '3', '9'],
|
||||
['4', '5', '5', '6'],
|
||||
['4', '9', '1', '6'],
|
||||
['4', '5', '3', '2'],
|
||||
['4', '9', '2', '9'],
|
||||
['4', '0', '2', '4', '0', '0', '7', '1'],
|
||||
['4', '4', '8', '6'],
|
||||
['4', '7', '1', '6'],
|
||||
['4']]
|
||||
mastercardPrefixList = [
|
||||
['5', '1'], ['5', '2'], ['5', '3'], ['5', '4'], ['5', '5']]
|
||||
amexPrefixList = [['3', '4'], ['3', '7']]
|
||||
|
||||
mastercards = credit_card_number(
|
||||
mastercardPrefixList, 16, 19800 * command_object.data_size)
|
||||
visas = credit_card_number(
|
||||
visaPrefixList, 16, 19800 * command_object.data_size)
|
||||
amexes = credit_card_number(
|
||||
amexPrefixList, 15, 19800 * command_object.data_size)
|
||||
|
||||
all_cards = mastercards + visas + amexes
|
||||
return all_cards
|
||||
|
||||
|
||||
def generate_ssn():
|
||||
ssn = randomNumbers(9)
|
||||
ssn = ssn[0:3] + "-" + ssn[3:5] + "-" + ssn[5:9]
|
||||
return ssn
|
||||
|
||||
|
||||
def http_server():
|
||||
Thread(target=serve_on_port, args=[443]).start()
|
||||
return
|
||||
|
||||
|
||||
def randomNumbers(b):
|
||||
"""
|
||||
Returns a random string/key of "b" characters in length, defaults to 5
|
||||
"""
|
||||
random_number = int(''.join(random.choice(string.digits) for x in range(b))
|
||||
) + 10000
|
||||
|
||||
if random_number < 100000:
|
||||
random_number = random_number + 100000
|
||||
|
||||
return str(random_number)
|
||||
|
||||
|
||||
def serve_on_port(port):
|
||||
if port == 443:
|
||||
cert_path = os.getcwd() + '/server.pem'
|
||||
server = ThreadingHTTPServer(("0.0.0.0", port), GetHandler)
|
||||
server.socket = ssl.wrap_socket(
|
||||
server.socket, certfile=cert_path, server_side=True)
|
||||
server.serve_forever()
|
||||
elif port == 80:
|
||||
server80 = ThreadingHTTPServer(("0.0.0.0", port), GetHandler)
|
||||
server80.serve_forever()
|
||||
return
|
||||
|
||||
|
||||
def title_screen():
|
||||
os.system('clear')
|
||||
print "################################################################################"
|
||||
print "# Egress-Assess #"
|
||||
print "################################################################################\n"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
title_screen()
|
||||
|
||||
cli_parsed = cli_parser()
|
||||
|
||||
if cli_parsed.http or cli_parsed.https:
|
||||
if cli_parsed.ssn:
|
||||
# Generate 150000 SSNs for http(s) transfer
|
||||
# This is about 1.9 megs
|
||||
post_data = ''
|
||||
for single_ssn in range(0, 81500 * cli_parsed.data_size):
|
||||
post_data += generate_ssn() + ', '
|
||||
if cli_parsed.https:
|
||||
post_url = 'https://' + cli_parsed.ip + '/ssndata.php'
|
||||
elif cli_parsed.http:
|
||||
post_url = 'http://' + cli_parsed.ip + '/ssndata.php'
|
||||
|
||||
elif cli_parsed.cc:
|
||||
# Generate about 1.8 megs of different credit cards
|
||||
post_data = ''
|
||||
credit_cards = generate_credit_cards(cli_parsed)
|
||||
for card in credit_cards:
|
||||
post_data += card + ', '
|
||||
# Setup URL that data is sent to, then post it there
|
||||
if cli_parsed.https:
|
||||
post_url = 'https://' + cli_parsed.ip + '/ccdata.php'
|
||||
elif cli_parsed.http:
|
||||
post_url = 'http://' + cli_parsed.ip + '/ccdata.php'
|
||||
|
||||
try:
|
||||
f = urllib2.urlopen(post_url, post_data)
|
||||
f.close()
|
||||
print "[*] File sent!!!"
|
||||
except urllib2.URLError:
|
||||
print "[*] Error: Web server may not be active on " + cli_parsed.ip
|
||||
print "[*] Error: Please check server to make sure it is active!"
|
||||
sys.exit()
|
||||
|
||||
elif cli_parsed.ftp:
|
||||
ftp_client_connect(cli_parsed)
|
||||
|
||||
elif cli_parsed.http_server:
|
||||
try:
|
||||
print "[*] Starting web server..."
|
||||
# bind to all interfaces
|
||||
Thread(target=serve_on_port, args=[443]).start()
|
||||
Thread(target=serve_on_port, args=[80]).start()
|
||||
print "[*] Web server is currently running"
|
||||
print "[*] Type \"killall -9 python\" to stop the web server."
|
||||
# handle keyboard interrupts
|
||||
except KeyboardInterrupt:
|
||||
print "[!] Rage quiting, and stopping the web server!"
|
||||
|
||||
elif cli_parsed.ftp_server:
|
||||
ftp_server(cli_parsed)
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
clear
|
||||
echo "[*] Installing pyftpdlib..."
|
||||
git clone https://github.com/giampaolo/pyftpdlib.git
|
||||
cd pyftpdlib
|
||||
python setup.py install
|
||||
cd ..
|
||||
rm -rf pyftpdlib
|
||||
cd ..
|
||||
clear
|
||||
echo "[*] Generating SSL Certificate"
|
||||
openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
|
||||
echo
|
||||
echo "[*] Install complete!"
|
Loading…
Reference in New Issue