# Интенсив №4. Безопасность операционных систем Windows
## 4.1 Создание виртульных машин
### 4.1.1 Создание виртуальной машины для Windows Server 2016
Будем использовать Oracle VirtualBox

Укажем имя и тип виртуальной машины

Укажем объем оперативной памяти

Создадим диск




Виртуальная машина готова

---
### 4.1.1 Создание виртуальной машины для Windows 10
Укажем имя и тип машины

Укажем объем оперативной памяти

Создадим диск




Машина готова

---
## 4.2 Установка операционных систем
### 4.2.1 Установка Windows Server 2016
На сервере устанавливаем английскую версию ОС

Начинаем установку

Так как сервер будет исполнять роль контроллера домена, выберем вариант Server Core

Соглашаемся с лицензией

Новая установка

Выберем диск

Разметим его

Пошла установка

Необходимо сменить пароль администратора

Укажем новый пароль

Пароль сменен

Установка завершена

---
### 4.2.2 Установка Windows 10
Клиентская машина будет с русским языком

Запустим установку

Без ключа

Клиент будет членом домена, поэтому выбираем Pro версию

Принимаем лицензию

Выбираем диск

Указываем разметку

Началась установка

Выберем регион

Раскладку клавиатуры

Добавим английскую раскладку

Выберем язык

И раскладку клавиатуры

Настроим для организации

Выберем присоединение к домену, домена у нас пока нет, поэтому создадим локальную учетную запись

Укажем имя пользователя

Установим пароль пользователя

Подтвердим пароль пользователя

Установим контрольные вопросы

Откажемся от телеметрии

Пропустим настройку взаимодействия

Откажемся от журнала действий

Операционная система установлена

---
## 4.3 Базовая настройка операционных систем
### 4.3.1 Настройка Windows Server 2016
Настройку проводить будем используя Powershell
Настроим сеть, следующим скриптом
```powershell=
# имя сервера
$name = "dc"
# адрес сервера
$IPAddress = "192.168.1.225"
# маска
$NetPrefix = 24
# шлюз по умолчанию
$DefaultGW = "192.168.1.1"
# получим сетевой адаптер, он у нас один
$NetAdapter = Get-NetAdapter
# отключим ipv6
Disable-NetAdapterBinding -Name $NetAdapter.Name -ComponentID ms_tcpip6
# установим сетевую конфигурацию
New-NetIPAddress -InterfaceIndex $NetAdapter.InterfaceIndex -IPAddress $IPAddress -DefaultGateway $DefaultGW -PrefixLength $NetPrefix
# dns сервер, он сам
Set-DnsClientServerAddress -InterfaceIndex $NetAdapter.InterfaceIndex -ServerAddresses ("127.0.0.1")
# переименуюем машину
Rename-Computer -NewName $name
# перезагрузимся
Restart-Computer -Force -Verbose
```
Результат:

### 4.3.2 Настройка Windows 10
DHCP сервер у нас пока нет поэтому клиента настроим статически.
Настройки клиента выполняем аналогично серверу, данным скриптом:
```powershell=
$name = "pc"
$IPAddress = "192.168.1.111"
$NetPrefix = 24
$DefaultGW = "192.168.1.1"
$NetAdapter = Get-NetAdapter
New-NetIPAddress -InterfaceIndex $NetAdapter.InterfaceIndex -IPAddress $IPAddress -DefaultGateway $DefaultGW -PrefixLength $NetPrefix
Set-DnsClientServerAddress -InterfaceIndex $NetAdapter.InterfaceIndex -ServerAddresses ("192.168.1.225")
Rename-Computer -NewName $name
Restart-Computer -Force -Verbose
```
Результат



## 4.4 Установка ролей и создание леса Active Directory.
### 4.4.1 Установка ролей
Посмотрим установленные на данный момент роли, данным конмадлетом:
```powershell=
Get-WindowsFeature
```
Результат:

Нас интересуют службы AD-Domain-Services, DNS, DHCP и Print Server.
Установим данные службы, все их подкомпоненты комадлетом:
```powershell=
Install-WindowsFeature AD-Domain-Services, DNS, DHCP, Print-Server -IncludeAllSubFeature
```
Результат:


### 4.4.2 Создание леса Active Directory.
Повышать dc до контроллера домена будетсредствам Powershell.
Для создания леса будем использовать комадлет Install-ADDSForest, для него необходимо установить некоторые параметры:
- DomainName "pt.local" - имя домена
- DomainNetbiosName "PT" - NetBIOS имя домена
- CreateDnsDelegation:$false - отключим делегирование DNS
- DomainMode WinThreshold - режим домена максимально возможный (Win2016)
- ForestMode WinThreshold - режим леса максимально возможный (Win2016)
- SafeModeAdministratorPassword $password - установим пароль восстановления
- NoRebootOnCompletion:$true - перезагрузимся вручную
- Force:$true - выполнить без дополнительных вопросов
Остальные настройки оставим по умолчанию.
Укажем пароль восстановления
```powershell=
$password = Read-Host -AsSecureString
```
Результат:

Создадим лес следующим командлетом:
```powershell=
Install-ADDSForest -DomainName "pt.local" -DomainNetbiosName "PT" -CreateDnsDelegation:$false -DomainMode WinThreshold -ForestMode WinThreshold -SafeModeAdministratorPassword $password -NoRebootOnCompletion:$true -Force:$true
```
Результат:



Перезагрузим сервер
```powershell=
Restart-Computer -Force -Verbose
```

Проверим результат создания леса комадлетами
```powershell=
# получим информацию о лесе
Get-ADForest
# получим информацию о домене
Get-ADomain
# получим информацию о контроллере домена
Get-ADDomainController
```
Результат:



### 4.4.3 Конфигурирование перенаправления DNS запросов.
Небходимо настроить перенаправление запросов DNS, не относящихся к зоне нашего домена pt.local на внешний DNS сервер.
Внешним DNS будет выступать шлюз по умолчанию.
Конфигурацию будем производить средствами Powershell.
Проверим текущие настройки серверов пересылки выполнив следующий командлент:
```powershell=
Get-DnsServerForwarder
```
Результат:

Установим сервер пересылки:
```powershell=
Set-DnsServerForwarder -IPAddress "192.168.1.1" -PassThru
```
Результат:

### 4.4.4 Создание зоны обратного просмотра.
Для корректной работы DNS необходимо настроить обратную зону для нашей сети 192.168.1.0/24.
Сначала проверим текущие обратные зоны:
```powershell=
Get-DnsServerZone
```
Зоны для нашей сети нет:

Создадим зону следующим командлетом и установим область репликации зоны "Домен", разрешим только безопасные динамические обновления:
```powershell=
Add-DnsServerPrimaryZone -NetworkId "192.168.1.0/24" -ReplicationScope Domain -DynamicUpdate Secure
```
Обратная зона для нашей сети успешно создана:

Остальные настройки, как и управление будем производить с административной машины, которая по совместительству является нашим клиентом.
---
## 4.5 Конфигурация клиента Windows 10
### 4.5.1 Ввод машины в домен
Для ввода нашей машины pc будем использовать следующий командлет
```powershell=
Add-Computer -DomainName pt.local -DomainCredential PT\Administrator -Restart -Force
```
Результат:


Машина успешна введена в домен.
### 4.5.2 Настройка административного места
Машину pc будем использовать как рабочее место администратора.
Установим RSAT. Посмотрим доступные модули:
```powershell=
Get-WindowsCapability -Name RSAT* -Online | Format-Table
```
Результат:

Машина административная, раздумывать не будем, поставим все:
```powershell=
Get-WindowsCapability -Name RSAT* -Online | Add-WindowsCapability –Online
```
Результат:


---
## 4.6. Административные задачи
### 4.6.1 Массовое создание пользователей Active Directory
Создадим 20 пользователей, пользователи будут называться user1..user20.
Каждому пользователю установим 8-значный пароль, в котором будут латинские символы верхнего и нижнего регистром, а также цифры, спец. символов не будет. Значения логина/пароля выгрузим в файл.
Выполним это следующим скриптом:
```powershell=
# для удобства создадим функцию генерации пароля
Function New-Password ([Parameter(Mandatory=$true)][int]$Lenght){
# воспользуемся методом GeneratePassword из System.Web
Add-Type -AssemblyName System.Web
# установим флаг проверки качества пароля
$check = $false
# бегаем в цикле
do {
# генерируем пароль
$password = [System.Web.Security.Membership]::GeneratePassword($Lenght,0)
# проверяем его на соответствие требованиям
if ( ($password -cmatch "[A-Z\p{Lu}\s]") -and ($password -cmatch "[a-z\p{Ll}\s]") -and ($password -match "[\d]") -and ($password -notmatch "[^\w]") -and ($password -notmatch "_")){
# пароль удовлетворяет требованиям
$check=$True
}
} while ($check -eq $false) # бегаем в цикле пока не найдем хороший пароль
# вернем пароль
return $password
}
# создадим OU куда будем класть пользователей
New-ADOrganizationalUnit -Name Accounts
New-ADOrganizationalUnit -Name TestUsers -Path 'OU=Accounts,dc=pt,dc=local'
# в этом подразделении будем создавать пользователей
$userPath = 'OU=TestUsers,OU=Accounts,dc=pt,dc=local'
# количество создаваемых пользователей
$userCount = 20
# словарь для хранения логинов\паролей
$users = [ordered]@{}
# цикл создания польлзователей
1..$userCount | ForEach-Object {
# соберем имя user1, user2, ...
$name = "user"+$_
# сгенерируем для него пароль длиной 8 символов
$password = New-Password -Lenght 8
# соберем UPN укажем суффикс домена
$UPN= $name+"@pt.local"
# создадим пользоватея с указанными параметрами
New-ADuser -Name $name `
-GivenName $name `
-UserPrincipalName $UPN `
-Path $userPath `
-AccountPassword (ConvertTo-SecureString $password -AsPlainText -Force) `
-Enabled $true
# запишем пользователя и его пароль в файл
$users[$name] = $password
}
# выгрузим словарь в файл в формате csv
$users.GetEnumerator() `
| Select-Object -Property Key,Value `
| ConvertTo-Csv -NoTypeInformation -Delimiter "," `
| Out-File \users.csv
```
Результат:


Посмотрим созданных пользователей:
```powershell=
Get-ADUser -Filter *
```
Результат:


### 4.6.2 Получение логинов и хэшей паролей из базы NTDS
В Powershell_ISE создадим вкладку удаленного подключения к серверу. И подключимся к контроллеру домена dc:

Выгрузим базу Active Directory используя утилиту ntdsutil:
```cmd=
ntdsutil "Activate Instance ntds" "ifm" "create full C:\Temp" q q
```
Результат:

Скопируем выгруженные данные с контроллера домена на нашу машину:

Для получения хэшей воспользуемся модулем DSInternals
https://github.com/MichaelGrafnetter/DSInternals
Установим Powershell модуль^
```powershell=
Install-Module -Name DSInternals
```
Результат:

Ослабим ограничения использования скриптов Powershell:
```powershell=
Set-ExecutionPolicy -ExecutionPolicy Bypass
```
Результат:

Следующим скриптом получим имена, сиды и хэши пользователей:
```powershell=
# импортируем модуль DSInternals
Import-Module DSInternals
# укажем ключ реестра
$bootKey = Get-BootKey -SystemHivePath 'C:\AD\registry\SYSTEM'
# загрузим базу данных учетных записей
$DB = Get-ADDBAccount -All -DBPath "C:\AD\Active Directory\ntds.dit" -BootKey $bootKey
# пробежимся по базе
$DB | ForEach-Object{
# создадим для каждай учетки, объект, куда положим нужные нам данные.
[PSCustomObject]@{
Name = $_.SamAccountName
Sid = $_.Sid
# конвертируем хэши из байт массива в нормальный вид
NTHash = ([System.BitConverter]::ToString($_.NTHash) -replace '-','').ToLower()
}
# выгрузим данные в файл в формате csv
} | ConvertTo-Csv -NoTypeInformation -Delimiter "," | Out-File C:\AD\dumpedUsers.csv
```
Результат:

Выполним еще раз без выгрузки в файл

### 4.6.3 Настройка областей выдачи адресовм на DHCP сервере
Необходимо сконфигурировать область выдачи адресов с 192.168.1.226 по 192.168.1.253. Конфигурировать будем средсвами Powershell.
Продолжаем использовать удаленное подключение к dc.
Просмотрим текущие области:
```powershell=
Get-DhcpServerv4Scope
```
Сконфигурированных областей нет:

Создадим область с именем "devicesPool":
```powershell=
Add-DhcpServerv4Scope -Name "devicesPool" -StartRange 192.168.1.226 -EndRange 192.168.1.253 -SubnetMask 255.255.255.0 -LeaseDuration 8.00:00:00 -State Active
```
Область создана:

Установим для нашей области значения роутера, домена и DNS:
```powershell=
Set-DhcpServerv4OptionValue -ScopeId 192.168.1.0 -Router 192.168.1.1 -DnsDomain "pt.local" -DnsServer 192.168.1.225
```
Опции установлены:

### 4.6.4 Создание управляемой сервисной учетной записи и запуск от ее имени службы DHCP сервера
Для начала создадим корневой ключ KDC:
```powershell=
Add-KdsRootKey –EffectiveImmediately
```
Результат:

Проверим:
```powershell=
Get-KdsRootKey
Test-KdsRootKey -KeyId (Get-KdsRootKey).KeyId
```
Результат:

Создадим MSA, ограничим использование одной машиной:
```powershell=
New-ADServiceAccount -Name msaDHCPserver –RestrictToSingleComputer
```
MSA с имененм msaDHCPserver создана:

Привяжем MSA к серверу DHCP, он же dc:
```powershell=
$Identity = Get-ADComputer -Identity dc
Add-ADComputerServiceAccount -Identity $identity -ServiceAccount msaDHCPserver
```
Результат:

Проверим:
```powershell=
Get-ADServiceAccount msaDHCPserver
```
Результат:

Установим MSA на сервер:
```powershell=
Install-ADServiceAccount -Identity msaDHCPserver
```

Запустим сервер DHCP от имени MSA:
```powershell=
# получим службу DHCP server
$service = Get-WmiObject win32_service | where {$_.name -eq "DHCPServer"}
# получим MSA
$msa = Get-ADServiceAccount -Identity msaDHCPserver
# сформируем имя с учетом домена
$name = "PT\{0}" -f $msa.SamAccountName
# изменим настройки запуска службы, установим учетную запись, от имени которой служба стартует
$service.change($null,$null,$null,$null,$null,$null,$name,$null,$null,$null,$null)
# остановим службу
$service.StopService()
# запустим службу
$service.StartService()
# проверим результат
Get-WmiObject win32_service | where {$_.name -eq "DHCPServer"} | Select-Object -Property *
```
Результат, поле StartName отражает учетную запись от которой стартует служба:

### 4.6.5 Экспорт конфигурации DHCP сервера
Экспортируем конфигурацию DHCP сервера:
```powershell=
# полная
Export-DhcpServer -File \dhcpServerConfig.xml
# скоупа
Export-DhcpServer -ScopeId 192.168.1.0 -File \dhcpServerScopeConfig.xml
# всего лизинга
Export-DhcpServer -Leases -File \dhcpServerLeasesConfig.xml
# лизинга скоупа
Export-DhcpServer -ScopeId 192.168.1.0 -Leases -File \dhcpServerScopeLeasesConfig.xml
```
Результат:


### 4.6.6 Создание принтера.
Установим автоматический запуск спулера и запустим его:
```powershell=
# посмотрим состояние службы спулера
Get-Service -Name Spooler
# установим автозапуск
Get-Service -Name Spooler | Set-Service -StartupType Automatic
# стартуем
Get-Service -Name Spooler | Start-Service
# проверим
Get-Service -Name Spooler
```
Результат:

Проверим существующие принтеры
```powershell=
Get-Printer
```

Создадим принтер
```powershell=
# имя
$Name = "MainPrinter"
# адрес
$Address = "192.168.1.246"
# сетевое имя
$Share = "MainSharedPrinter"
# драйвер
$Driver = "Microsoft XPS Document Writer v4"
# просто комментарий
$Comment = "This main printer"
# где находится
$Location = "My home"
# добавим принтерпорт, укажем тип SNMP и комьюнити паблик
Add-PrinterPort -Name $Address -PrinterHostAddress $Address -SNMP 1 -SNMPCommunity 'public'
# добавим принтер
Add-Printer -Name $Name -DriverName $Driver -PortName $Address -Comment $Comment -Location $Location
# расшарим принтер
Set-Printer -Name $Name -Shared $True -Published $True -ShareName $Share
```
Результат:

Посмотрим на принтеры:
```powershell=
Get-Printer
```
Результат:

### 4.6.7 Распространение принтера через GPO.
Распространим принтер на машины домене через GPO.
Будем использовать функционал GPP.
Создадим gpo прилинкуем к домену:

В GPP области компьютера созадим принтер.
Укажем его свойства. Режим оставим обновления:

Принтер добавлен:

Отключим конфигурацию пользователя:

GPO готово:

### 4.6.8 Экспорт конфигурации принтера.
Скрипт выгрузки конфигурации принтеров:
```powershell=
# получим все принтеры
$printers = Get-Printer *
# пробежимся по ним и запросим конфигурации, выберем все поля
$printers | ForEach-Object {Get-PrintConfiguration -PrinterName $_.name | Select-Object -Property *}
# экспортируем конфигурации в файл в формате xml
$printers | Export-Clixml \printersConfig.xml
```
Результат:


---
## 4.7 Административные задачи на клиентской машине
### 4.7.1 Настройка динамической адресации
Проверим текущие настройки
```powershell=
Get-NetIPConfiguration -InterfaceIndex (Get-NetAdapter).InterfaceIndex
```
Результат

Установим динамическое получение адресов:
```powersell=
# сбросим настройки dns
Set-DnsClientServerAddress -InterfaceIndex (Get-NetAdapter).InterfaceIndex -ResetServerAddresses
# переключим на динамическое получение сетевых настроек
Set-NetIpInterface -InterfaceIndex (Get-NetAdapter).InterfaceIndex -Dhcp Enabled
```
Результат:

### 4.7.2 Установка ПО Notepad++
Установим ПО Notepad++ используя winget:
```cmd=
winget install notepad++
```
ПО установлено:

### 4.7.3 Определение установки ПО Notepad++
Следующим скриптом определим установленное ПО:
```powershell=
# какое ПО будем искать
$searchProgram = "Notepad++"
# машина 64 разрядная, поэтому искать будем и в Wow6432Node, на случай 32 разрядной установки.
$programsPath = @(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
# побежим по свойствам ключей обоих путей
$foundPrograms = Get-ItemProperty $programsPath `
# ищем интересующее нас выводимое имя программы, используем неполное совпадение
| Where-Object {$_.DisplayName -like "*"+$searchProgram+"*"} `
# для каждого найденного приложение создаем объект, куда помещаем интересующую нас информацию
| ForEach-Object {
[PSCustomObject]@{
Vendor = $_.Publisher
Name = $_.DisplayName
Version = $_.DisplayVersion
Path = $_.UninstallString.Replace("uninstall.exe","")
}
}
# выводим найденные программы. могут быть несколько версий в зависимости например от разрядности
$foundPrograms
```
Результат:

### 4.7.4 Вывод скриптом "Remaining Windows rearm count" (Оставшееся число возвращений к исходному состоянию активаций Windows)
Будем использовать вывод выстроенного скрипта slmgr.vbs и распарсим его:
```powershell=
$rearmCount = (cscript C:\Windows\System32\slmgr.vbs -dlv).split([Environment]::NewLine)[-5].split(":")[1].trim()
$rearmCount
```
Результат:

Вывод в графике:

### 4.7.5 Создание локального пользователя.
Создадим локльного пользователя. Будем использовать ранее написанную функцию генерации пароля:
```powershell=
# функции подробно описывалась ранее
Function New-Password ([Parameter(Mandatory=$true)][int]$Lenght){
Add-Type -AssemblyName System.Web
$check = $false
do {
$password= [System.Web.Security.Membership]::GeneratePassword($Lenght,0)
If ( ($password -cmatch "[A-Z\p{Lu}\s]") -and ($password -cmatch "[a-z\p{Ll}\s]") -and ($password -match "[\d]") -and ($password -notmatch "[^\w]") -and ($password -notmatch "_")){
$check=$True
}
} While ($check -eq $false)
return $password
}
# укажем имя пользователя
$user = "user1"
# его описание
$description = "New user "+$user
# сгенерируем пароль
$password = New-Password -Lenght 8
# создадим пользователя с выбранными свойствами
New-LocalUser $user -Password (ConvertTo-SecureString $password -AsPlainText -Force) -FullName $user -Description $Description
# сохраним пользователя и пароль в хэштаблицу и выведем на экран
@{$user = $Password}.GetEnumerator() | Select-Object -Property Key, Value
```

### 4.7.6 Добавление членов в локальную группу безопасности
Добавим членов в локальную группу безопасности "Администраторы":
```powershell=
# добавим локального пользователя user1 в группу Администраторы
Add-LocalGroupMember -Group "Администраторы" -Member "user1"
# добавим доменного пользователя user2 в группу Администраторы
Add-LocalGroupMember -Group "Администраторы" -Member "PT\user2"
# добавим доменную группу Domain Admins в группу Администраторы
Add-LocalGroupMember -Group "Администраторы" -Member "PT\Domain Admins"
```
Результат:

### 4.7.7 Получение членов локальной группы безопасности
Получим членов локальной группы безопасности "Администраторы"
```powershell=
# получим имя машины где запущен скрипт
$pcName = $env:COMPUTERNAME
# получаем членов указанной локальной группы
$locaGroutMember = Get-LocalGroupMember -Group "Администраторы" `
| Select-Object -Property * `
# бежим по ним
| ForEach-Object {
# устанавливаем флаг группы в false
$isGroup = $false
# устанавливаем флаг домена в false
$isDomain = $false
# проверяем доменный или локальный член, устанавливаем флаг
if($_.PrincipalSource -eq "ActiveDirectory"){ $isDomain = $true }
# проверяем группа или пользователь , устанавливаем флаг
if($_.ObjectClass -eq "Группа"){ $isGroup = $true }
# собираем необходимые нам данные в объект
[PSCustomObject]@{
# имя машины
ComputerName = $pcName
# имя члена без указания домена
Name = $_.name.split("\")[1]
# SID
SID = $_.SID
# флаг группы
isGroup = $isGroup
# флаг домена
isDomain = $isDomain
}
}
# выводим информацию на экран
$locaGroutMember | Format-Table
```
Результат:

### 4.7.8 Получение данных сетевой конфигурации и конфигурации принтера
Выведем сетевую конфигурации и принтерную.
```powershell=
Write-Host "=====================This network card configuration====================="
# сетевая
Get-NetIPConfiguration -All | Select-Object -Property *
Write-Host "========================This printer configuration======================="
# принтерная
Get-PrintConfiguration -PrinterName $(Get-Printer)[1].Name | Select-Object -Property *
```
Результат:


На этом данная работа завершена.