锁定注册表键的“乐趣”

假如说你的注册表中有一些非常重要的注册表键,你肯定不希望别人随意修改或删除它们,那你应该怎么办呢?其中一种方法是通过修改注册表键得安全描述符来防止他人修改键值 。但是攻击者可以配合内核驱动或管理员权限来轻松绕过这种防御手段 。
【锁定注册表键的“乐趣”】另一种常用的防护技术是向键名或键值中嵌入NUL字符来实现保护,但这种方法会破坏原本的注册表编辑器(使用了Win32 API),因为Win32 API使用了NUL字符作为字符串的终结符,不过这种方式也无法完全阻止攻击者 。我认为最有效的方法是编写一个使用了“注册表过滤器回调API”的内核驱动器来防止他人访问注册表键,但微软增加了运行任意内核代码的难度,所以自己开发一个内核驱动器听起来似乎不太现实 。
那我们应该怎么办?我先给大家介绍内核中一个名叫NtLockRegistryKey的API,一般的操作文档中都没有提供关于这个API的内容 。该API所用参数如下:
NTSTATUS NtLockRegistryKey(HANDLEKeyHandle);
系统调用只需要传入一个注册表的KeyHandle,将其添加到我的NtObjectManager Powershell模块之后我们就可以调用它了,下图为运行情况:
很明显,我们还没有权限去锁定这个注册表键,实际上无论你有什么权限你都没办法锁定,是不是觉得很奇怪?让我们回头看一看内核 , 看看能不能找到我们所需要的权限:
从上面这段内核代码中可以看出 , 我们需要的是在内核运行代码的权限 。如果我们要这样做的话,我完全可以直接写一个注册表过滤驱动器,但这种办法的性价比实在太低 。那内核代码中有没有可以调用锁定现有注册表键功能的函数呢?如果有的话,我们可以直接利用吗?在进行了一番搜索之后,我发现了这个名叫NtLockProductActivationKeys的调用函数 。接下来,我们一起看看一看它可以对注册表键做些什么:

锁定注册表键的“乐趣”

文章插图
上面这段代码会打开一个root键- “HKLMSystemWPA”,不过在代码中这个键名是经过混淆处理的 。接下来,它会枚举并打开任意子键,然后调用ZwLockRegistryKey 。需要注意的是,这个键在调用其他功能函数时似乎不会进行权限检测 , 所以我们也许可以从用户模式下调用它 。
不过目前为止我们还不知道锁定注册表键到底有没有用,但我们知道的是WPA注册表键下的子键是锁定的 。那我们就可以尝试利用管理员权限向WAP键下的其中一个子键写入一个值:
如上图所示,这就是我们的目的 , 虽然我们能够访问键值,但当我们尝试修改该键值的时候系统返回的是STATUS_ACCESS_DENIED 。如果你回头看看NtLockProductActivationKeys的代码,你就会发现内核并没有锁定WPA键,它只是枚举了所有的子键而已 。因此没有什么可以阻止我们在WPA键下创建一个新的子键,然后我们就可以重新运行NtLockProductActivationKeys 函数,这样我们就可以得到一个被锁定的注册表键了 。
这种锁定功能最有意思的地方就在于,它不仅可以屏蔽用户模式下的修改尝试,而且连内核模式都无法修改注册表键值 。不过目前好像没有办法解锁这些键,因为系统可没有提供ZwUnlockRegistryKey函数,我们只能进入到注册表键控制块中去解锁才行 , 但微软不鼓励这种行为,因为这种操作风险性极高 。还有一种清除锁定状态的办法就是卸载hive文件并重启系统,但实现起来也非常麻烦(涉及到设备启动过程中的NtLockProductActivationKeys内核调用),本文就不做探讨了 。
如果你想用WAP注册表键的子键来存储一些配置参数的话还是可以的,但如果你想永久保存一个锁定的注册表键,那你可以创建一个子键(符号链接),并让它指向一个你想保护的注册表键就可以了 。但是在WPA键下创建符号链接的话,那么在下一次系统启动过程中WPA就没办法保证这个符号链接不被删除了 。
总结
这是一个很有意思的功能你在注册表编辑器中只能你在注册表编辑器中只能,恶意软件可以利用这个功能来实现某些恶意目的,有的安全取证环境很可能也会涉及到这种功能 。但无论怎样,这只是一个引子而已 , 想要在真实环境下利用这个功能来实现你的某些目标,你可能还需要一番努力才行 。
本文到此结束,希望对大家有所帮助!

猜你喜欢