首页
社区
课程
招聘
[分享&挑战]sekurlsa.dll逆向分析challenge(可能发现windows系统账号存储机制的小秘密)
发表于: 2012-2-23 20:55 59916

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

2012-2-23 20:55
59916
收藏
免费 6
支持
分享
最新回复 (64)
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
26
大侠口误了吧

Minimum supported client
  Windows XP
2012-2-24 22:50
0
雪    币: 1233
活跃值: (907)
能力值: ( LV12,RANK:750 )
在线值:
发帖
回帖
粉丝
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
2012-2-25 00:07
0
雪    币: 53
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
28
楼上v587~
2012-2-25 00:40
0
雪    币: 46
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
29
直接dll名字 就可以的~
2012-2-25 12:45
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
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");
后面省略
2012-2-25 19:40
0
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
31
各位大神雄起啊!
2012-2-25 19:44
0
雪    币: 416
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
32
這種技術似乎很容易就背抵抗了= =,只要稍微再hook和inject動手腳,就無法取得了= =

感覺還不錯,但是太容易悲劇了。
2012-2-25 20:03
0
雪    币: 1233
活跃值: (907)
能力值: ( LV12,RANK:750 )
在线值:
发帖
回帖
粉丝
33
这个应该是Windows实现的问题,怎么能保存密码到内存呢?怎么着也只能保存hash哈
2012-2-25 20:15
0
雪    币: 563
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
34
有意思 收下
2012-2-25 20:25
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
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可以抄代码
其他的部分前面的大牛已经分析的差不多了,详细的流程什么的等牛人来写吧,干活去咯
2012-2-26 13:53
0
雪    币: 1787
活跃值: (340)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
36
[QUOTE=zhuwg;1047913]好久不写东西了,继续下
我的机器上
lsass进程空间里面
eax=[742EC184]=74520088+b0=74520138
在地址74520138是LSASRV.7448FE76
这个函数是lsasrv.dll里面的内部函数
7448FE76 ; int __stdcall LsaProte...[/QUOTE]

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