当前位置:首页 > 未分类 > 密码重置盘研究后续 - 更多细节 & 伪造尝试

密码重置盘研究后续 - 更多细节 & 伪造尝试

admin1年前 (2020-10-12)未分类171

密码重置盘研究后续 - 更多细节 & 伪造尝试 

密码重置盘研究后续 - 更多细节 & 伪造尝试
本文是研究报告“创建密码重置盘的时候,系统都做了些什么”的后续。
0. 访问“本地计算机”证书存储区的方式
certmgr.msc所能够访问的证书存储区归属于当前登录的用户,而我们所要研究的那张自签名证书不在这些存储区里。
在Windows 7及更高版本的系统中,可以使用certlm.msc访问到“本地计算机”证书存储区。而在Windows XP中,步骤稍微复杂。
启动管理控制台mmc.exe。
选择“文件”-“添加/删除管理单元”菜单。
在打开的窗口中点击“添加”按钮。此时会弹出一个列表。在列表中选择“证书”,点击“添加”。
在“该管理单元将始终为下列账户管理证书”的选项中,选择“计算机账户”。
一直“下一步”,返回到刚才的列表。关闭这个列表。
点击“确定”。此时的控制台窗口中将会出现“证书(本地计算机)”一项。其使用方法与certmgr.msc相同。
1. 能否从系统中清除密码重置盘的痕迹?
只要用户制作过密码重置盘,在登录密码输入错误的时候,就会出现使用密码重置盘的提示。尤其是在Windows XP上,弹出的提示框特别显眼。那么,既然系统提供了创建密码重置盘的入口,那有没有移除密码重置盘的方式呢?
实践表明,只要删除了注册表数据和/或证书,登录密码输入错误的时候就不会再提示使用密码重置盘。可以推测,系统是通过查找用户SID对应的数据,再通过数据中的证书SHA1查找证书来判断其有没有可用的密码重置盘的。逆向分析证明了这一点,调用链如下:

msgina!HandleFailedLogon(登录界面,密码错误时触发)
  msgina!PRQueryStatus(RPC)
    dpapisrv!s_SSRecoverQueryStatus
      dpapisrv!SPRecoverQueryStatus
        dpapisrv!RecoverFindRecoveryPublic
          (各种操作)

最后的RecoverFindRecoveryPublic函数会先调用RecoveryRetrieveSupplementalCredential获取注册表数据,再根据其中存储的证书SHA1查找对应证书。和假说不同的是,找到证书之后又使用LogonCredVerifySignature对注册表数据进行了签名检查。并不是很清楚全零的签名(见下)为什么可以通过检查。
2. 密码重置盘与密码间的关系有多密切?
之前的研究结束后,翻阅微软文档时惊奇地发现

如果再次忘记了密码,可以使用同一密码重置盘。无需创建新的密码重置盘。
—— 更改或重置 Windows 密码 - Windows Help

这使我怀疑系统保存用户密码的过程是否是必要的。
经过实验,使用密码重置盘后,注册表中保存的密码与签名也会同步变化。但是:
如果手动修改密码(没有修改注册表数据),事后密码重置盘仍然可用;
如果手动修改注册表数据(来源是之前的备份,没有修改密码),事后密码重置盘也仍然可用。
也就是说,系统保存的用户密码并不是修改密码的必要条件。为了获知系统存储用户密码的目的,接下来对上次没有逆向完的接口进行分析。
重置密码的过程
接上次对dpapisrv.dll中RPC接口的分析,重置密码的调用链如下:

keymgr!PRRecoverPassword
  s_SSRecoverPassword
    DecryptRecoveryPassword(获取、解密并判断注册表中的用户密码)
      (各类细化的操作)
    ResetLocalUserPassword
      samsrv!SamIChangePasswordForeignUser(API,修改用户密码)

整条调用链中最神奇的就是DecryptRecoveryPassword函数。它拿着注册表数据,最终使用API BCryptDecrypt解密得到明文密码,然后……就没有然后了。判断能否进行密码重置的唯一条件是,提供的私钥能够解密注册表数据,而对解密得到的数据没有进行任何校验。而且好像这个函数对注册表数据中的签名也没有进行校验……不过这是后话,需要进一步分析。
明文密码之后被传入了ResetLocalUserPassword函数。然而,真正用来修改密码的API并没有使用这个参数。(和我的预期一致;系统自己修改自己的密码还需要校验,岂不是自己骗自己?)使用到它的只有来自于lsasrv.dll的一个接口的函数,跟踪接口编号发现是API lsasrv!LsaINotifyPasswordChanged,与修改密码无关。
至此,一个事实也被确定了下来:注册表中保存用户密码没有任何实际意义。非要说有的话,就是增加了一个信息泄露的攻击面吧……
签名的生成过程
接上次的分析,生成签名的部分调用链如下:

...
  EncryptRecoveryPassword
    LogonCredGenerateSignature
      LogonCredGenerateSignatureKey
        ...(没勇气看下去了)

这个先放放。真的太复杂了。大概瞟了几眼,发现签名中包含用户的二进制格式SID(但Windows XP的数据中好像没有),而且签名与用户密码有关(FMyPrimitiveSHA函数)。
上面逆向s_SSRecoverQueryStatus方法的时候,注意到在PDB中,这个签名的结构是有名称的,为_CRED_SIGNATURE,但是没有定义,网上也找不到文档。
2020-10 更新:最近的Windows XP源码泄露事件给了我们一个对相关功能进行源码审计的机会。上文的_CRED_SIGNATURE可以在泄露的源码中找到:
XPSP1\NT\ds\security\cryptoapi\secstor\dpapisvc\session.cpp:

#define SIGNATURE_SALT_SIZE (16)
#define CRED_SIGNATURE_VERSION 1
 
typedef struct _CRED_SIGNATURE
{
    DWORD dwVersion;
    GUID  CredentialID;
    DWORD cIterations;
    BYTE  Salt[SIGNATURE_SALT_SIZE];
    DWORD cbSid;
    DWORD cbSignature;
} CRED_SIGNATURE, *PCRED_SIGNATURE;

本研究报告中提及的其他技术细节也被泄露的源码证实了。相关文件列举如下:
XPSP1\NT\ds\security\base\keymgr\wizard.cpp
XPSP1\NT\ds\security\cryptoapi\common\dpapi\passrec.cpp
XPSP1\NT\ds\security\cryptoapi\common\dpapi\pasrec.idl
XPSP1\NT\ds\security\cryptoapi\secstor\dpapisvc\recovery.cpp
XPSP1\NT\ds\security\cryptoapi\secstor\dpapisvc\session.cpp
3. 我有一个大胆的想法
一顿分析下来,我得出的结论就是:微软对这个功能真的不上心!加密保存却没用到的密码、生成了却打酱油的签名……到处都是形同虚设的设计。那么,既然各种验证机制都没有起到应有的作用,密码重置盘这个机制能否成为新的攻击面?
能否伪造/无效化签名?
直接拿提取的注册表数据开刀,把签名部分整体抹零处理,再导入回注册表。结果不出所料:密码重置盘仍然正常工作。有趣的是,手动修改过签名之后再重置密码,注册表数据便不再与用户密码同步了,签名也维持着全零状态。
能否伪造证书/公私钥对?
测试步骤有点多:
使用OpenSSL生成一个2048位的私钥:openssl genrsa -out priv.pem 2048
再把各个参数打印出来:openssl rsa -in priv.pem -text
由这些参数制作一个userkey.psw(注意字节序,以及上述命令的输出有时有前导零的问题),备用。
由刚才生成的私钥生成一张自签名证书:openssl req -x509 -key priv.pem -out cert.pem。最后还可以加一个-days 365参数指定证书有效时长。
再把生成的证书转换为Windows下使用的格式:openssl x509 -in cert.pem -outform DER -out cert.cer
打开这张证书,把它的SHA1值填入注册表数据。
随便准备一点数据存入dec.bin,用来作为“用户的密码”。
再用一次OpenSSL,加密数据:openssl rsautl -encrypt -certin -inkey cert.pem -in dec.bin -out enc.bin。把得到的数据填入注册表。
至于签名,和上面一样置零就好。
导入证书和注册表,安放好userkey.psw,见证奇迹。
嗯,见证奇迹失败,提示“重置磁盘无效”。错误码是0x80090005 NTE_BAD_DATA,代表着是解密时出了问题。又一次进入了漫长的逆向工程和登陆界面调试过程。
P.S.:在不关闭Windows XP系统文件保护的前提下修改系统文件的方式:直接修改DllCache。(顿时又觉得微软的程序员们蠢萌蠢萌的)
P.P.S.:在Windows XP上,LPC端口protected_storage的另一端在lsasrv.dll,而不是dpapisrv.dll中,但接口的方法名没有变。
小插曲:手动启动重置向导的正确方式
跑调试的过程中发现,使用rundll32手动启动的密码重置向导,无论是不是在登录画面启动,都会在重置密码的一步报错,进行不下去。调试发现错误码及其喜庆:0x80008888,继续深挖,是一个存储用户名的全局变量没有初始化,但是不知道原因。无奈,跑去分析keymgr.dll的入口点。

事先分析过进程,得知创建向导是用rundll32启动的没错。发现入口中使用了一个GetNames函数,而它的作用就是初始化各个全局变量,包括当前用户的用户名。回过头来看重置向导,在登录界面上由msgina.dll直接调用,用户名是使用参数传递进来的。加上用户名做rundll32的命令行参数(PRShowRestoreFromMsginaW和PRShowRestoreWizardExW是同一个函数),问题解决。
另外,在导出表中还发现了PRShowSaveFromMsginaW函数。能在登录界面上创建密码重置盘?
在msgina.dll中查找调用链外加实验,发现可能的这种启动创建向导的路径为:
用户登录时修改密码(“用户下次登录时需更改密码”标记)
用户登录后手动修改密码
算了,没用。不过这意味着这个入口可以直接调用,也就是为指定用户启动创建向导。上一篇文章中的命令行就来源于此。
回到正题
在把自己的Windows XP虚拟机调试死机过N次后,我决定放弃,转而去翻文档。Windows XP下,执行RSA加密的函数是更加原始的CryptEncrypt。文档一语点醒梦中人:

The ciphertext is returned in little-endian format.
—— CryptEncrypt function (wincrypt.h)

好的。才想起来存进注册表的数据忘记了字节序颠倒。补上这一步操作再导入注册表,实验成功。
到现在为止,我们已经可以通过自行生成并导入一个用户的密码重置盘数据,修改任意账户的密码。所需要的仅仅是用户的SID(wmic useraccount where name='%username%' get sid),和……
头疼的权限
理想很丰满,但如果要从头伪造一份密码重置盘的数据,需要异常高的权限:
将证书导入“本地计算机”证书存储区:管理员权限
直接写入注册表数据:SYSTEM权限
另一个方案是去手动调用RPC接口,毕竟提供接口的服务是运行在lsass.exe进程中,具有SYSTEM权限。但负责导入数据的s_SSRecoverImportRecoveryKey函数,参数之一是用户当前的密码,而且会进行校验(VerifyCredentials函数)。

哎,又是一个伪漏洞。研究就先到这里了。

转载自:http://www.cnhonkerarmy.com/thread-252804-1-1.html

    扫描二维码推送至手机访问。

    版权声明:本文由勤奋的思远发布,如需转载请注明出处。

    如果文章对你有帮助的话就赞助一下吧https://lsybk.xyz/donation.html

    本文链接:https://lsybk.xyz/post/PRD2.html

    标签: 系统安全
    分享给朋友:

    相关文章

    Linux 的 18 个命令,记得全部搂一遍!

    Linux 的 18 个命令,记得全部搂一遍!

    1、sl 命令你会看到一辆火车从屏幕右边开往左边……安装$ sudo apt-get install sl运行$ sl命令有 -a l F e 几个选...

    【C++入门教程(5)】循环结构(1)for

    【C++入门教程(5)】循环结构(1)for

    emm今天有点时间,就继续发一下这个C++系列教程的文章----------------------------------------------------------------for循环for...

    赞助平台的建成步骤

    赞助平台的建成步骤

    前言大家看到这篇文章的人应该都知道,现在上线了这个赞助平台,简称“要饭网”那这个是如何建成的呢?幸好作业不多,我弄了一晚上其实之前搞过一个,但是跟这个版本不一样,用的是爱支付接口,玩了一下,手续费太多...

    为IE下载点赞

    为IE下载点赞

    昨天为了服务器迁移搞了一天,因为浏览器看到彩虹云主机只剩一点内存了,而且压缩不了文件,搞了一整天【笑哭】结果,我用Firefox压缩时又可以了,再看显示内存,才用了一半而已压缩好了咋办呢,当然是下载备...

    sqlmap基本注入手法

    sqlmap基本注入手法

    先说说SQLmapSqlmap 是一个自动化的 SQL 注入工具,其主要功能是扫描、发现并利用给定的 Url 的 Sql 注入漏洞,目前支持 MySQL、 Oracle、 PostgreSQL、 Mi...

    SQL手注时绕waf的十一种方法

    SQL手注时绕waf的十一种方法

    带大家了解一下SQL时过waf的小方法1.大小写绕过这个大家都很熟悉,对于一些太垃圾的WAF效果显著,比如拦截了union,那就使用Union UnIoN等等绕过。2.简单编码绕过比如WAF检测关键字...

    发表评论

    访客

    看不清,换一张

    ◎欢迎参与讨论,请在这里发表您的看法和观点。