确认有没有人从网络登入 Windows 的简单方法是查询事件视图器的安全性事件,事件标识符 4624 是登入成功记录、4625 是登入失败,事件详细数据会包含登入账号、来源 IP 等信息,若发现可疑再深入追查:
(提醒:这种检查方式只能揭露用 Windows 验证试图登入主机的行为,像是远程登入、连上网络磁盘机... 等,但不包含透过木马、后门程式创建的网络连接)
不过呢,身为大内攻城狮,这种例行检查还一笔一笔点开来看成何体统?当然要土炮小工具自用才帅气。
早年我曾写过 WPF 版,不过 EXE 档分享转发较困难,这些年学会新兵器,就来翻写成 PowerShell 版吧! 使用时只需拷贝粘贴存成 ListLogonEvent.ps1 档,程序码直接摊在阳光下(也顺便请大家 Code Review),没有夹带木马或病毒的风险。在计算机上开个 【Windows PowerShell (系统管理员)】(如下图) 或 Cmder (推荐!) 即可执行,想到就健检一下,有机会提早抓出潜伏的歹咪呀,希望对提升全人类资安能有丁点贡献。
PowerShell 有个 Get-WinEvent 指令可以查询 Windows 事件,依实务经验,将所有事件记录抓回来用 PowerShell 筛选的效率很差,用 -FilterHashtable 或 -FilterXPath 查询,FilterHashtable 只支持简单的比对,XPath 语法较难懂但能实现复杂一点的查询条件,会是较好的选择。
Windows Event Log 支持的 XPath 版本只到 1.0,能用的函式少得可怜,别期望它像 SQL WHERE。如果不知从何开始,可以用事件视图器的筛选工具设好条件,再参考它产生的 XML。参考
我设了几项条件:
- EventID = 4624 (登入成功) 或 4625 (登入失败)
- 只显示特定日期之后的记录,要用 TimeCreated[timediff(@SystemTime) ⇐ 距现在的毫秒数] 这种特殊写法
- 由于我要锁定来自网络的存取,故要排除 EventData 中的 IpAddress 为 -、::1、127.0.0.1 的事件
程序码很简单,大约五十行搞定,最后将结果输出成以 Tab 分隔的 CSV:
Param (
# 查询区间之起始时间(缺省最近30天)
[DateTime]$start = (Get-Date).AddDays(-30)
)
$wp = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-Not $wp.IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
Write-Host "*** 请使用系统管理员权限执行 ***" -ForegroundColor Red
return
}
# 登入类别对照表
$LogonTypeTexts = @(
'NA','NA',
'Interactive', #2
'Network','Batch','Service','NA','Unlock','NetworkClearText',
'NewCredentials','RemoteInteractive','CachedInteractive'
)
# 计算起始时间距今的毫秒数
$timeDiff = (New-TimeSpan -Start $start -End (Get-Date)).TotalMilliseconds
# 限定 4624(登入成功)、4625(登入失败)
$xpath = @"
*[
System[
(EventID=4624 or EventID=4625) and
TimeCreated[timediff(`@SystemTime) <= $timeDiff]
] and
EventData[
Data[@Name='IpAddress'] != '-' and
Data[@Name='IpAddress'] != '::1' and
Data[@Name='IpAddress'] != '127.0.0.1'
]
]
"@
# 加上 SilentlyContinue 防止查无数据时喷错 No events were found that match the specified selection criteria.
Get-WinEvent -LogName 'Security' -FilterXPath $xpath -ErrorAction SilentlyContinue | ForEach-Object {
$xml = [xml]$_.ToXml() # 将事件记录转成 XML
$d = @{} # 创建 Hashtable 放 EventData.Data 中的客制属性
@($xml.Event.EventData.Data) | ForEach-Object {
$d[$_.name] = $_.'#text'
}
if ($_.ID -eq 4624) { $action = '登入成功' }
elseif ($_.ID -eq 4625) { $action = '登入失败' }
$logonType = ''
if ($d.LogonType -gt 1) {
$logonType = $LogonTypeTexts[$d.LogonType]
}
[PSCustomObject]@{
Action = $action;
Time = $_.TimeCreated.ToString("yyyy/MM/dd HH:mm:ss");
Id = $_.ID;
TargetAccount = "$($d.TargetDomainName)\$($d.TargetUserName)"; # 登入账号
Socket = "$($d['IpAddress']):$($d['IpPort'])"; # IP 来源
LogonType = $logonType; # 登入类别
LogonProcess = $d.LogonProcessName; # 程序名称
AuthPkgName = $d.AuthenticationPackageName; # 验证模块
}
} | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation
我仿真了从另一台机器 192.168.50.93 登入集成式验证 ASP.NET 网站 登入成功、失败及网络磁盘机失败的状况,查询结果如下:
(提醒:需使用系统管理员权限执行)
纯文本不好阅读,建议用 .\ListLoginEvents.ps1 > D:\Check.csv 存成 CSV 档再用 Excel 开启。
22 列红字是登入 IIS 失败,21 列绿字是登入 IIS 成功;蓝字是试图连上 \\My-PC\d$ 时 Windows 用当下登入账号 tony 试图自动登入失败的记录,两笔紫色是故意打错帐密产生的失败记录。
大家可以用它检查自己的 Windows,看看是否有人曾试图登入你的计算机、连上你的网络分享文件夹。
https://blog.darkthread.net/blog/ps-list-logon-events/