Попалась интересная задачка: генерировать пароль для RDP и выдавать его в телеграм боте.
Ну тут множество готовых решений есть, но решили сделать свое. Плюс я внес корректив в план и описал его так:
- Пользователь приходит на работу
- Открывает ТГ, проваливается в бота и запрашивает пароль (команда=имя)
- Бот смотрит на сервере файл с именем команды и возвращает содержимое
- Пользователь заходит на сервер
- На сервере срабатывает триггер и запускает скрипт
- Скрипт генерирует пароль и отправляет его на сервер бота в файл
- Пользователь пошел кушац, комп заблокировался
- Пользователь вернулся и начинает с шага 2
LogonType подробно описан здесь, а это запрос для настраиваемого просмотра событий. Мне нужно было выдернуть только подключение (в т.ч. и вход) к сеансу RDP и навесить выполнение скрипта (ниже)
<QueryList>
<Query Id='0' Path='Security'>
<Select Path='Security'>*[System[(EventID=4624)] and EventData[Data[@Name='LogonType']=10 and (Data[@Name='TargetUserName']!='SYSTEM' and Data[@Name='TargetUserName']!='Администратор')]]</Select>
</Query>
</QueryList>
А это простенький скрипт. К сожалению щелчком пальцев нельзя выдернуть имя пользователя, я решил этот вопрос так:
Param(
[string]$userName
)
$FileLog="C:\usr\reloadCred"
$date=$(Get-date -Format "dd.MM.yyyy HH:mm")
$dateEvent= $(Get-date -Format "yyyy-MM-ddTHH:mm:ss.fffZ")
function Generate-Password {
param (
[Parameter(Mandatory)]
[int] $length,
[int] $amountOfNonAlphanumeric = 1
)
Add-Type -AssemblyName 'System.Web'
return [System.Web.Security.Membership]::GeneratePassword($length, $amountOfNonAlphanumeric)
}
function GetUsernameFromEventList {
$userName=""
$query=@"
<QueryList>
<Query Id='0' Path='Security'>
<Select Path='Security'>*[System[(EventID=4624) and TimeCreated[@SystemTime<='$dateEvent']] and EventData[Data[@Name='LogonType']=10 and (Data[@Name='TargetUserName']!='SYSTEM' and Data[@Name='TargetUserName']!='Администратор')]]</Select>
</Query>
</QueryList>
"@
$result = Get-WinEvent -FilterXML $query -MaxEvents 1
if ($result.count -eq 1) {
$eventXML = ([xml]$result[0].ToXml()).Event
$userName=($eventXML.EventData.Data | Where-Object {$_.Name -eq "TargetUserName"}).'#text'
}else{
Out-File -FilePath $FileLog -InputObject $("$date Events not found") -Width 50 -Append -Force
}
return $userName
}
if (!$userName){
$userName=GetUsernameFromEventList
} else{
$check=(Get-LocalUser).Name -Contains $userName
if (!$check){
Write-host("$userName does not exist")
$userName=""
}
}
if ( $userName -ne "") {
$NewPassword=Generate-Password 10
$Secure_NewPassword = ConvertTo-SecureString $NewPassword -AsPlainText -Force
try{
Set-LocalUser -Password $Secure_NewPassword -Name $userName -ErrorAction Stop
}
catch {
Write-Host("FAIL")
exit
}
$command=$("echo '$NewPassword' >/pswd/$($userName.toLower())")
Write-Host($str)
Out-File -FilePath $FileLog -InputObject $("$date $userName $NewPassword $command") -Width 50 -Append -Force
Start-Process -FilePath "C:\Program Files (x86)\Bitvise SSH Client\sexec.exe" -ArgumentList "-profile=`"C:\USR\wms_bot.tlp`"","-cmd=`"$command`"" -Wait -RedirectStandardOutput C:\usr\reloadCred2
}
У скрипта есть косяк, он выдергивает события по времени равные или старше момента запуска, т.о. мы пытаемся избежать некорректной обработки "если два пользователя вошли с малым интервалом".
В конце скрипта идет отправка пароля на сервер при помощи настроенного профиля Bitvise с ssh ключом.
Также скрипт можно запустить вручную с указанием имени пользователя как параметр
Для лучшей работы не забываем настраивать автоотключения сеанса при простое.
Ремарка по поводу реализации, со стороны бота можно настроить api и запись в БД, но это удорожание разработки бота.
ВАЖНО
При установке на другой комп, также не в домене, выяснилось, что событие 4624 с кодом 10 регистрируется только при входе. При подключении к уже созданному сеансу регистрируется событие с кодом 7. Я пока не могу понять, почему так.
Поэтому в коде и в фильтре надо поправить:
Data[@Name='LogonType']=10
на
(Data[@Name='LogonType']=10 or Data[@Name='LogonType']=7)
Но, событие с кодом 7 может вызываться несколько раз за одно подключение, поэтому варик так себе
Комментариев нет:
Отправить комментарий