Главная

Sunday, 1 August 2021

Анализ логов RDP подключений.


Всем привет.

Время от времени администратору необходимо проводить аудит логов RDP подключений в Windows. Как правило, это может пригодиться при расследовании различных инцидентов на терминальных / RDS серверах Windows, когда от системного администратора требуется предоставить информацию: какие пользователи входили на RDS сервер, когда авторизовался и завершил сеанс конкретный пользователь, с какого устройства (имя или IP адрес) подключался RDP-пользователь, и т.п. 

Используем Powershell. Самый простой запрос:

Get-EventLog security -after (Get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 4624 -and $_.Message -match 'Тип входа:\s+(10)\s'} |  select -First  5 | Select $_.Message 

И более развернутый вариант. Обращаю ваше внимание на различие запросов по языку интерфейса.

# English версия

Get-EventLog -LogName Security -after (Get-date -hour 0 -minute 0 -second 0)| ?{(4624,4778) -contains $_.EventID -and $_.Message -match 'Тип входа:\s+(10)\s'}| %{

(new-object -Type PSObject -Property @{

TimeGenerated = $_.TimeGenerated

ClientIP = $_.Message -replace '(?smi).*Source Network Address:\s+([^\s]+)\s+.*','$1'

UserName = $_.Message -replace '(?smi).*Account Name:\s+([^\s]+)\s+.*','$1'

UserDomain = $_.Message -replace '(?smi).*Account Domain:\s+([^\s]+)\s+.*','$1'

LogonType = $_.Message -replace '(?smi).*Logon Type:\s+([^\s]+)\s+.*','$1'

})

} | sort TimeGenerated -Descending | Select TimeGenerated, ClientIP `

, @{N='Username';E={'{0}\{1}' -f $_.UserDomain,$_.UserName}} `

, @{N='LogType';E={

switch ($_.LogonType) {

2 {'Interactive - local logon'}

3 {'Network conection to shared folder)'}

4 {'Batch'}

5 {'Service'}

7 {'Unlock (after screensaver)'}

8 {'NetworkCleartext'}

9 {'NewCredentials (local impersonation process under existing connection)'}

10 {'RDP'}

11 {'CachedInteractive'}

default {"LogType Not Recognised: $($_.LogonType)"}

}

}} | Export-Csv RDP-eng.txt  -Encoding UTF8


# Russian версия

Get-EventLog -LogName Security -after (Get-date -hour 0 -minute 0 -second 0)| ?{(4624,4778) -contains $_.EventID -and $_.Message -match ‘Тип входа:\s+(10)\s’}| %{

(new-object -Type PSObject -Property @{

TimeGenerated = $_.TimeGenerated

ClientIP = $_.Message -replace ‘(?smi).*Сетевой адрес источника:\s+([^\s]+)\s+.*’,’$1'

UserName = $_.Message -replace ‘(?smi).*Имя учетной записи:\s+([^\s]+)\s+.*’,’$1'

UserDomain = $_.Message -replace ‘(?smi).*Домен учетной записи:\s+([^\s]+)\s+.*’,’$1'

LogonType = $_.Message -replace ‘(?smi).*Тип входа:\s+([^\s]+)\s+.*’,’$1'

})

} | sort TimeGenerated | Select TimeGenerated, ClientIP `

, @{N=’Username’;E={‘{0}\{1}’ -f $_.UserDomain,$_.UserName}} `

, @{N=’LogType’;E={

switch ($_.LogonType) {

2 {‘Interactive — local logon’}

3 {‘Network conection to shared folder)’}

4 {‘Batch’}

5 {‘Service’}

7 {‘Unlock (after screensaver)’}

8 {‘NetworkCleartext’}

9 {‘NewCredentials (local impersonation process under existing connection)’}

10 {‘RDP’}

11 {‘CachedInteractive’}

default {«LogType Not Recognised: $($_.LogonType)»}

}

}} | Export-Csv RDP-rus.txt  -Encoding UTF8


Если вас не интересует сама авторизация RDP-подключения то не обязательно анализировать журнал Security. Есть более простой способ. Открываем журнал Diagnostics -> Event Viewer -> Applications and Services Logs -> Microsoft -> Windows -> TerminalServices-RemoteConnectionManager->Operational и смотрим события с номером Event Id 1149. Для удобства можно отфильтровать журнал по событию с этим номером.

#------- Connection by RDP ------------------

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

$servername = "sccm01.forza.com"

$username = "Cooladmin"

 [xml]$equery = @"

<QueryList>

   <Query Id="0" Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">

   <Select Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">*[System[(EventID=1149)]] and *[UserData[EventXML[(Param1='$username')]]]</Select>

   </Query>

</QueryList>

"@

 

Get-WinEvent -ComputerName $servername -FilterXML $equery |

   Select-Object TimeCreated, @{Name="User";Expression={$_.Properties[0].Value}},

                              @{Name="Domain";Expression={$_.Properties[1].Value}},

                              @{Name="Source Network Address";Expression={$_.Properties[2].Value}},MachineName | Out-GridView



#--------- Connections thru RD Gateway 1 ----------------

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

$servername = "sccm01.forza.com"

$username = "forza.com\Cooladmin"

 [xml]$equery = @"

<QueryList>

   <Query Id="0" Path="Microsoft-Windows-TerminalServices-Gateway/Operational">

   <Select Path="Microsoft-Windows-TerminalServices-Gateway/Operational">*[System[(EventID=302)]] and *[UserData[EventInfo[(Username='$username')]]]</Select>

   </Query>

</QueryList>

"@

 

Get-WinEvent -ComputerName $servername -FilterXML $equery |

   Select-Object TimeCreated, @{Name="User";Expression={$_.Properties[0].Value}},

                              @{Name="Source Network Address";Expression={$_.Properties[1].Value}},

                              @{Name="Resource";Expression={$_.Properties[3].Value}},MachineName | Out-GridView

 

#--------- Connections thru RD Gateway 2 ----------------

Тоже самое только имя пользователя задается в формате RegEx для поиска по шаблону. Этот вариант будет работать очень медленно! К сожалению, Windows не поддерживает поиск по шаблону в XPath для значений.

$servername = "sccm01.forza.com"

$username = "Cooladmin"

[xml]$equery = @"

<QueryList>

   <Query Id="0" Path="Microsoft-Windows-TerminalServices-Gateway/Operational">

   <Select Path="Microsoft-Windows-TerminalServices-Gateway/Operational">*[System[(EventID=302)]]</Select>

   </Query>

</QueryList>

"@

Get-WinEvent -ComputerName $servername -FilterXML $equery |

   Select-Object TimeCreated, @{Name="User";Expression={$_.Properties[0].Value}},

                              @{Name="Source Network Address";Expression={$_.Properties[1].Value}},

                              @{Name="Resource";Expression={$_.Properties[3].Value}},MachineName |

              Where-Object {$_.User -match $username} | Out-GridView


Еще такой вариант - возможно вам понадобиться провести аудит активных RDP-сессий на ваших серверах. В этом случае вам поможет следующий скрипт, список исследуемых серверов помещаете в файл servers.txt, либо получаете прямым запросом из AD.

$Today = Get-Date

$SessionLis t = "`n`nRDP Session List - " + $Today + "`n`n"

$CurrentSN = 0

#$Servers = Get-ADComputer -filter {OperatingSystem -like "*server*"}

#$Servers = Import-Csv -Encoding UTF8 -path "D:\PS\servers.txt" -Delimiter "," 

$Servers = Get-ADComputer -filter * -searchbase "OU=Infrastructure Servers,DC=forza,DC=com"

$NumberOfServers = $Servers.Count


ForEach ($Server in $Servers) {

    $ServerName = $Server.Name

    Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN/$NumberOfServers)*100)

    try

    {

        $queryResults = (qwinsta /server:$ServerName | foreach { (($_.trim() -replace "\s+",","))} | convertfrom-csv)

# Обращаю ваше внимание на различие запросa по языку интерфейса.

        ForEach($QueryResult in $QueryResults) {

        #    $RDPUser=$QueryResult.USERNAME

        #    $SessionType=$QueryResult.SESSIONNAME

        #    $SessionID=$QueryResult.ID

        #    $ReturnedCurrentState=$QueryResult.State

             $RDPUser = $QueryResult.ПОЛЬЗОВАТЕЛЬ

             $SessionType = $QueryResult.СЕАНС

             $SessionID = $QueryResult.ID

             $ReturnedCurrentState = $QueryResult.СТАТУС

            If($ReturnedCurrentState -eq $null){ $CurrentState="Disconnected" } Else { $CurrentState="Active" }

            If (($RDPUser -ne $NULL) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {

                $SessionList=$SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " as " + $SessionType + ", session id "+ $SessionID + " is " + $CurrentState

            }

        }

    }

    catch

    {

        $SessionList=$SessionList + "`n Unable to query " + $ServerName 

        write-host "Unable to query $ServerName!" -foregroundcolor Red

    }

    $CurrentSN++

}

$SessionList + "`n`n"

На этом все.

No comments:

Post a Comment

А что вы думаете по этому поводу?