Skip to content

WP Booking System <= 1.5.1 - CSRF to Authenticated SQL Injection

Summary

Description Details
Name WP Booking System <= 1.5.1 - CSRF to Authenticated SQL Injection
Summary Multiple SQL injections which can be exploited over CSRF
Affected application WP Booking System
Affected revision <= 1.5.1
Vendor update available Yes
CVE CVE-2019-12239
Ids CWE-89;
CVSSv3.0 Base Score 7.7
CVSS vector AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N
Public Exploit available No
Exploit verified
Authentication Required Yes

Vulnerable Code

<?php

wp-booking-system.php:

  103 add_action('wp_ajax_bookingModalData' , 'bookingModalData_callback');

include/bookingAjax.php:

  2 function bookingModalData_callback() {
  3     global $wpdb;
  4     $sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_calendars WHERE 
    calendarID = ' . $_POST['calendarID']; 
  5     $calendar = $wpdb->get_row( $sql, ARRAY_A );




include/pluginStructure.php:

   6 function wpbs_calendars(){
   7     $do = (!empty($_GET['do'])) ? $_GET['do'] : 'calendars';
   8     switch($do){
  ..
  49         case 'booking-delete':
  50             include WPBS_DIR_PATH . '/controllers/bookings/
     booking-delete.php';
  ..
  54     }
  55 }

controllers/bookings/booking-delete.php:

  4 $sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingID
    = '. $_GET['bookingID'] .'';
  5 $booking = $wpdb->get_row( $sql, ARRAY_A );

Exploit Methodology

The attacker will have to do the following to exploit this vulnerability:-

  • The attacker has to upload a payload in page/comments which can exploit sql injection vulnerability
  • Attacker waits for admin to visit page/comments to execute SQL injection
  • Attacker can gain access to the website

Security Patch

diff --git a/wp-content/plugins/wp-booking-system/controllers/bookings/booking-delete.php b/wp-content/plugins/wp-booking-system/controllers/bookings/booking-delete.php
index dad7fa8..186b916 100644
--- a/wp-content/plugins/wp-booking-system/controllers/bookings/booking-delete.php
+++ b/wp-content/plugins/wp-booking-system/controllers/bookings/booking-delete.php
@@ -1,7 +1,8 @@
 <?php
 global $wpdb;
 $goto = '';
-$sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingID = '. $_GET['bookingID'] .'';
+$bookingID = esc_sql($_GET['bookingID']);
+$sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_calendars WHERE calendarID = "' . $calendarID . '"';
 $booking = $wpdb->get_row( $sql, ARRAY_A );
 if($booking['bookingStatus'] == 'pending'){
     $wpdb->update( $wpdb->prefix.'bs_bookings', array('bookingStatus' => 'trash'), array('bookingID' => $_GET['bookingID']) );     
@@ -14,4 +15,4 @@ wp_redirect(admin_url('admin.php?page=wp-booking-system&do=edit-calendar&id='.$_
 die();


-?>
\ No newline at end of file
+?>
diff --git a/wp-content/plugins/wp-booking-system/include/bookingAjax.php b/wp-content/plugins/wp-booking-system/include/bookingAjax.php
index 8630649..6aab2ab 100644
--- a/wp-content/plugins/wp-booking-system/include/bookingAjax.php
+++ b/wp-content/plugins/wp-booking-system/include/bookingAjax.php
@@ -1,7 +1,8 @@
 <?php
 function bookingModalData_callback() {
     global $wpdb;
-    $sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_calendars WHERE calendarID = ' . $_POST['calendarID'];
+    $calendarID = esc_sql($_POST['calendarID']);
+    $sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_calendars WHERE calendarID = "' . $calendarID . '"';
     $calendar = $wpdb->get_row( $sql, ARRAY_A );
     echo '<div class="wpbs-modal-box-content wpbs-calendar-'.$calendar['calendarID'].'">';
         echo wpbs_edit_dates( array( 'customRange' => true, 'startDate' => $_POST['startDate'], 'endDate' => $_POST['endDate'], 'calendarData' => $calendar['calendarData'], 'calendarLegend' => $calendar['calendarLegend'], 'currentTimestamp' => time(), 'calendarLanguage' => 'en' ) ) ;    
@@ -12,7 +13,8 @@ function bookingModalData_callback() {

 function bookingMarkAsRead_callback() {
     global $wpdb;
-    $wpdb->update( $wpdb->prefix.'bs_bookings', array('bookingRead' => '1'), array('bookingID' => $_POST['bookingID']) );     
+    $bookingID = esc_sql($_POST['bookingID']);
+    $wpdb->update( $wpdb->prefix.'bs_bookings', array('bookingRead' => '1'), array('bookingID' => $bookingID) );
        die(); 
 }

diff --git a/wp-content/plugins/wp-booking-system/include/bookingCore.php b/wp-content/plugins/wp-booking-system/include/bookingCore.php
index 319e50e..00fb920 100644
--- a/wp-content/plugins/wp-booking-system/include/bookingCore.php
+++ b/wp-content/plugins/wp-booking-system/include/bookingCore.php
@@ -5,9 +5,9 @@ function wpbs_display_bookings($calendarID = ""){
     $bookingStatuses = array('pending' => 'ORDER BY createdDate ASC', 'accepted' => 'ORDER BY startDate ASC','trash' => 'ORDER BY createdDate ASC');


-    
+    $calendarID = esc_sql($calendarID);    
     $sql = 'SELECT bookingID FROM ' . $wpdb->prefix . 'bs_bookings WHERE calendarID = "'. $calendarID .'"';
-    $rows = $wpdb->get_results( $sql, ARRAY_A );
+    $rows = $wpdb->query( $sql, ARRAY_A );
     if($wpdb->num_rows > 0):
         echo '<div class="wpbs-bookings-container">';
             //menu
@@ -15,7 +15,7 @@ function wpbs_display_bookings($calendarID = ""){
             $i = 0; foreach($bookingStatuses as $bookingStatus => $orderBy):

                 if(++$i != 1) echo " | "; 
-                $bookingsQuery = 'SELECT bookingID FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingStatus = "'.$bookingStatus.'" AND calendarID = '. $calendarID .' ' . $orderBy;
+                $bookingsQuery = 'SELECT bookingID FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingStatus = "'.$bookingStatus.'" AND calendarID = "'. $calendarID .'" ' . $orderBy;
                 $bookings = $wpdb->get_results( $bookingsQuery, ARRAY_A );
                 echo '<a href="#wpbs-bookings-'.$bookingStatus.'" class="wpbs-bookings-tab-button" id="wpbs-bookings-tab-'.$bookingStatus.'">'.ucwords($bookingStatus).'</a>';
                 echo ' <span class="wpbs-bookings-count">('.$wpdb->num_rows.')</span>';                  
@@ -27,7 +27,7 @@ function wpbs_display_bookings($calendarID = ""){
             echo '<div class="wpbs-bookings-statuses">';
             foreach($bookingStatuses as $bookingStatus => $orderBy):

-                $bookingsQuery = 'SELECT bookingID,bookingStatus FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingStatus = "'.$bookingStatus.'" AND calendarID = '. $calendarID .' ' . $orderBy;
+                $bookingsQuery = 'SELECT bookingID,bookingStatus FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingStatus = "'.$bookingStatus.'" AND calendarID = "'. $calendarID .'" ' . $orderBy;
                 $bookings = $wpdb->get_results( $bookingsQuery, ARRAY_A );

                 echo '<div id="wpbs-bookings-'.$bookingStatus.'" class="wpbs-bookings-status wpbs-bookings-'.$bookingStatus.'">';
@@ -59,7 +59,8 @@ function wpbs_display_bookings($calendarID = ""){

 function wpbs_display_single_booking($bookingID){
     global $wpdb; 
-    $sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingID = '. $bookingID .'';
+    $bookingID = esc_sql($bookingID);
+    $sql = 'SELECT * FROM ' . $wpdb->prefix . 'bs_bookings WHERE bookingID = "'. $bookingID .'"';
     $booking = $wpdb->get_row( $sql, ARRAY_A );
     $bookingData = json_decode($booking['bookingData'],true);
     $preview = '';

References

dumpco.re