Уязвима ли это соединение с базой данных Perl для SQL-инъекций?

Вопрос или проблема

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

Насколько мне известно, он использует подготовленные выражения и, следовательно, считается достаточно безопасным. Однако я нашел это относительно проблем с quote и param.

if ('POST' eq request_method && param('username') && param('password')){
    my $dbh = DBI->connect( "DBI:mysql:database_name","database_name", "<censored>", {'RaiseError' => 1});
    my $query="Select * FROM users where username =".$dbh->quote(param('username')) . " and password =".$dbh->quote(param('password')); 

    my $sth = $dbh->prepare($query);
    $sth->execute();
    my $ver = $sth->fetch();
    if ($ver){
        print "win!<br>";
        print "here is your result:<br>";
        print @$ver;
    }
    else{
        print "fail";
    }
    $sth->finish();
    $dbh->disconnect();
}

Это небезопасно, но я не думаю, что это можно эксплуатировать.

Суть в том, что param может возвращать скаляр или список. В контексте списка, если вы передадите username=a&username=b на эту страницу, список будет (“a”, “b”).

В Perl, если вы передаете список в функцию, он интерпретируется как отдельные аргументы.

quote("a", "b")

Это эквивалентно

@list = ("a", "b")
quote(@list)

Таким образом, если вы вызовете quote(param("username")), пользователь сможет предоставить второй параметр для quote, передав два значения username. Поскольку второй параметр определяет, как выполнять экранирование, это может привести к уязвимости SQL-инъекции.

Однако то, как обрабатывается второй параметр, зависит от драйвера DBD, который различен для каждого типа базы данных. Более того, это должен быть хеш-ссылка, но мы можем передавать только строку. Поэтому может быть так, что существует драйвер, в котором передача чего-то изменяет способ выполнения экранирования, но я не смог его найти. Драйвер Postgres, например, явно указывает: “Второй аргумент для quote должен быть ссылкой на хеш”.

После воспроизведения сайта локально и ознакомления с документацией

Да

Эта программа на Perl уязвима к SQL-инъекции.

  • Однако это зависит от драйвера DBI, и я смог воспроизвести это только с MySQL.

Существует 2 недостатка в $dbh->quote(param('paramater'))

  1. Видите ли, param чувствителен к контексту. В скалярном контексте, если параметр имеет одно значение (name=foo), он возвращает это значение, а если параметр имеет несколько значений (name=foo&name=bar), он возвращает arrayref.

    Согласно ссылке на SO, проблема с непосредственным вызовом param() заключается в том, что он может вернуть array

  2. Как особый случай, стандартные числовые типы оптимизированы для возврата $value без вызова type_info.

    Согласно документации DBI. Вызов quote как list с SQL_INTEGER в качестве второго параметра вернет неэкранированное значение.

Поскольку SQL_INTEGER == 4 Все, что потребовалось, – это этот скрипт на Python:

def vuln(url):
    params={"username": "valid_username", "password": ["'lol' or 1", 4]}
    print(requests.post(url, data=params).text)

В общем, это плохая идея использовать переменные POST напрямую (в конце концов, они контролируются клиентом). Лучше сделать следующее:

  • Ограничить размер ввода, чтобы ограничить переполнения.
  • Разобрать значение, чтобы убедиться, что оно того типа, которого вы ожидаете.
  • Очистить параметр, чтобы он не содержал никаких (неэкранированных) управляющих инструкций; quote делает большинство из этого, но не все (проверьте инструкции для вашей версии Perl)
  • Использовать правильные подготовленные выражения (как предлагает @Marc)

В остальном это выглядит как хороший подход, но убедитесь, что вы используете актуальное программное обеспечение и библиотеки. (это относится к любому приложению)

Я знаю, что эта тема довольно старая, но я только сегодня столкнулся с этой задачей, когда играл в уровень 30 вызова Natas в OverTheWire.

Читая ответ от @Ludisposed, я смог решить проблему, как он отметил, что SQL_INTEGER == 4, я попытался заменить число 4 на другие числа и, похоже, только от 2 до 8 работает.
Вот результат

Мне интересно, почему только числа от 2 до 8 работают в этом случае? Поскольку я пытался поискать, я лишь вижу, что люди упоминают, что SQL_INTEGER это просто целое число, например 1, 2, 3, 4 и т.д.

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

Ответ или решение

Вопрос, связанный с уязвимостью соединения с базой данных в Perl к SQL-инъекциям, требует внимательного анализа. Статья, на которую вы ссылаетесь, рассматривает несколько аспектов, касающихся использования метода quote из Perl DBI, и поясняет возможные уязвимости.

Обзор уязвимости

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

Подробный разбор кода

В приведенном вами коде основным местом, где потенциально может возникнуть SQL-инъекция, является конструкция:

$query = "SELECT * FROM users WHERE username =" . $dbh->quote(param('username')) . " AND password =" . $dbh->quote(param('password'));

Здесь метод quote используется для экранирования пользовательских вводов. Однако важно помнить, что метод param может возвращать как скалярные значения, так и массивы, что усложняет работу с его результатом.

  1. Контекст вызова: param может возвращать массив, если передано несколько значений для одного и того же ключа. В случае, если запрос будет выглядеть так:

    username=foo&username=bar

    Метод param("username") будет возвращать массив с двумя элементами. Это может привести к следующей проблеме: если quote получает массив с двумя элементами, он может не обрабатывать их должным образом и передавать их в SQL-запрос как отдельные параметры, что может существенно повлиять на безопасность.

  2. Неправильное использование quote: В случае, если param возвращает массив, это может привести к вызову метода quote с несколькими аргументами, что может вызвать неожиданное поведение, в зависимости от реализации драйвера базы данных. Это, в свою очередь, может создать уязвимость для SQL-инъекций, особенно если передается неправильный тип данных.

  3. Специфика драйвера базы данных: Как указывают исследования, конкретные детали реализации метода quote могут варьироваться в зависимости от используемого драйвера (например, MySQL или PostgreSQL). В вашем случае, тестировалось с MySQL. Если такое поведение будет несанкционировано и неправильно обработано, это может помочь злоумышленникам создать SQL-инъекции.

Выводы и рекомендации

На основании предоставленного анализа видно, что данный код действительно уязвим к SQL-инъекциям. Чтобы устранить эту уязвимость, рекомендуется следующее:

  • Используйте подготовленные выражения (Prepared Statements): Вместо динамической подстановки значений в SQL-запросы, используйте подготовленные выражения, которые позволяют безопасно передавать параметры в запросы.
my $sth = $dbh->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$sth->execute(param('username'), param('password'));
  • Валидация и фильтрация ввода: Применяйте строгую валидацию входных данных. Проверяйте, что пользователь передает ожидаемые типы данных и не содержит незаконных символов.

  • Ограничение параметров: Установите ограничения на допустимые размеры входящих данных, чтобы предотвратить возможные атаки.

  • Обновление библиотек и систем: Регулярно обновляйте используемые библиотеки и системы для обеспечения их безопасности.

Следуя этим рекомендациям, вы сможете существенно повысить безопасность вашего веб-приложения и снизить риск SQL-инъекций.

Оцените материал
Добавить комментарий

Капча загружается...