Merged modular branch into master
parent
309eefeb43
commit
6477642b6e
|
@ -1,6 +1,4 @@
|
|||
|
||||
|
||||
function Egress-Assess {
|
||||
function Invoke-EgressAssess {
|
||||
<#
|
||||
|
||||
.Synopsis
|
||||
|
@ -11,58 +9,50 @@ function Egress-Assess {
|
|||
Due to processing overhead in Powershell, numbers are created in batches of 5,000.
|
||||
Reference: http://powershell.org/wp/2013/09/16/powershell-performance-the-operator-and-when-to-avoid-it/
|
||||
|
||||
.Parameter HTTP
|
||||
The switch to enable transfer over http
|
||||
|
||||
.Parameter HTTPS
|
||||
The switch to enable transfer over https
|
||||
|
||||
.Parameter FTP
|
||||
The switch to enable transer over ftp
|
||||
.Parameter Client
|
||||
The string containing the protocol to egress data over
|
||||
|
||||
.Parameter IP
|
||||
The string containing the IP or hostname of the egress assess server.
|
||||
|
||||
.Parameter Proxy
|
||||
This switch is used when you need to exfiltrate data using the system proxy.
|
||||
|
||||
.Parameter Username
|
||||
The username for the ftp server
|
||||
|
||||
.Parameter Password
|
||||
The password for the ftp server
|
||||
|
||||
.Parameter CC
|
||||
Enable this switch if you want to send credit card data
|
||||
|
||||
.Parameter SSN
|
||||
Enable this switch if you want to send social securit numbers
|
||||
.Parameter Datatype
|
||||
The string containing the data you want to generate and exfil
|
||||
|
||||
.Parameter Size
|
||||
How many blocks of 5000 numbers to generate
|
||||
|
||||
.Example
|
||||
Import-Module Egress-Assess.ps1
|
||||
Egress-Assess -http -ip 127.0.0.1 -CC -Size 1 -Verbose
|
||||
Invoke-EgressAssess -client http -ip 127.0.0.1 -datatype cc -Size 1 -Verbose
|
||||
|
||||
Script created by @rvrsh3ll
|
||||
Script created by @rvrsh3ll @christruncer @harmj0y @sixdub
|
||||
https://www.rvrsh3ll.net
|
||||
http://www.rvrsh3ll.net/blog/
|
||||
|
||||
|
||||
Thanks to @christruncer for the project and @harmjoy for the powershell help!
|
||||
https://www.christophertruncer.com/
|
||||
http://blog.harmj0y.net/
|
||||
http://sixdub.net/
|
||||
|
||||
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[switch]$HTTP,
|
||||
[switch]$HTTPS,
|
||||
[switch]$FTP,
|
||||
[Parameter(Mandatory=$True)]
|
||||
[string]$CLIENT,
|
||||
[Parameter(Mandatory=$True)]
|
||||
[string]$IP,
|
||||
[switch]$Proxy,
|
||||
[Parameter(Mandatory=$True)]
|
||||
[string]$Datatype,
|
||||
[string]$Username,
|
||||
[string]$Password,
|
||||
[switch]$CC,
|
||||
[switch]$SSN,
|
||||
[int]$Size=1
|
||||
)
|
||||
|
||||
|
@ -133,26 +123,26 @@ begin {
|
|||
|
||||
|
||||
# check for cc or ssn and pass to body
|
||||
if ($CC) {
|
||||
if ($DATATYPE -eq "cc") {
|
||||
Generate-CreditCards
|
||||
$Body = @()
|
||||
$Body = $allCC
|
||||
if ($http){
|
||||
$url = "http://" + $IP + "/ccdata.php"
|
||||
if ($client -eq "http"){
|
||||
$url = "http://" + $IP + "/post_data.php"
|
||||
}
|
||||
elseif ($https){
|
||||
$url = "https://" + $IP + "/ccdata.php"
|
||||
elseif ($client -eq "https") {
|
||||
$url = "https://" + $IP + "/post_data.php"
|
||||
}
|
||||
}
|
||||
elseif ($SSN){
|
||||
elseif ($DATATYPE -eq "ssn"){
|
||||
Generate-SSN
|
||||
$Body = @()
|
||||
$Body = $allSSN
|
||||
if ($http){
|
||||
$url = "http://" + $IP + "/ssndata.php"
|
||||
if ($client -eq "http"){
|
||||
$url = "http://" + $IP + "/post_data.php"
|
||||
}
|
||||
elseif ($https){
|
||||
$url = "https://" + $IP + "/ssndata.php"
|
||||
elseif ($client -eq "https"){
|
||||
$url = "https://" + $IP + "/post_data.php"
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -163,6 +153,11 @@ begin {
|
|||
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
|
||||
$uri = New-Object -TypeName System.Uri -ArgumentList $url
|
||||
$wc = New-Object -TypeName System.Net.WebClient
|
||||
if ($proxy) {
|
||||
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
|
||||
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
|
||||
$wc.proxy = $proxy
|
||||
}
|
||||
Write-Verbose "Uploading data.."
|
||||
$wc.UploadString($uri, $Body)
|
||||
Write-Verbose "Transaction Complete."
|
||||
|
@ -170,32 +165,40 @@ begin {
|
|||
|
||||
function Use-Ftp {
|
||||
|
||||
if ($CC) {
|
||||
$Date = Get-Date -Format Mdyyyy_hhmmss
|
||||
$Path = "ftpdata" + $Date + ".txt"
|
||||
|
||||
if ($DATATYPE -eq "cc") {
|
||||
Generate-CreditCards
|
||||
out-file -filepath ftpdata.txt -inputobject $allCC -encoding ASCII
|
||||
$FTPData = $allCC
|
||||
}
|
||||
elseif ($SSN){
|
||||
elseif ($DATATYPE -eq "ssn"){
|
||||
Generate-SSN
|
||||
out-file -filepath ftpdata.txt -inputobject $allSSN -encoding ASCII
|
||||
$FTPData=$allSSN
|
||||
|
||||
}
|
||||
else {
|
||||
Write-Verbose "You did not provide a data type to generate."
|
||||
}
|
||||
$Path = "ftpdata.txt"
|
||||
$Destination = "ftp://" + $IP + "/ftpdata.txt"
|
||||
$Destination = "ftp://" + $IP + "/" + $Path
|
||||
$Credential = New-Object -TypeName System.Net.NetworkCredential -ArgumentList $Username,$Password
|
||||
|
||||
# Create the FTP request and upload the file
|
||||
$FtpRequest = [System.Net.FtpWebRequest][System.Net.WebRequest]::Create($Destination)
|
||||
if ($proxy) {
|
||||
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
|
||||
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
|
||||
$FtpRequest.proxy = $proxy
|
||||
}
|
||||
$FtpRequest.KeepAlive = $False
|
||||
$FtpRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
|
||||
$FtpRequest.Credentials = $Credential
|
||||
|
||||
# Get the request stream, and write the file bytes to the stream
|
||||
$Encoder = [system.Text.Encoding]::UTF8
|
||||
$RequestStream = $FtpRequest.GetRequestStream()
|
||||
Get-Content -Path $Path -Encoding Byte | % { $RequestStream.WriteByte($_); }
|
||||
$Encoder.GetBytes($FTPData) | % { $RequestStream.WriteByte($_); }
|
||||
$RequestStream.Close()
|
||||
Remove-Item $Path
|
||||
|
||||
Write-Verbose "File Transfer Complete."
|
||||
}
|
||||
|
@ -203,11 +206,11 @@ begin {
|
|||
}
|
||||
process {
|
||||
|
||||
if ($http -or $https) {
|
||||
if ($client -eq "http" -or $client -eq "https") {
|
||||
Use-HTTP
|
||||
}
|
||||
|
||||
elseif ($ftp) {
|
||||
elseif ($client -eq "ftp") {
|
||||
Use-Ftp
|
||||
}
|
||||
else {
|
||||
|
|
501
Egress-Assess.py
501
Egress-Assess.py
|
@ -6,461 +6,70 @@
|
|||
# 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 or args.ftp_server) 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 (args.ftp or args.http or args.https) and (args.cc is False and args.ssn is False):
|
||||
print "[*] Error: You need to tell Egress-Assess the type of data to send!"
|
||||
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!\n\n"
|
||||
parser.print_help()
|
||||
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"
|
||||
from common import helpers
|
||||
from common import orchestra
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
title_screen()
|
||||
helpers.title_screen()
|
||||
|
||||
cli_parsed = cli_parser()
|
||||
cli_parsed = helpers.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'
|
||||
the_conductor = orchestra.Conductor()
|
||||
|
||||
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!"
|
||||
# Check if only listing supported server/client protocols or datatypes
|
||||
if cli_parsed.list_servers:
|
||||
print "[*] Supported server protocols: \n"
|
||||
the_conductor.load_server_protocols(cli_parsed)
|
||||
for name, server_module in the_conductor.server_protocols.iteritems():
|
||||
print "[+] " + server_module.protocol
|
||||
print
|
||||
sys.exit()
|
||||
|
||||
elif cli_parsed.ftp:
|
||||
ftp_client_connect(cli_parsed)
|
||||
elif cli_parsed.list_clients:
|
||||
print "[*] Supported client protocols: \n"
|
||||
the_conductor.load_client_protocols(cli_parsed)
|
||||
for name, client_module in the_conductor.client_protocols.iteritems():
|
||||
print "[+] " + client_module.protocol
|
||||
print
|
||||
sys.exit()
|
||||
|
||||
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.list_datatypes:
|
||||
print "[*] Supported data types: \n"
|
||||
the_conductor.load_datatypes(cli_parsed)
|
||||
for name, datatype_module in the_conductor.datatypes.iteritems():
|
||||
print "[+] " + datatype_module.cli + " - (" +\
|
||||
datatype_module.description + ")"
|
||||
print
|
||||
sys.exit()
|
||||
|
||||
elif cli_parsed.ftp_server:
|
||||
ftp_server(cli_parsed)
|
||||
if cli_parsed.server is not None:
|
||||
the_conductor.load_server_protocols(cli_parsed)
|
||||
|
||||
for full_path, server in the_conductor.server_protocols.iteritems():
|
||||
|
||||
if server.protocol == cli_parsed.server.lower():
|
||||
server.serve()
|
||||
|
||||
elif cli_parsed.client is not None:
|
||||
# load up all supported client protocols and datatypes
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
||||
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."
|
||||
sys.exit()
|
||||
|
|
17
README.md
17
README.md
|
@ -24,25 +24,18 @@ Blog posts are available here:
|
|||
|
||||
Typical use case for Egress-Assess is to copy this tool in two locations. One location will act as the server, the other will act as the client. Egress-Assess can send data over FTP, HTTP, and HTTPS.
|
||||
|
||||
To extract data over FTP, you would first start Egress-Assess’s FTP server by selecting “–ftp-server” and providing a username and password to use:
|
||||
To extract data over FTP, you would first start Egress-Assess’s FTP server by selecting “--server ftp” and providing a username and password to use:
|
||||
|
||||
./Egress-Assess.py –ftp-server –username testuser –password pass123
|
||||
./Egress-Assess.py --server ftp --username testuser --password pass123
|
||||
|
||||
Now, to have the client connect and send data to the ftp server, you could run...
|
||||
|
||||
./Egress-Assess.py --ftp --username testuser --password pass123 --ip 192.168.63.149 --ssn
|
||||
|
||||
./Egress-Assess.py --client ftp --username testuser --password pass123 --ip 192.168.63.149 --datatype ssn
|
||||
|
||||
Also, you can setup Egress-Assess to act as a web server by running....
|
||||
|
||||
./Egress-Assess.py --http-server
|
||||
./Egress-Assess.py --server https
|
||||
|
||||
Then, to send data to the FTP server, and to specifically send 15 megs of credit card data, run the following command...
|
||||
|
||||
./Egress-Assess.py –http –data-size 15 –ip 192.168.63.149 –cc
|
||||
|
||||
|
||||
Upcoming Changes
|
||||
================
|
||||
|
||||
1. Make Egress-Assess modular so users can easily extend the tool to support additional frameworks and data types.
|
||||
./Egress-Assess.py --client https --data-size 15 --ip 192.168.63.149 --datatype cc
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
'''
|
||||
|
||||
This is for functions potentially used by all modules
|
||||
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
|
||||
|
||||
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(
|
||||
"--client", default=None, metavar="[http]",
|
||||
help="Extract data over the specified protocol.")
|
||||
protocols.add_argument(
|
||||
"--list-clients", default=False, action='store_true',
|
||||
help="List all supported client protocols.")
|
||||
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(
|
||||
"--server", default=None, metavar='[http]',
|
||||
help="Create a server for the specified protocol.")
|
||||
servers.add_argument("--list-servers", default=False, action='store_true',
|
||||
help="Lists all supported server protocols.")
|
||||
|
||||
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(
|
||||
"--datatype", default=None, metavar='[ssn]',
|
||||
help="Extract data containing fake social security numbers.")
|
||||
data_content.add_argument(
|
||||
"--data-size", default=1, type=int,
|
||||
help="Number of megs to send")
|
||||
data_content.add_argument(
|
||||
"--list-datatypes", default=False, action='store_true',
|
||||
help="List all data types that can be generated by the framework.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.h:
|
||||
parser.print_help()
|
||||
sys.exit()
|
||||
|
||||
if (args.server == "ftp" or args.client == "ftp") and (
|
||||
args.username is None or args.password is None):
|
||||
print "[*] Error: FTP connections require a username and password!"
|
||||
print "[*] Error: Please re-run and provide the required info!"
|
||||
sys.exit()
|
||||
|
||||
if args.client 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 (args.client is not None) and (args.datatype is None):
|
||||
print "[*] Error: You need to tell Egress-Assess the type of data to send!"
|
||||
print "[*] Error: to connect to. Please re-run with required info!"
|
||||
sys.exit()
|
||||
|
||||
if (args.client is None and args.server is None and
|
||||
args.list_servers is None and args.list_clients is None and
|
||||
args.list_datatypes is None):
|
||||
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!"
|
||||
parser.print_help()
|
||||
sys.exit()
|
||||
|
||||
return args
|
||||
|
||||
|
||||
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 title_screen():
|
||||
os.system('clear')
|
||||
print "################################################################################"
|
||||
print "# Egress-Assess #"
|
||||
print "################################################################################\n"
|
||||
return
|
||||
|
||||
|
||||
def ea_path():
|
||||
return os.getcwd()
|
|
@ -0,0 +1,55 @@
|
|||
'''
|
||||
|
||||
This is the conductor which controls everything
|
||||
|
||||
'''
|
||||
|
||||
import glob
|
||||
import imp
|
||||
from protocols.servers import *
|
||||
from protocols.clients import *
|
||||
from datatypes import *
|
||||
|
||||
|
||||
class Conductor:
|
||||
|
||||
def __init__(self):
|
||||
# Create dictionaries of supported modules
|
||||
# empty until stuff loaded into them
|
||||
self.client_protocols = {}
|
||||
self.server_protocols = {}
|
||||
self.datatypes = {}
|
||||
|
||||
def load_client_protocols(self, command_line_object):
|
||||
for name in glob.glob('protocols/clients/*.py'):
|
||||
if name.endswith("__init__.py"):
|
||||
pass
|
||||
elif name.endswith(".pyc"):
|
||||
pass
|
||||
else:
|
||||
loaded_client_proto = imp.load_source(name.replace("/", ".").rstrip('.py'), name)
|
||||
self.client_protocols[name] = loaded_client_proto.Client(command_line_object)
|
||||
return
|
||||
|
||||
|
||||
def load_server_protocols(self, command_line_object):
|
||||
for name in glob.glob('protocols/servers/*.py'):
|
||||
if name.endswith("__init__.py"):
|
||||
pass
|
||||
elif name.endswith(".pyc"):
|
||||
pass
|
||||
else:
|
||||
loaded_server_proto = imp.load_source(name.replace("/", ".").rstrip('.py'), name)
|
||||
self.server_protocols[name] = loaded_server_proto.Server(command_line_object)
|
||||
return
|
||||
|
||||
def load_datatypes(self, command_line_object):
|
||||
for name in glob.glob('datatypes/*.py'):
|
||||
if name.endswith("__init__.py"):
|
||||
pass
|
||||
elif name.endswith(".pyc"):
|
||||
pass
|
||||
else:
|
||||
loaded_datatypes = imp.load_source(name.replace("/", ".").rstrip('.py'), name)
|
||||
self.datatypes[name] = loaded_datatypes.Datatype(command_line_object)
|
||||
return
|
|
@ -0,0 +1,98 @@
|
|||
'''
|
||||
|
||||
This module generates credit card data
|
||||
|
||||
'''
|
||||
|
||||
import copy
|
||||
import random
|
||||
|
||||
|
||||
class Datatype:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.cli = "cc"
|
||||
self.description = "Credit Card Numbers"
|
||||
self.filetype = "text"
|
||||
self.datasize = int(cli_object.data_size)
|
||||
|
||||
def completed_number(self, 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(self, prefixList, length, howMany):
|
||||
|
||||
generator = random.Random()
|
||||
generator.seed()
|
||||
|
||||
result = []
|
||||
|
||||
while len(result) < howMany:
|
||||
ccnumber = copy.copy(generator.choice(prefixList))
|
||||
result.append(self.completed_number(ccnumber, length, generator))
|
||||
|
||||
return result
|
||||
|
||||
def generate_data(self):
|
||||
# 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 = self.credit_card_number(
|
||||
mastercardPrefixList, 16, 19800 * self.datasize)
|
||||
visas = self.credit_card_number(
|
||||
visaPrefixList, 16, 19800 * self.datasize)
|
||||
amexes = self.credit_card_number(
|
||||
amexPrefixList, 15, 19800 * self.datasize)
|
||||
|
||||
all_cards = mastercards + visas + amexes
|
||||
final_cards = ''
|
||||
|
||||
for card in all_cards:
|
||||
final_cards += card + ', '
|
||||
|
||||
return final_cards
|
|
@ -0,0 +1,28 @@
|
|||
'''
|
||||
|
||||
This module generates social security numbers
|
||||
|
||||
'''
|
||||
|
||||
from common import helpers
|
||||
|
||||
|
||||
class Datatype:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.cli = "ssn"
|
||||
self.description = "Social Security Numbers"
|
||||
self.filetype = "text"
|
||||
self.datasize = int(cli_object.data_size)
|
||||
|
||||
def create_ssn(self):
|
||||
ssn = helpers.randomNumbers(9)
|
||||
ssn = ssn[0:3] + "-" + ssn[3:5] + "-" + ssn[5:9]
|
||||
return ssn
|
||||
|
||||
def generate_data(self):
|
||||
ssns = ''
|
||||
# This is approx 1 meg of socials
|
||||
for single_ssn in range(0, 81500 * self.datasize):
|
||||
ssns += self.create_ssn() + ', '
|
||||
return ssns
|
|
@ -0,0 +1,50 @@
|
|||
'''
|
||||
|
||||
This is the ftp client code
|
||||
|
||||
'''
|
||||
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
from common import helpers
|
||||
from ftplib import FTP
|
||||
from ftplib import error_perm
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "ftp"
|
||||
self.remote_server = cli_object.ip
|
||||
self.username = cli_object.username
|
||||
self.password = cli_object.password
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
|
||||
try:
|
||||
ftp = FTP(self.remote_server)
|
||||
except socket.gaierror:
|
||||
print "[*] Error: Cannot connect to FTP server. Checking provided ip!"
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
ftp.login(self.username, self.password)
|
||||
except error_perm:
|
||||
print "[*] Error: Username or password is incorrect! Please re-run."
|
||||
sys.exit()
|
||||
|
||||
# Create file name and write out file for ftp transfer
|
||||
current_date = time.strftime("%m/%d/%Y")
|
||||
current_time = time.strftime("%H:%M:%S")
|
||||
ftp_file_name = current_date.replace("/", "") +\
|
||||
"_" + current_time.replace(":", "") + "ftp_data.txt"
|
||||
|
||||
with open(helpers.ea_path() + "/" + ftp_file_name, 'w') as cc_temp_file:
|
||||
cc_temp_file.write(data_to_transmit)
|
||||
|
||||
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!!!"
|
|
@ -0,0 +1,32 @@
|
|||
'''
|
||||
|
||||
This is the web client code
|
||||
|
||||
'''
|
||||
|
||||
import sys
|
||||
import urllib2
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
# Really http and https
|
||||
self.data_to_transmit = ''
|
||||
self.remote_server = cli_object.ip
|
||||
self.protocol = "http"
|
||||
|
||||
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()
|
||||
return
|
|
@ -0,0 +1,32 @@
|
|||
'''
|
||||
|
||||
This is the web client code
|
||||
|
||||
'''
|
||||
|
||||
import sys
|
||||
import urllib2
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
# Really http and https
|
||||
self.data_to_transmit = ''
|
||||
self.remote_server = cli_object.ip
|
||||
self.protocol = "https"
|
||||
|
||||
def transmit(self, data_to_transmit):
|
||||
# Create the url to post to
|
||||
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()
|
||||
return
|
|
@ -0,0 +1,49 @@
|
|||
'''
|
||||
|
||||
This is the code for the ftp server
|
||||
|
||||
'''
|
||||
|
||||
import os
|
||||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import FTPServer
|
||||
|
||||
|
||||
class Server:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "ftp"
|
||||
self.username = cli_object.username
|
||||
self.password = cli_object.password
|
||||
self.data_directory = ""
|
||||
|
||||
def serve(self):
|
||||
# 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(
|
||||
self.username, self.password,
|
||||
loot_path, perm="elradfmwM")
|
||||
|
||||
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()
|
||||
return
|
|
@ -0,0 +1,32 @@
|
|||
'''
|
||||
|
||||
This is the code for the web server
|
||||
|
||||
'''
|
||||
|
||||
from protocols.servers.serverlibs import base_handler
|
||||
from protocols.servers.serverlibs import threaded_http
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class Server:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "http"
|
||||
|
||||
def serve(self):
|
||||
try:
|
||||
print "[*] Starting web (http) 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."
|
||||
# handle keyboard interrupts
|
||||
except KeyboardInterrupt:
|
||||
print "[!] Rage quiting, and stopping the web server!"
|
||||
|
||||
def serve_on_port(self):
|
||||
server80 = threaded_http.ThreadingHTTPServer(
|
||||
("0.0.0.0", 80), base_handler.GetHandler)
|
||||
server80.serve_forever()
|
||||
return
|
|
@ -0,0 +1,38 @@
|
|||
'''
|
||||
|
||||
This is the code for the web server
|
||||
|
||||
'''
|
||||
|
||||
import ssl
|
||||
from common import helpers
|
||||
from protocols.servers.serverlibs import base_handler
|
||||
from protocols.servers.serverlibs import threaded_http
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class Server:
|
||||
|
||||
def __init__(self, cli_object):
|
||||
self.protocol = "https"
|
||||
|
||||
def serve(self):
|
||||
try:
|
||||
print "[*] Starting web (https) 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."
|
||||
# handle keyboard interrupts
|
||||
except KeyboardInterrupt:
|
||||
print "[!] Rage quiting, and stopping the web server!"
|
||||
|
||||
def serve_on_port(self):
|
||||
cert_path = helpers.ea_path() +\
|
||||
'/protocols/servers/serverlibs/server.pem'
|
||||
server = threaded_http.ThreadingHTTPServer(
|
||||
("0.0.0.0", 443), base_handler.GetHandler)
|
||||
server.socket = ssl.wrap_socket(
|
||||
server.socket, certfile=cert_path, server_side=True)
|
||||
server.serve_forever()
|
||||
return
|
|
@ -0,0 +1,67 @@
|
|||
import os
|
||||
import time
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler
|
||||
from common import helpers
|
||||
|
||||
|
||||
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(helpers.ea_path(), "data")
|
||||
loot_path = exfil_directory + "/"
|
||||
|
||||
# Info for this from -
|
||||
# http://stackoverflow.com/questions/13146064/simple-
|
||||
# python-webserver-to-save-file
|
||||
if uri_posted == "post_data.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(":", "") + "web_data.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
|
|
@ -0,0 +1,6 @@
|
|||
from BaseHTTPServer import HTTPServer
|
||||
from SocketServer import ThreadingMixIn
|
||||
|
||||
|
||||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
pass
|
|
@ -1,15 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
clear
|
||||
echo "[*] Installing Egress-Assess Dependencies..."
|
||||
echo "[*] Installing pyftpdlib..."
|
||||
git clone https://github.com/giampaolo/pyftpdlib.git
|
||||
cd pyftpdlib
|
||||
python setup.py install
|
||||
cd ..
|
||||
rm -rf pyftpdlib
|
||||
cd ..
|
||||
cd ../protocols/servers/serverlibs
|
||||
clear
|
||||
echo "[*] Generating SSL Certificate"
|
||||
openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
|
||||
echo
|
||||
echo
|
||||
echo "[*] Install complete!"
|
||||
echo "[*] Enjoy Egress-Assess!"
|
||||
|
|
Loading…
Reference in New Issue