频道栏目
首页 > 安全 > 网络安全 > 正文

NT平台拨号连接密码恢复原理

2004-11-09 08:59:34      个评论      
收藏   我要投稿

Author : eyas
Email  : eyas at xfous.org
Date   : 2004-11-08


    前段时间ADSL密码忘记了,但幸好还保存在拨号连接里面,于是到网上找了些星号密码
显示工具,可惜不起作用。后来找到一种名为dialupass的工具,这家伙不负重望把密码给
我还原出来了。(用的dialupass v2.42,我的系统是windows xp)

    看起来dialupass非普通的星号密码显示工具,那它的原理是什么呢?上GOOGLE查了
一翻,没找到相关资料(可能是我用的关键字有问题)。 一生气便操起家伙(windbg)
准备把它大卸八块。郁闷的是,用windbg加载后,密码就还原不出来了,显示是星号。换替
补ollydbg上场,情况依旧。莫非这小工具有Anti-Debug功能?当时只是一丝怀疑,因为实
在不相信这样的小工具作者会花心思来保护。

    后来在用s-ice跟踪的过程中,发现有这么一个调用:

    GetProcAddress(xx, "IsDebugPresent")。
   
    晕倒,原来真的有Anti-Debug功能,好在比较简单。统计了一下,总共有5处进行了
Anti-Debug检查。
   
    情况查明了,便换回windbg来调试,在windbg里面下这么一个断点便可绕过Anti-Debug
检测:

    bp KERNEL32!IsDebuggerPresent "g poi(esp);r eax=0;g"

    花了些时间跟踪了一下,把dialupass恢复密码的流程都搞清楚了。这小程序猫腻还
挺多的,总结如下:

    1. 关键函数不直接调用,而是用LoadLibraryA和GetProcAddress来获取函数地址
后再CALL。
    2. 函数名是经过编码的,反汇编后看字符串是看不到的。
    3. 关键地方一概用花指令来迷惑你和反汇编软件。
   
    其实原理很简单,就是用rasapi32.dll里面的一些函数来获取拨号连接的一些信息,
再用 ADVAPI32!LsaRetrievePrivateData 函数来获取密码。

    根据dialupasss的原理,写了个类似的工具,源代码参见后面的x_dialupass.c。

    后来用"LsaRetrievePrivateData"和"RasDialParams"做关键字,重新在GOOGLE搜索了
一遍,找到一些类似的代码。

    参考资源[1]和[2]的是俄罗斯人公布的演示代码,没有对LsaRetrievePrivateData返回
的数据进行拆分用户名和密码。参考资源[3]是日本人公布的完整的应用程序的代码,可惜
在对LsaRetrievePrivateData返回的数据进行拆分处理时存在BUG,导致有些情况下用户名
和密码取的不正确。

   
    后来发现lsadump2 DUMP出来的数据里面包含了"LsaRetrievePrivateData"返回的数
据。lsadump2的原理大致如下:

    1)插入一线程到lsass.exe进程
    2)打开LSA Policy database
    3)从注册表"HKLMSECURITYPolicySecrets"中枚举子键
    4)LsarOpenSecret
    5)LsarQuerySecret

    进一步跟踪后发现,其实ADVAPI32!LsaRetrievePrivateData是通过NdrClientCall2
发送RPC调用到lsass.exe进程,lsass.exe里面再调用LsarOpenSecret、LsarQuerySecret
来完成获取拨号连接信息过程的。(注:LsarOpenSecret里面有权限判断,非ADMIN组用
户是没有权限来调用ADVAPI32!LsaRetrievePrivateData的)

   跟踪了一下LsarQuerySecret,发现它返回的数据其实是从注册表中读取。保存拨号
连接信息的注册表键值为:

    HKLMSECURITYPolicySecretsRasDialParams!SID#0CurrVal

    SID对应的是用户的string SID。(“HKLMSECURITY”这个键只有SYSTEM有权限读
写,连admin都没有权限)

    LsarQuerySecret从注册表中读取出来数据后,接着调用LsapCrDecryptValue函数来
解密,对于同一台机器来说,解密时用的KEY始终都是固定的,这个KEY在lsasrv.dll里面
变量名为"_LsapDbSecretCipherKey"。在windows 2003里面,变量名不一样,对应的有两
个,分别为"LsapDbSecretCipherKeyWrite"和"LsapDbSecretCipherKeyRead",但这两个
变量里面的数据是一样的。

    LsapCrDecryptValue用的似乎是标准DES算法,解密时主要流程如下:

    lsasrv!LsapCrDecryptValue
        |_ advapi32!SystemFunction005
            |_ advapi32!DecryptDataLength
                |_ advapi32!SystemFunction002
                    |_ advapi32!DES_ECB_LM
                        |_ advapi32!des

    解密后,在"<<"标示处还有一个判断:

    .text:785462F0                 call    _LsapCrDecryptValue@12
    .text:785462F5                 test    eax, eax
    .text:785462F7                 mov     [ebp+var_8], eax
    .text:785462FA                 jl      loc_785838E1
    .text:78546300
    .text:78546300 loc_78546300:                         
    .text:78546300                 cmp     byte ptr [esi+45h], 0   <<<<<<<<<<<<
    .text:78546304                 jz      short loc_7854632E
    ......
    .text:7854632E loc_7854632E:
    .text:7854632E                 lea     eax, [ebp+var_10]
    .text:78546331                 push    eax
    .text:78546332                 push    [ebp+arg_8]
    .text:78546335                 push    [ebp+var_C]
    .text:78546338                 call    _LsapCrEncryptValue@12


    假如[esi+45h]为0的话(esi是LsarOpenSecret函数返回的HANDLE),它会把解密后的
数据再进行一次加密,不管是2000还是2003,这时用的KEY始终都是固定为
“SystemLibraryDTC”。

    lsadump2里面调用LsarOpenSecret得到的HANDLE,偏移0x45处值为1,所以
LsarQuerySecret函数返回的就是解密后的数据了。

    而在调用ADVAPI32!LsaRetrievePrivateData时,LsarOpenSecret返回的HANDLE偏移
0x45处值为0x0,所以LsarQuerySecret返回的是解密后又加密的数据,所以在
ADVAPI32!LsaRetrievePrivateData里面还有一个对应的解密过程。相应的,
LsapCrEncryptValue加密的主要流程如下:

    lsasrv!LsapCrEncryptValue
        |_ advapi32!SystemFunction004
            |_ advapi32!EncryptDataLength
                |_ advapi32!SystemFunction001
            

相关TAG标签 原理 密码 平台
上一篇:基于错误CRC的防火墙探测技术
下一篇:交换机及路由器如何更加安全
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站