Часть II: Первое погружение

Когда идёшь сквозь ад, продолжай идти

Уинстон Черчиль

Глава 5. Побег из тюрьмы

Всего через 24 часа с начала нашей фишинговой компании мы взломали 35 паролей. Это 35 пуль в виде 35 сотрудников, которых мы способны олицетворять. По причине их любопытства наша фишинговая почта смогла обмануть даже нескольких технически подкованных продавцов и ИТ- администраторов. Учитывая нашу окончательную цель внедрения потайной двери в код Strat Accounting, нашей целью выступает любой, у кого имеется доступ для записи в эту базу кода, будь то персонал ИТ- поддержки, инженеры по обеспечению качества, программисты или, конечно же, ИТ- администраторы.

Мы знаем, что большинство наших общедоступных жертв благодаря нашим целевым электронным письмам, скорее всего, программисты; однако мы не можем быть уверенными что все они вовлечены в проект Strat Accounting. К счастью, когда мы окажемся внутри их корпоративной сетевой среды, мы обретём чёткую идею.

Будьте готовы к нашему первому погружению.

[Замечание]Сторонние провода

Вновь и вновь тестирующие проникновения и участники красной команды ассоциируют кражу компании с получением полномочий администратора домена. Сколь убогий взгляд и упрощённый способ моделирования угроз реального мира.

Домен Windows, или, точнее, домен Active Directory, это набор серверов, компьютеров, пользователей и прочих объектов, соединённых воедино общими атрибутами конфигурации. Множество серверов, именуемых контроллерами домена, управляет этими объектами и имеет дело со всем, начиная с аутентификации и вплоть до настроек системы. Несколько обладающих высокими правами доступа к этим контроллерам домена пользователей и, соответственно, ко всем ресурсам в домене и носят название администраторов домена. Администратор домена имеет возможность подключаться к любому компьютеру, получать доступ к любой папке в любом подключённом к домену компьютеру, сбрасывать пароли пользователей, создавать дамп электронной почты и так далее.

Как только мы получаем полномочия администратора домена, мы получаем полную свободу действий во всех системах Windows, на которые запросто приходится более 80 процентов инфраструктуры ИТ. Несомненно, именно по этой причине ограниченные по времени и бюджету тестирующие проникновения зачастую гоняются за этим Святым граалем. Это единственная находка для управления всем. Единственная уязвимость для извлечения неограниченного числа опасностей. Идеальный ответ на несовершенный пример.

Однако мы не тестируем проникновение. У нас нет ограничения по времени, ни обязанности сообщать о результатах и убеждать сварливый совет директоров в вашей ценности. Если мы будем способны добиться своего при помощи обычной учётной записи разработчика, пусть будет так.

Ныряем

Через свой сервер интерфейса Windows, зарегистрированный в центре обработки данных (ЦОД) где- то в Лондоне, мы подключаемся к приложению экстрасети Strat Jumbo в stratextranet.stratjumbo.com, воспользовавшись одними случайно выбранными учётными данных из полученных нами через фишинг в предыдущей главе. Мы остановились на учётных данных Лауры, поскольку ей доводилось в Великобритании, а потому это породит меньше подозрений. На Рисунке 5.1 мы вводим свои с трудом нарытые учётные данные.

 

Рисунок 5.1


Подключаемся к экстрасети от имени Лауры

Мы получаем приветствие от чего-то, похожего на платформу Citrix, предлагающую исполнять лишь одно приложение - браузер Firefox - как это показано на Рисунке 5.2.

 

Рисунок 5.2


Платформа Citrix

Тогда давайте рассмотрим Citrix! Citrix это среда виртуализации, которую обычно предпочитают крупные компании для предоставления внешним сотрудникам или партнёрам по бизнесу ограниченного доступа ко внутренним ресурсам: бизнес- приложениям, файловым ресурсам и т.п.

Доступные через Citrix программы выполняются в одном из множества серверов фермы Citrix, однако конечному пользователю представляется, что связанная с ним программа реально работает в его собственном компьютере. Мы можем наблюдать это на Рисунке 5.3.

 

Рисунок 5.3


Внешний браузер, запущенный в удалённом сервере Citrix, в то время как другой исполняется в нашей локальной машине

В то время как естественный RDP (Remote Desktop Protocol) Microsoft часто настраивается при подключении к серверу на предоставление пользователям полного графического интерфейса, Citrix ограничивает подобное подключение единственным приложением. Если хотите, представляйте себе это как искажённую, ограниченную форму RDP. Рисунок 5.4 представляет собой упрощённую схему типичной архитектуры Citrix, помогающую вам представить себе эту платформу.

Крайняя слева машина представляет собой наш собственный компьютер. Сервер NetScaler действует как балансировщик нагрузки и обратный прокси- сервер для распределения подключений пользователей к нескольким системам StoreFront , предоставляющим доступ этому пользователю к своим приложениям через интерфейс пользователя, аналогичный тому, который мы наблюдали на Рисунке 5.3. Администраторы настраивают StoreFront для объявления и определения того какие именно приложения должны публиковаться, кто может получать к ним доступ, какой тип проверки подлинности осуществлять, а также прочие разрешения и ограничения. Тем не менее, работающие через Citrix приложения не выполняются в StoreFront, а они извлекаются из своего рода инкапсулированного RDP с удалённых серверов Windows, носящих название XenApps.

 

Рисунок 5.5


Вывод ошибки при попытке доступа к командной строке Citrix

Естественно, это было бы слишком просто. Судя по всему, Strat Jumbo слегка приподнял планку. Основываясь на тексте сообщения об ошибке, мы способны сделать предположение, что нас заблокировал AppLocker, собственное решение Microsoft для ограничения приложений. AppLocker позволяет администраторам блокировать исполняемые файлы, которые предполагаются опасными. Диспетчер задач представляет очевидную потенциальную опасность, поскольку способен создавать процессы. Мы попробуем найти способ обхода этого.

Вернёмся обратно в своё окно Firefox и нажмём CTRL-O, на этот раз для запуска диалога Open File, а также попытаемся осуществить оттуда доступ к устройству C:, как это показано на Рисунке 5.6. Мы не можем получить доступ к основному устройству C: или к его копии через \\127.0.0.1\C$.

 

Рисунок 5.6


Вывод ошибки при попытке доступа к устройству C: Citrix

И снова, на базе полученного сообщения об ошибке, мы можем отважиться предсказать что администраторы обязаны обладать применяемыми некой Групповой политикой настройками для ограничения доступа как к самому устройству, так и к его сетевому совместному ресурсу.

[Замечание]Замечание

GPO (Group Policy Objects, Объекты Групповой политики) это наборы правил и настроек, применяемых на уровне домена AD к какому- то подмножеству пользователей и рабочих станций. Эти правила в Windows могут покрывать широкий массив элементов конфигурации, такие как сложность пароля, время увольнения или, в данном случае, доступ к устройству C:.

Забавно, однако мы способны обойти это глупое ограничение, просматривая соответствующую файловую систему непосредственно через адресную полосу Firefox file:///c:/, как это видно на Рисунке 5.7... Эх, Windows! Зачастую правила, подобные блокировке доступа к диску C: основаны на жёстких предположениях о таких вещах, как имя родительского процесса или выполняющего действие вызова API. Изучая глубокие траншей данной системы мы способны воссоздать тот же нужный нам результат, применяя неожиданные инструменты, которые разрушают подобные предположения (к примеру, применяя веб браузер для изучения локальной файловой системы).

 

Рисунок 5.7


Просмотр файловой системы Citrix через адресную планку Firefox

Мы знаем что диалоги Open File и Save As это субъекты тех же самых описанных ранее ограничений настроек GPO, а поэтому мы не можем выполнять запись в файл или заменять их, но мы способны обладать простым доступом на считывание. Это позволяет нам просматривать соответствующий жёсткий диск на предмет низко висящих фруктов, таких как персональные папки, пароли в открытом тексте, оставленные без присмотра файла настроек во временных папках и тому подобного. Какое- то время мы просматриваем, но, к несчастью для нас, ничего полезного не бросается в глаза.

Продолжая спорить с AppLocker и ограничительными настройками GPO, мы попытаемся запустить несколько программ из адресной строки диалогового окна Open File, как это можно видеть на Рисунке 5.8. Мы испробуем несколько обычных подозреваемых, что позволит нам избежать ограничительного характера просмотра веб- страниц чтобы более свободно исследовать эту систему и прочие машины в данной сетевой среде: cmd.exe, explorer.exe, notepad.exe, WMIC, комплект Office, CScript, JScript, rundll32, mshta и так далее. Если вы не знакомы с этими естественными инструментами Windows отсылаем вас к ссылке UltimateApplockerByPassList в разделе Ресурсы в конце этой главы.

 

Рисунок 5.8


Попытка породить программы из адресной планки диалога File Citrix

И все они заблокированы, за исключением нашего старого доброго товарища PowerShell.exe, как это отражено на Рисунке 5.9.

 

Рисунок 5.9


Успех! Мы получили доступ к PowerShell в Citrix

Что может быть проще? Когда мы в PowerShell запрашиваем имя хоста, мы получаем имя сервера Strat-CI-01.

Подключающиеся к опубликованному в сервере XenApp приложению пользователи сопоставляются с реальным пользователем Windows, а домашняя из сетевой папки назначается совместно используемой всеми пользователями Citrix. Эта домашняя папка обычно сопоставляется с некой буквой локального диска, отсюда и X:\ в приглашении на ввод с Рисунка 5.9. Сеанс PowerShell сам по себе не ограничивает доступ к диску C: больше чем это делает его сеанс Firefox. Можно даже вообще задаться вопросом зачем они вообще реализовали в первую очередь такую настройку GPO.

Рекогносцировка сервера

В этом сервере Strat-CI-01 мы испытаем несколько несложных команд для разведывания обстановки для получения краткого обзора среды, к которой мы подключены. Прежде всего для получения сетевых настроек мы запускаем ipconfig, а вслед за ней systeminfo для сбора основных сведений о системе:


   PS X:\> ipconfig
   Windows IP Configuration
      Connection-specific DNS Suffix    : stratjumbo.lan
  (1) IPv4 Address. . . . . . . . . . . : 10.78.1.83
      Subnet Mask . . . . . . . . . . . : 255.255.255.0
 
   PS X:\> systeminfo
   Host Name:        STRAT-CI-01
   OS Name:          Microsoft Windows Server 2019 Datacenter
(2) OS Version:      10.0.17763 N/A Build 17763
(3) Domain:          stratjumbo.lan
   Hotfix(s):        22 Hotfix(s) Installed
                     [01]: KB3186568
                     [02]: KB3192137
                     --snip--
                 (4) [56]: KB5011503
		

Здесь мы можем наблюдать, что мы имеем дело с самой последней версией (по состоянию на март 2022) Windows Server 2019 с номером сборки 17763(2). Этот сервер расположен в сетевой среде 10.78.1.83/24(1), причём вероятно изолированной от прочих критически важных ресурсов, таких как внутренние базы данных и репозитории кода. Корпоративный домен AD обладает названием Italicstratjumbo.lan(3).

Эта система была только что снабжена исправлениями; это снабжено событием с номером KB KB5011503(4), что, как показывает быстрый поиск в Google, сообщает нам, что они были активированы 8 марта 2022 года. Мы можем забыть о недавно выпущенных эксплойтах повышения полномочий.

Затем мы перечислим всех имеющихся в данной машине пользователей с правами локального администратора:


PS X:\> net localgroup "administrators"

Members
-------------------------------------------------------
Administrator
STRATJUMBO\citrix_srv
STRATJUMBO\Domain Admins
		

Учётная запись домена Citrix_srv обладает в этой машине правами администратора. Его имя предполагает, что он также может содержать те же самые полномочия в прочих серверах XenApp в нашей ферме Citrix. Это была бы ценная учётная запись, которую стоило бы взять в свои руки, что стоит взять на заметку.

Далее проверим свой домен Windows stratjumbo.lan. Я уже упоминал ранее, что администраторы домена это богоподобные учётные записи, на которые не распространяются правила простых смертных. Давайте, воспользовавшись своей следующей командой, проверим кто в Strat Jumbo является администратором домена:


PS X:\> net group "domain admins" /domain

Members
-------------------------------------------------------
admin.beny            admin.ho             admin.stanley
admin.edward          admin.flavien        admin.bill
admin.mehdi           admin.penny          admin.nastya
admin.jed             admin.chan           admin.ken
admin.shwartz         admin.klauss         admin.silberto
--snip--
		

Домен Windows Strat Jumbo выглядит как управляемый 30 учётными записями с высокими полномочиями. Мы пробегаемся по этому небольшому перечню на предмет совпадений с полученными нами в результате фишинга именами пользователей, но на этот раз удача не нашей стороне: совпадений нет. Тем не менее, нам надлежит следить за этими учётными записями на тот случай, если мы когда- нибудь наткнёмся на одну из них.

Автоматизируем свою рекогносцировку

Выполнение разведки при помощи инструментов Windows может быстро разочаровывать. От администраторов доменов можно получить гораздо больше сведений, чем просто названия их учётных записей, а это всё что нам удалось узнать при помощи наших наивных сетевых команд. Мы желаем знать время последнего подключения этих администраторов, их последнюю ротацию паролей, членство в группах и тому подобное.

LDAP (Lightweight Directory Access Protocol, Протокол облегчённого доступа к каталогам) это распространённый способ взаимодействия с базой данных Active Directory. Мы можем воспользоваться запросами к LDAP для получения свойств пользователей, объектов групповой политики и прочих хранящихся в AD объектов. Однако более простой альтернативой является сбор сведений при помощи таких инструментов как PowerView, которые автоматизируют все эти малоприятные плоские вызовы Контроллера домена и сжимают получаемые результаты в представительный вывод, более удобный для наших глаз.

PowerView изначально разрабатывался @harmj0y и @sixdub как набор наступательных инструментов PowerShell, которые позднее трансформировались в инфраструктуру Empire, обёртывающую запросы LDAP в более удобные для применения API, сосредоточенные на разведке в домене. Его первоначальную версию вы можете найти в GitHub PowerShellMafia.

У вас может возникнуть соблазн выгрузить этот сценарий в папку на исследуемом сервере Citrix и сохранить его там, но это напустит внутреннего зверя всякого известного антивируса на эту бледноголубую точку. К счастью, PowerShell предоставляет изящный способ более тонкой загрузки сценариев в память во избежание большинства антивирусных проверок.

Прежде всего мы построим объект браузера при помощи такой команды:


PS X:\> $browser = New-Object System.Net.Webclient;
New-Object : Cannot create type. Only core types are supported in this language mode.
At line:1 char:12
+ $browser = New-Object System.Net.Webclient;
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : PermissionDenied: (:) [New-Object], PSNotSupportedExcept
+ FullyQualifiedErrorID : CannotCreateTypeConstrainedLanguage,Micrososft.Powershell
		

Постойте, обычно так не бывает. Ой. Ну как же, это, мягко говоря, разочаровывает. Возможно, администраторы Citrix небрежно упустили из виду PowerShell, но правила сценариев AppLocker позаботились о том, чтобы урезать большинство его возможностей. Microsoft называет это режимом Ограничений языка (Constrained Language).


PS X:\> $ExecutionContext.SessionState.LanguageMode
ConstrainedLanguage
		

Режим Ограничений языка лимитирует PowerShell нормированным подмножеством одобренных и безопасных свойств. Команда New-Object несомненно не относится к подобным безопасным функциональным возможностям, поскольку она определяет объекты .NET или COM, которые расширяют богатство PowerShell для взаимодействия с внутренними компонентами Windows - как следствие, предыдущая ошибка.

Component Object Model (COM, модель компонентных объектов) это разработанный Microsoft стандарт для управления взаимодействием между процессами. Такая программа как Internet Explorer способна зарегистрировать некий объект COM, который определяет подобные FetchURL, DownloadFile, BrowseToPage и тому подобные методы. Затем некий сценарий Visual Basic способен конкретизировать такой объект COM и вызвать его методы для какой- либо необходимой цели. То же самое верно и для сценария Python, который понимает COM, сценария PowerShell, программы C++ и так далее. Внутреннее устройство COM несколько сложнее того, что следует из данного пояснения, но основная суть в том, что цель COM именно и заключается в наличии унифицированного способа вызова удалённых процедур, публикуемых прочими программами. Вы можете догадаться почему создание COM- объектов запрещено в режиме с Ограничениями языка PowerShell, ибо они делают возможным взаимодействие с внутренними компонентами Windows, а в конечном итоге, избегать ограничений.

.NET во многом следует стандарту COM и подменяет COM в предоставлении полной инфраструктуры для разработки, сборки и запуска приложений в Windows. В точности как и с объектами CON, сы можем применять типы и классы .NET для активации произвольных API Windows для считывания файлов, создания процессов, отправки сетевых пакетов и многого иного. Все допускающий такой низкоуровневый доступ свойства .NET, таким образом, блокируются режимом с Ограничениями языка PowerShell, включая интенсивно применяемую команду add-type, которая способна определять новые классы из естественного кода C#.

Тем самым, большинство наступательных сценариев PowerShell рынка, которые обязательно полагаются на такие функциональные возможности, превращаются в почти бесполезные по причине режима с Ограничениями языка, настроек безопасности, представленных в механизме исполнения PowerShell версии 5 (он же Windows Management Framework версии 5, или WMF 5).

Самый простой способ обхода данного ограничения среды состоял бы в вызове устанавливаемого по умолчанию интерпретатора PowerShell V2, который не реализует никаких новых свойств безопасности V5:


PS X:\> powershell -version 2 -command {$browser = New-Object...}

Version 2.9.50727 of the .NET Framework is not installed and it is required to run version 2 of Windows PowerShell
		

Опять не повезло, V2 PowerShell, а следовательно и .NET Framework, не установлены в данном сервере.

Вместо того чтобы пытаться загружать сценарии в память, мы могли бы вернуться к более традиционному подходу сброса DLL и исполняемых файлов на диск - но это тоже не так просто. Развёрнутая в этом сервере политика AppLocker допускает исполнение только из обладающих доверием местоположений. Вызвав командлет Get-AppLockerPolicy, мы можем получить перечень таких местоположений, с последующим изучением коллекций правил соответствующего объекта:


PS X:\> import-module applocker
PS X:\> $a = Get-AppLockerPolicy -effective
PS X:\> $a.rulecollections

PathConditions      : (1) {%WINDIR%\*}
PathExceptions      : {}
PublisherExceptions : {}
HashExceptions      : {}
Name                : (Default Rule) Microsoft Windows DLLs
Description         : Allows members of the Everyone group to load DLLs...
UserOrGroupSid      : S-1-1-0
Action              : Allow
--snip--
		

Правила AppLocker допускают исполнение лишь из каталогов пути, таких как {%WINDIR%}(1), что эквивалентно C:\Windows и прочим системным папкам, в которых полномочиями на запись обладают лишь администраторы.

Кажется, нам следует расчехлять крупную артиллерию чтобы избежать смертельного сочетания AppLocker и ограничений среды PowerShell.

Персональная обложка PowerShell

PowerShell.exe, как и большинство сложных исполняемых файлов, это просто обёртка вокруг DLL, которая экспортирует все методы и API, которые в действительности и осуществляют необходимую работу. Все доступные в PowerShell функциональные возможности ядра, к примеру, определены в файле System.Management.Automation.dll и экспортируются им.

В то время как PowerShell.exe принуждается к режиму с Ограничениями языка при активации AppLocker, System.Management.Automation.dll продолжает оперировать в режиме Полного языка, наплевав на правила AppLocker. Таким образом, мы имеем возможность собрать свою собственную обёртку, которая вызывает и инициирует System.Management.Automation.dll и, быть может, предоставит нам ещё раз счастье всей мощи команд PowerShell.

Благодаря AppLocker для исполнения допустимы лишь файлы из определённых папок (в данном случае C:\Windows и C:\Programs), а у нас нет полномочий на запись в эти папки. Данная обложка, тем самым, не может быть неким внешним исполняемым файлом (.exe или .dll), который собирается обособленно и затем сбрасывается в среду Citrix. Вместо этого нам надлежит собрать его внутри самой среду Citrix. Поскольку всё столь жёстко заблокировано, нам следует учитывать что допускается в данной машине. Ответ - доверенные исполняемые файлы; то есть программы и утилиты, присутствующие в любой среде Windows, которыми можно манипулировать многими неожиданными способами.

Встречайте Кейса Смита (@subtee), исследователя безопасности, чьи многочисленные советы и приёмы по злоупотреблению доверенными исполняемыми файлами Windows превратили его в кого- то вроде богоподобной фигуры и надёжного авторитета в сообществе безопасности. Имя Кейси является почти синонимом обхода решений по контролю над приложениями. Он продемонстрировал всевозможные приёмы манипуляции такими исполняемыми файлами от столь простых трюков как загрузка файлов при помощи certutil.exe, инструмента для отображения сертификатов, вплоть до более сложных методов, таких как исполнение шеллкода и вредоносных программ с применением Regsvr32, естественного инструмента Windows, который регистрирует объекты COM для того, чтобы их методы имели возможность вызова из прочих программ. Если вас это заинтересовало, проверьте соответствующие ссылки в разделе Ресурсы данной главы.

Одной из подобных мощных уловок, которым мы способны воспользоваться в своём затруднительном случае, вовлекает MSBuild, платформу ядра, которая компилирует и запускает приложения .NET MSBuild - это подписанный Microsoft исполняемый файл, расположенный во вложенной папке доверенного каталога (C:\Windows), точное расположение которого зависит от версии .NET Framework нашей целевой системы. Для версии 4, к примеру, это C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe. Если вы не обнаружите его там, проверьте иные вложенные каталоги в папке Microsoft.NET, и вы обязательно его отыщите.

Предполагая что данный исполняемый файл располагается в данной папке C:\Windows, AppLocker позволяет ему запускаться под устанавливаемыми по умолчанию правилами. А поскольку MSBuild безмерно полезный инструмент, на постоянной основе применяемый разработчиками для своих возможностей написания сценариев, мало вероятно что администраторы заблокируют его по всем своим серверам - в особенности Strat Jumbo, в той фирме, разработчики которой полагаются на такие инструменты. И в самом деле, когда мы вводим упомянутый выше путь MSBuild, мы видим, что способны свободно запускать эту утилиту из диалогового окна Open File, как это отображено на Рисунке 5.10, хотя он и быстро пропадёт, ибо завершается ошибкой, когда ему не предоставлен надлежащий файл на входе.

 

Рисунок 5.10


Мы способны исполнять MSBuild.exe в своей системе Citrix

Теперь, когда нам известно что мы имеем возможность запуска MSBuild, нам потребуется собрать нечто для исполнения им. MSBuild исполняет проекты, написанные в XML, которые объявляют необходимые задачи и этапы, за которыми производится компиляция исполняемого файла: какие файлы скопировать, какой исходный код вложить, какие DLL скомпоновать и так далее. Наш проект будет содержать собственно код нашей обёртки PowerShell для компиляции. В случае успеха, MSBuild автоматически загрузит и запустит этот исполняемый файл, при этом обходя правила AppLocker.

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

Собираем проект MSBuild

В одном из своих серверов хакинга мы начинаем писать пустой файл проекта MSBuild с безобидным названием readme.txt, следуя руководству из документации Visual Studio 2017 "Creating an MSBuild Project File from Scratch". Этот проект пишется на XML и мы пользуемся той же самой версией MSBuild, которую нашли в своей целевой системе:


<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/MSBuild/2003">

</Project>
 	   

Как правило, проект MSBuild включает в свой состав некий узел Target, который выступает корневым элементом, собирающим все последующие подлежащие исполнению задачи. Задача может быть некоторой встроенной операцией типа MakeDir для создания каталогов или Copy для копирования файлов, либо некой персональной, которую мы определяем с нуля при помощи индивидуального кода. Поскольку мы пристреливаем свой проект MSBuild на способность к чему- то более сложному - компиляции и запуску кода на лету - нам требуется создать свою собственную задачу, определив новый элемент XML.

Здесь мы добавляем некую персональную задачу и добавляем её к узлу Target своего проекта MSBuild:


<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/MSBuild/2003">

<Target Name="PSBYPASS">
  <PsCommand/>
</Target>

</Project>
 	   

PsCommand это название индивидуальной задачи, компиляцию которой мы бы хотели от MSBuild с последующим запуском в нашей среде Citrix. Мы предоставляем это название в элементе UsingTask, который регистрирует данную задачу:


<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/MSBuild/2003">

<Target Name="PSBYPASS">
  <PsCommand/>
</Target>
<UsingTask
    TaskName="PsCommand"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
</UsingTask>

</Project>
 	   

Определение значения атрибута TaskName для UsingTask должно соответствовать названию в его узле Target. Определение атрибута TaskFactory указывает на значение реализующего эти методы и свойства класса, необходимые для компиляции нашего кода потока. Мы бы хотели чтобы наша задача скомпилировала код C# (который вскорости будет написан), а потому мы загружаем из соответствующего файла DLL Microsoft.Build.Tasks.v4.0.dll необходимый класс с названием CodeTaskFactory (что также носит название компоновки).

Далее внутри элемента UsingTask мы определяем некую потоковую Task, который предоставляет тот код, который исполняется в процессе сборки и он - сюрприз- сюрприз - содержится в дочернем элементе Code:


<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/MSBuild/2003">

<Target Name="PSBYPASS">
  <PsCommand/>
</Target>
<UsingTask
    TaskName="PsCommand"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <Task>
      <Reference Include="System.Management.Automation" />
      <Code Type="Class" Language="cs">
        <![CDATA[
            // Впишите сюда код C#! 1
        ]]>
      </Code>
    </Task>
</UsingTask>

</Project>
 	   

Как постулировалось ранее, чтобы иметь возможность вызова команд PowerShell, нам необходимо загрузить DLL System.Management.Automation, поэтому мы включаем эту DLL в свой элемент Reference. Строка с комментарием указывает то место, в которое мы добавим свой код C# для вызова классов и функций .NET с целью загрузки среды PowerShell1.

PowerShell без ограничений

Мы начинаем с определения общедоступного класса с названием PsCommand. MSBuild требует чтобы все задачи для него наследовали интерфейсы ITask и Task распознаваемые его механизмом. Эти классы соответственно определяются в DLL Microsoft.Build.Framework и Microsoft.Build.Utilities, а потому убедитесь что вы их также импортировали. Также мы импортируем класс System.Management.Automation.PowerShell и даём ему псевдоним PowerShell для лучшей читаемости:


// Импорт всех необходимых DLL
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using PowerShell = System.Management.Automation.PowerShell;

// Реализующий необходимые интерфейсы Task и ITask общедоступный главный класс
public class PsCommand : Task, ITask
{

}
 	   

Внутри класса PsCommand мы перекрываем функцию Execute интерфейса по умолчанию ITask, и это именно то место, в котором MSBuild запускает наш поток (thread) исполнения с нашим собственным кодом C#. Я отсёк повторяющийся код и выделил все новые строки жирным шрифтом:


--snip--
public class PsCommand : Task, ITask
{

  // Перекрываем метод Execute. Сам поток (thread) исполнения начинается здесь
  public override bool Execute() {
    // Вывод приветствия
    Console.WriteLine("Executing PS commands");

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();

    // Конец нашего метода Execute
    return true;
  }
}
		

Мы стартуем с простого вывода на печать строки предвестницы "Executing PS commands" при помощи метода WriteLine, за которым следует вызов ReadKey для приостановки на паузу нашей программы чтобы убедиться что всё в норме.

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


--snip--
public class PsCommand : Task, ITask
{

  public override bool Execute() {

    Console.WriteLine("Executing PS commands");

    // Создание конвейера PowerShell: command1 | command2 | ...
    PowerShell Ps_instance = PowerShell.Create();

    // Изменение команд в нашем конвейере
    string script="$ExecutionContext.SessionState.LanguageMode"
    Ps_instance.AddScript(script);

    // Активация нашего конвейера и выборка строк вывода
    foreach (string str in Ps_instance.Invoke<string>()){
      Console.WriteLine(str);
    }

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
    return true;

  } // Конец метода Execute
} // Конец класса PsCommand
		

Напомним, что мы применили MSBuild для компиляции и выполнения написанного на XML проекта, содержащего код C#, который загружает интерпретатор PowerShell для исполнения любой команды, которую мы пожелаем.

Вы всё ещё со мной? Отлично. Я поместил окончательный код в GitHub, просто для того варианта, если вам потребуется выгрузить его и поэкспериментировать с ним. Вы обнаружите данный сценарий в моём файле psh.xml в папке msbuild. Это наилучший способ чтобы усвоить обсуждённые нами понятия.

В своей лабораторной системе мы скомпилировали и исполнили свой файл проекта MSBuild readme.txt при помощи:


C:\Windows\Microsoft.Net\Framework64\v4.0.30319\MSBuild.exe readme.txt

Microsoft (R) Build Engine version 4.7.2053.0
[Microsoft .NET Framework, version 4.0.30319.42000]
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 3/5/2022 7:59:01 PM.
Executing PS commands
FullLanguage
Press any key to exit...
		

Наш код, таким образом, исполняется в режиме Полного языка, как и ожидалось. Всё идёт как надо; он готов к отправке в сервер XenApp Strat Jumbo. Мы загружаем свой проект в одну из наших машин С2 и выгружаем его в свою домашнюю папку (X:) применяя старый добрый Firefox.

Теперь в среде Citrix из Firefox, воспользовавшись CTRL-O, мы открываем диалоговое окно Open File и запускаем ту же самую команду, как это видно на Рисунке 5.11.

 

Рисунок 5.11


Запуск нашей команды из диалога Open File в Firefox

Потрясающе! Мы добились исполнения команд PowerShell в режиме Полного языка и одновременно обошли AppLocker. Речь идёт о двойной победе!

Воспользовавшись тем же самым подробно описанным в проекте readme.txt MSBuild скелете мы можем следующим образом соединить в цепочку простые команды:


Ps_instance.AddCommand("get-process");
Ps_instance.AddCommand("out-string");
Ps_instance.AddStatement();
Ps_instance.AddScript("net user");
Ps_instance.AddStatement();
Ps_instance.AddScript("ls c: | out-string");
 	   

Мы пользуемся своей функцией AddCommand для одиночных естественных командлетов PowerShell (get-process, start-service и тому подобных), а также мы запускаем AddScript для исполнения блоков сценариев и внешний исполняемых файлов, либо соединения в цепочку множества командлетов. AddStatement() эквивалентен разделителю ;.

Ресурсы