106 lines
3.2 KiB
PowerShell
106 lines
3.2 KiB
PowerShell
# ====== 配置区 ======
|
||
$accessToken = "d28bd09159097d9cc5793a183990927ce637bd8addafb5e4586e2687ca317039"
|
||
$secret = "SECd4bf3fb7703bd2826896deefa68d579e9945a67058ee9047ac5f8757ae800729"
|
||
|
||
$threshold = 3 # 尝试失败次数阈值
|
||
$failCache = @{} # 失败计数缓存
|
||
|
||
# ====== 钉钉发送函数 ======
|
||
function Get-Signature {
|
||
$timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
|
||
$stringToSign = "$timestamp`n$secret"
|
||
$hmac = New-Object System.Security.Cryptography.HMACSHA256
|
||
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($secret)
|
||
$hash = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($stringToSign))
|
||
$sign = [Convert]::ToBase64String($hash)
|
||
$sign = [System.Net.WebUtility]::UrlEncode($sign)
|
||
return @{ timestamp=$timestamp; sign=$sign }
|
||
}
|
||
|
||
function Send-DingTalk($msg) {
|
||
$signData = Get-Signature
|
||
$url = "https://oapi.dingtalk.com/robot/send?access_token=$accessToken×tamp=$($signData.timestamp)&sign=$($signData.sign)"
|
||
$body = @{ msgtype="text"; text=@{ content=$msg } } | ConvertTo-Json -Depth 5
|
||
Invoke-RestMethod -Uri $url -Method Post -ContentType "application/json" -Body $body
|
||
}
|
||
|
||
# ====== 封禁函数(可选) ======
|
||
function Ban-IP($ip) {
|
||
if (-not (Get-NetFirewallRule -DisplayName "RDP_Block_$ip" -ErrorAction SilentlyContinue)) {
|
||
New-NetFirewallRule -DisplayName "RDP_Block_$ip" -Direction Inbound -RemoteAddress $ip -Action Block -Protocol TCP
|
||
}
|
||
}
|
||
|
||
# ====== 查询日志 ======
|
||
$query = @"
|
||
<QueryList>
|
||
<Query Id="0" Path="Security">
|
||
<Select Path="Security">*[System[(EventID=4625)]]</Select>
|
||
</Query>
|
||
</QueryList>
|
||
"@
|
||
|
||
$events = Get-WinEvent -FilterXml $query -MaxEvents 50
|
||
|
||
foreach ($event in $events) {
|
||
|
||
# 处理 LogonType
|
||
$logonTypeRaw = $event.Properties[8].Value
|
||
$logonType = 0
|
||
|
||
if ($logonTypeRaw -match '%%(\d+)') {
|
||
$logonType = [int]$matches[1]
|
||
} else {
|
||
$logonType = [int]$logonTypeRaw
|
||
}
|
||
|
||
# 只处理远程登录类型(10、134、2304,2313)
|
||
if ($logonType -notin @(10, 134, 2304, 2313)) { continue }
|
||
|
||
$user = $event.Properties[5].Value
|
||
|
||
# 尝试多个索引获取 IP
|
||
$ip = $event.Properties[18].Value
|
||
if (-not $ip -or $ip -eq '-' -or $ip -match 'C:\\') { $ip = $event.Properties[19].Value }
|
||
if (-not $ip -or $ip -eq '-' -or $ip -match 'C:\\') { $ip = $event.Properties[20].Value }
|
||
|
||
if (-not $ip -or $ip -eq '-') { $ip = "UNKNOWN" }
|
||
|
||
# 输出日志
|
||
Write-Host "RDP Failed login: $user from $ip at $($event.TimeCreated) LogonType=$logonType"
|
||
|
||
# 累加失败次数
|
||
# 格式化时间
|
||
$time = $event.TimeCreated.ToString("yyyy-MM-dd HH:mm:ss")
|
||
|
||
Write-Host "RDP Failed login: $user from $ip at $time LogonType=$logonType"
|
||
|
||
# 累加失败次数
|
||
if ($ip -ne "UNKNOWN") {
|
||
if (-not $failCache.ContainsKey($ip)) {
|
||
$failCache[$ip] = 1
|
||
} else {
|
||
$failCache[$ip]++
|
||
}
|
||
|
||
$count = $failCache[$ip]
|
||
|
||
if ($count -ge $threshold) {
|
||
Ban-IP $ip
|
||
# 推送钉钉(加入时间)
|
||
$msg = @"
|
||
!!!RDP Broke!!!
|
||
|
||
IP: $ip
|
||
username: $user
|
||
failcounts: $count
|
||
time: $time
|
||
LogonType: $logonType
|
||
"@
|
||
|
||
# Send-DingTalk $msg
|
||
|
||
$failCache.Remove($ip)
|
||
}
|
||
}
|
||
} |