Merged modular branch into master
parent
309eefeb43
commit
6477642b6e
|
@ -1,6 +1,4 @@
|
||||||
|
function Invoke-EgressAssess {
|
||||||
|
|
||||||
function Egress-Assess {
|
|
||||||
<#
|
<#
|
||||||
|
|
||||||
.Synopsis
|
.Synopsis
|
||||||
|
@ -11,58 +9,50 @@ function Egress-Assess {
|
||||||
Due to processing overhead in Powershell, numbers are created in batches of 5,000.
|
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/
|
Reference: http://powershell.org/wp/2013/09/16/powershell-performance-the-operator-and-when-to-avoid-it/
|
||||||
|
|
||||||
.Parameter HTTP
|
.Parameter Client
|
||||||
The switch to enable transfer over http
|
The string containing the protocol to egress data over
|
||||||
|
|
||||||
.Parameter HTTPS
|
|
||||||
The switch to enable transfer over https
|
|
||||||
|
|
||||||
.Parameter FTP
|
|
||||||
The switch to enable transer over ftp
|
|
||||||
|
|
||||||
.Parameter IP
|
.Parameter IP
|
||||||
The string containing the IP or hostname of the egress assess server.
|
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
|
.Parameter Username
|
||||||
The username for the ftp server
|
The username for the ftp server
|
||||||
|
|
||||||
.Parameter Password
|
.Parameter Password
|
||||||
The password for the ftp server
|
The password for the ftp server
|
||||||
|
|
||||||
.Parameter CC
|
.Parameter Datatype
|
||||||
Enable this switch if you want to send credit card data
|
The string containing the data you want to generate and exfil
|
||||||
|
|
||||||
.Parameter SSN
|
|
||||||
Enable this switch if you want to send social securit numbers
|
|
||||||
|
|
||||||
.Parameter Size
|
.Parameter Size
|
||||||
How many blocks of 5000 numbers to generate
|
How many blocks of 5000 numbers to generate
|
||||||
|
|
||||||
.Example
|
.Example
|
||||||
Import-Module Egress-Assess.ps1
|
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
|
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/
|
https://www.christophertruncer.com/
|
||||||
http://blog.harmj0y.net/
|
http://blog.harmj0y.net/
|
||||||
|
http://sixdub.net/
|
||||||
|
|
||||||
|
|
||||||
#>
|
#>
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
Param (
|
Param (
|
||||||
[switch]$HTTP,
|
[Parameter(Mandatory=$True)]
|
||||||
[switch]$HTTPS,
|
[string]$CLIENT,
|
||||||
[switch]$FTP,
|
|
||||||
[Parameter(Mandatory=$True)]
|
[Parameter(Mandatory=$True)]
|
||||||
[string]$IP,
|
[string]$IP,
|
||||||
|
[switch]$Proxy,
|
||||||
|
[Parameter(Mandatory=$True)]
|
||||||
|
[string]$Datatype,
|
||||||
[string]$Username,
|
[string]$Username,
|
||||||
[string]$Password,
|
[string]$Password,
|
||||||
[switch]$CC,
|
|
||||||
[switch]$SSN,
|
|
||||||
[int]$Size=1
|
[int]$Size=1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -133,26 +123,26 @@ begin {
|
||||||
|
|
||||||
|
|
||||||
# check for cc or ssn and pass to body
|
# check for cc or ssn and pass to body
|
||||||
if ($CC) {
|
if ($DATATYPE -eq "cc") {
|
||||||
Generate-CreditCards
|
Generate-CreditCards
|
||||||
$Body = @()
|
$Body = @()
|
||||||
$Body = $allCC
|
$Body = $allCC
|
||||||
if ($http){
|
if ($client -eq "http"){
|
||||||
$url = "http://" + $IP + "/ccdata.php"
|
$url = "http://" + $IP + "/post_data.php"
|
||||||
}
|
}
|
||||||
elseif ($https){
|
elseif ($client -eq "https") {
|
||||||
$url = "https://" + $IP + "/ccdata.php"
|
$url = "https://" + $IP + "/post_data.php"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ($SSN){
|
elseif ($DATATYPE -eq "ssn"){
|
||||||
Generate-SSN
|
Generate-SSN
|
||||||
$Body = @()
|
$Body = @()
|
||||||
$Body = $allSSN
|
$Body = $allSSN
|
||||||
if ($http){
|
if ($client -eq "http"){
|
||||||
$url = "http://" + $IP + "/ssndata.php"
|
$url = "http://" + $IP + "/post_data.php"
|
||||||
}
|
}
|
||||||
elseif ($https){
|
elseif ($client -eq "https"){
|
||||||
$url = "https://" + $IP + "/ssndata.php"
|
$url = "https://" + $IP + "/post_data.php"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -163,6 +153,11 @@ begin {
|
||||||
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
|
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
|
||||||
$uri = New-Object -TypeName System.Uri -ArgumentList $url
|
$uri = New-Object -TypeName System.Uri -ArgumentList $url
|
||||||
$wc = New-Object -TypeName System.Net.WebClient
|
$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.."
|
Write-Verbose "Uploading data.."
|
||||||
$wc.UploadString($uri, $Body)
|
$wc.UploadString($uri, $Body)
|
||||||
Write-Verbose "Transaction Complete."
|
Write-Verbose "Transaction Complete."
|
||||||
|
@ -170,32 +165,40 @@ begin {
|
||||||
|
|
||||||
function Use-Ftp {
|
function Use-Ftp {
|
||||||
|
|
||||||
if ($CC) {
|
$Date = Get-Date -Format Mdyyyy_hhmmss
|
||||||
|
$Path = "ftpdata" + $Date + ".txt"
|
||||||
|
|
||||||
|
if ($DATATYPE -eq "cc") {
|
||||||
Generate-CreditCards
|
Generate-CreditCards
|
||||||
out-file -filepath ftpdata.txt -inputobject $allCC -encoding ASCII
|
$FTPData = $allCC
|
||||||
}
|
}
|
||||||
elseif ($SSN){
|
elseif ($DATATYPE -eq "ssn"){
|
||||||
Generate-SSN
|
Generate-SSN
|
||||||
out-file -filepath ftpdata.txt -inputobject $allSSN -encoding ASCII
|
$FTPData=$allSSN
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Write-Verbose "You did not provide a data type to generate."
|
Write-Verbose "You did not provide a data type to generate."
|
||||||
}
|
}
|
||||||
$Path = "ftpdata.txt"
|
$Destination = "ftp://" + $IP + "/" + $Path
|
||||||
$Destination = "ftp://" + $IP + "/ftpdata.txt"
|
|
||||||
$Credential = New-Object -TypeName System.Net.NetworkCredential -ArgumentList $Username,$Password
|
$Credential = New-Object -TypeName System.Net.NetworkCredential -ArgumentList $Username,$Password
|
||||||
|
|
||||||
# Create the FTP request and upload the file
|
# Create the FTP request and upload the file
|
||||||
$FtpRequest = [System.Net.FtpWebRequest][System.Net.WebRequest]::Create($Destination)
|
$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.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
|
||||||
$FtpRequest.Credentials = $Credential
|
$FtpRequest.Credentials = $Credential
|
||||||
|
|
||||||
# Get the request stream, and write the file bytes to the stream
|
# Get the request stream, and write the file bytes to the stream
|
||||||
|
$Encoder = [system.Text.Encoding]::UTF8
|
||||||
$RequestStream = $FtpRequest.GetRequestStream()
|
$RequestStream = $FtpRequest.GetRequestStream()
|
||||||
Get-Content -Path $Path -Encoding Byte | % { $RequestStream.WriteByte($_); }
|
$Encoder.GetBytes($FTPData) | % { $RequestStream.WriteByte($_); }
|
||||||
$RequestStream.Close()
|
$RequestStream.Close()
|
||||||
Remove-Item $Path
|
|
||||||
|
|
||||||
Write-Verbose "File Transfer Complete."
|
Write-Verbose "File Transfer Complete."
|
||||||
}
|
}
|
||||||
|
@ -203,11 +206,11 @@ begin {
|
||||||
}
|
}
|
||||||
process {
|
process {
|
||||||
|
|
||||||
if ($http -or $https) {
|
if ($client -eq "http" -or $client -eq "https") {
|
||||||
Use-HTTP
|
Use-HTTP
|
||||||
}
|
}
|
||||||
|
|
||||||
elseif ($ftp) {
|
elseif ($client -eq "ftp") {
|
||||||
Use-Ftp
|
Use-Ftp
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
501
Egress-Assess.py
501
Egress-Assess.py
|
@ -6,461 +6,70 @@
|
||||||
# capabilities.
|
# capabilities.
|
||||||
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import copy
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import socket
|
|
||||||
import ssl
|
|
||||||
import string
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
from common import helpers
|
||||||
import urllib2
|
from common import orchestra
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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:
|
the_conductor = orchestra.Conductor()
|
||||||
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:
|
# Check if only listing supported server/client protocols or datatypes
|
||||||
# Generate about 1.8 megs of different credit cards
|
if cli_parsed.list_servers:
|
||||||
post_data = ''
|
print "[*] Supported server protocols: \n"
|
||||||
credit_cards = generate_credit_cards(cli_parsed)
|
the_conductor.load_server_protocols(cli_parsed)
|
||||||
for card in credit_cards:
|
for name, server_module in the_conductor.server_protocols.iteritems():
|
||||||
post_data += card + ', '
|
print "[+] " + server_module.protocol
|
||||||
# Setup URL that data is sent to, then post it there
|
print
|
||||||
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()
|
sys.exit()
|
||||||
|
|
||||||
elif cli_parsed.ftp:
|
elif cli_parsed.list_clients:
|
||||||
ftp_client_connect(cli_parsed)
|
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:
|
elif cli_parsed.list_datatypes:
|
||||||
try:
|
print "[*] Supported data types: \n"
|
||||||
print "[*] Starting web server..."
|
the_conductor.load_datatypes(cli_parsed)
|
||||||
# bind to all interfaces
|
for name, datatype_module in the_conductor.datatypes.iteritems():
|
||||||
Thread(target=serve_on_port, args=[443]).start()
|
print "[+] " + datatype_module.cli + " - (" +\
|
||||||
Thread(target=serve_on_port, args=[80]).start()
|
datatype_module.description + ")"
|
||||||
print "[*] Web server is currently running"
|
print
|
||||||
print "[*] Type \"killall -9 python\" to stop the web server."
|
sys.exit()
|
||||||
# handle keyboard interrupts
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print "[!] Rage quiting, and stopping the web server!"
|
|
||||||
|
|
||||||
elif cli_parsed.ftp_server:
|
if cli_parsed.server is not None:
|
||||||
ftp_server(cli_parsed)
|
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.
|
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...
|
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....
|
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...
|
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
|
./Egress-Assess.py --client https --data-size 15 --ip 192.168.63.149 --datatype cc
|
||||||
|
|
||||||
|
|
||||||
Upcoming Changes
|
|
||||||
================
|
|
||||||
|
|
||||||
1. Make Egress-Assess modular so users can easily extend the tool to support additional frameworks and data types.
|
|
||||||
|
|
|
@ -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
|
#!/bin/bash
|
||||||
|
|
||||||
clear
|
clear
|
||||||
|
echo "[*] Installing Egress-Assess Dependencies..."
|
||||||
echo "[*] Installing pyftpdlib..."
|
echo "[*] Installing pyftpdlib..."
|
||||||
git clone https://github.com/giampaolo/pyftpdlib.git
|
git clone https://github.com/giampaolo/pyftpdlib.git
|
||||||
cd pyftpdlib
|
cd pyftpdlib
|
||||||
python setup.py install
|
python setup.py install
|
||||||
cd ..
|
cd ..
|
||||||
rm -rf pyftpdlib
|
rm -rf pyftpdlib
|
||||||
cd ..
|
cd ../protocols/servers/serverlibs
|
||||||
clear
|
clear
|
||||||
echo "[*] Generating SSL Certificate"
|
echo "[*] Generating SSL Certificate"
|
||||||
openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
|
openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
|
||||||
echo
|
echo
|
||||||
|
echo
|
||||||
echo "[*] Install complete!"
|
echo "[*] Install complete!"
|
||||||
|
echo "[*] Enjoy Egress-Assess!"
|
||||||
|
|
Loading…
Reference in New Issue