예제 #1
0
DWORD
NtlmGetWorkstationFromResponse(
    IN PNTLM_RESPONSE_MESSAGE_V1 pRespMsg,
    IN DWORD dwRespMsgSize,
    IN BOOLEAN bUnicode,
    OUT PSTR* ppWorkstation
    )
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PCHAR pName = NULL;
    DWORD dwNameLength = 0;
    PBYTE pBuffer = NULL;
    PNTLM_SEC_BUFFER pSecBuffer = &pRespMsg->Workstation;

    *ppWorkstation = NULL;

    if (dwRespMsgSize < sizeof(*pRespMsg))
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (LW_LTOH32(pSecBuffer->dwOffset) + LW_LTOH16(pSecBuffer->usLength) > dwRespMsgSize)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwNameLength = LW_LTOH16(pSecBuffer->usLength);
    pBuffer = LW_LTOH32(pSecBuffer->dwOffset) + (PBYTE)pRespMsg;

    if (!bUnicode)
    {
        dwError = LwAllocateMemory(dwNameLength + 1, OUT_PPVOID(&pName));
        BAIL_ON_LSA_ERROR(dwError);

        memcpy(pName, pBuffer, dwNameLength);
    }
    else
    {
        dwError = NtlmGetCStringFromUnicodeBuffer(
                      pBuffer,
                      dwNameLength,
                      &pName);
        BAIL_ON_LSA_ERROR(dwError);

    }

cleanup:
    *ppWorkstation = pName;
    return dwError;
error:
    LW_SAFE_FREE_STRING(pName);
    goto cleanup;
}
예제 #2
0
VOID
RtlpDecodeLittleEndianSid(
    IN PSID LittleEndianSid,
    OUT PSID Sid
    )
{
    ULONG i = 0;

    Sid->Revision = LW_LTOH8(LittleEndianSid->Revision);
    Sid->SubAuthorityCount = LW_LTOH8(LittleEndianSid->SubAuthorityCount);
    // sequence of bytes
    Sid->IdentifierAuthority = LittleEndianSid->IdentifierAuthority;

    for (i = 0; i < Sid->SubAuthorityCount; i++)
    {
        Sid->SubAuthority[i] = LW_LTOH32(LittleEndianSid->SubAuthority[i]);
    }
}
예제 #3
0
DWORD
NtlmValidateResponse(
    IN HANDLE Handle,
    IN NTLM_CRED_HANDLE hCred,
    IN PNTLM_RESPONSE_MESSAGE_V1 pRespMsg,
    IN DWORD dwRespMsgSize,
    IN PNTLM_CONTEXT pChlngCtxt,
    OUT BYTE pSessionKey[NTLM_SESSION_KEY_SIZE]
    )
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PNTLM_CREDENTIALS pCred = (PNTLM_CREDENTIALS)hCred;
    LSA_AUTH_USER_PARAMS Params;
    PLSA_AUTH_USER_INFO pUserInfo = NULL;
    PBYTE pLMRespBuffer = NULL;
    PBYTE pNTRespBuffer = NULL;
    LW_LSA_DATA_BLOB Challenge;
    LW_LSA_DATA_BLOB LMResp;
    LW_LSA_DATA_BLOB NTResp;
    PSTR pUserName = NULL;
    PSTR pDomainName = NULL;
    PSTR pWorkstation = NULL;
    PSTR pDomainInstance = NULL;
    BYTE sessionNonce[MD5_DIGEST_LENGTH];
    BYTE sessionHashUntrunc[MD5_DIGEST_LENGTH];
    BOOLEAN bInLock = FALSE;

    memset(&Params, 0, sizeof(Params));
    memset(&Challenge, 0, sizeof(Challenge));
    memset(&LMResp, 0, sizeof(LMResp));
    memset(&NTResp, 0, sizeof(NTResp));

    // sanity check
    if (!pRespMsg || ! pChlngCtxt)
    {
        dwError = LW_ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (dwRespMsgSize < sizeof(*pRespMsg))
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = LwAllocateMemory(
        LW_LTOH16(pRespMsg->LmResponse.usLength),
        OUT_PPVOID(&pLMRespBuffer));
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwAllocateMemory(
        LW_LTOH16(pRespMsg->NtResponse.usLength),
        OUT_PPVOID(&pNTRespBuffer));
    BAIL_ON_LSA_ERROR(dwError);

    // The username, domain, and workstation values might come back as Unicode.
    // We could technically prevent this by not allowing NTLM_FLAG_UNICODE to be
    // set during the negotiation phase, but that seems like an odd restriction
    // for now.

    dwError = NtlmGetUserNameFromResponse(
        pRespMsg,
        dwRespMsgSize,
        pChlngCtxt->NegotiatedFlags & NTLM_FLAG_UNICODE,
        &pUserName);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = NtlmGetDomainNameFromResponse(
        pRespMsg,
        dwRespMsgSize,
        pChlngCtxt->NegotiatedFlags & NTLM_FLAG_UNICODE,
        &pDomainName);
    BAIL_ON_LSA_ERROR(dwError);

    if (pDomainName[0] == 0)
    {
        LW_SAFE_FREE_STRING(pDomainName);
    }

    dwError = NtlmGetWorkstationFromResponse(
        pRespMsg,
        dwRespMsgSize,
        pChlngCtxt->NegotiatedFlags & NTLM_FLAG_UNICODE,
        &pWorkstation);
    BAIL_ON_LSA_ERROR(dwError);

    if (LW_LTOH32(pRespMsg->LmResponse.dwOffset) + LW_LTOH16(pRespMsg->LmResponse.usLength) >
            dwRespMsgSize)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    memcpy(
        pLMRespBuffer,
        (PBYTE)pRespMsg + LW_LTOH32(pRespMsg->LmResponse.dwOffset),
        LW_LTOH16(pRespMsg->LmResponse.usLength));

    if (LW_LTOH32(pRespMsg->NtResponse.dwOffset) + LW_LTOH16(pRespMsg->NtResponse.usLength) >
            dwRespMsgSize)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    memcpy(
        pNTRespBuffer,
        (PBYTE)pRespMsg + LW_LTOH32(pRespMsg->NtResponse.dwOffset),
        LW_LTOH16(pRespMsg->NtResponse.usLength));

    if (LW_LTOH16(pRespMsg->NtResponse.usLength) == 24 &&
            pChlngCtxt->NegotiatedFlags & NTLM_FLAG_NTLM2)
    {
        // The client sent an NTLM2 session response. That means we need to
        // calculate the challenge the client used.

        if (LW_LTOH16(pRespMsg->LmResponse.usLength) < 8)
        {
            dwError = LW_ERROR_INVALID_PARAMETER;
            BAIL_ON_LSA_ERROR(dwError);
        }

        // Calculate the session nonce first
        memcpy(sessionNonce + 0, pChlngCtxt->Challenge, 8);
        memcpy(sessionNonce + 8, pLMRespBuffer, 8);

        MD5(sessionNonce, 16, sessionHashUntrunc);

        Challenge.dwLen = NTLM_CHALLENGE_SIZE;
        Challenge.pData = sessionHashUntrunc;
    }
    else
    {
        Challenge.dwLen = NTLM_CHALLENGE_SIZE;
        Challenge.pData = pChlngCtxt->Challenge;
    }

    LMResp.dwLen = LW_LTOH16(pRespMsg->LmResponse.usLength);
    LMResp.pData = pLMRespBuffer;

    NTResp.dwLen = LW_LTOH16(pRespMsg->NtResponse.usLength);
    NTResp.pData = pNTRespBuffer;

    Params.AuthType = LSA_AUTH_CHAP;

    Params.pass.chap.pChallenge = &Challenge;
    Params.pass.chap.pLM_resp = &LMResp;
    Params.pass.chap.pNT_resp = &NTResp;

    Params.pszAccountName = pUserName;

    Params.pszDomain = pDomainName;

    Params.pszWorkstation = pWorkstation;

    if (pCred)
    {
        NTLM_LOCK_MUTEX(bInLock, &pCred->Mutex);

        if (pCred->pszDomainName)
        {
            dwError = LwAllocateStringPrintf(
                          &pDomainInstance,
                          ":%s",
                          pCred->pszDomainName);
            BAIL_ON_LSA_ERROR(dwError);
        }

        NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex);
    }

    dwError = LsaSrvAuthenticateUserEx(
        Handle,
        pDomainInstance,
        &Params,
        &pUserInfo
        );
    BAIL_ON_LSA_ERROR(dwError);

    LW_ASSERT(pUserInfo->pSessionKey->dwLen == NTLM_SESSION_KEY_SIZE);

    if (LW_LTOH16(pRespMsg->NtResponse.usLength) == 24 &&
            pChlngCtxt->NegotiatedFlags & NTLM_FLAG_NTLM2)
    {
        HMAC(
            EVP_md5(),
            pUserInfo->pSessionKey->pData,
            NTLM_SESSION_KEY_SIZE,
            sessionNonce,
            16,
            pSessionKey,
            NULL);
    }
    else
    {
        memcpy(pSessionKey, pUserInfo->pSessionKey->pData, NTLM_SESSION_KEY_SIZE);
    }

    pChlngCtxt->pUserInfo = pUserInfo;
    pUserInfo = NULL;

cleanup:

    if (pCred)
    {
        NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex);
    }

    if (pUserInfo)
    {
        LsaFreeAuthUserInfo(&pUserInfo);
    }

    LW_SAFE_FREE_MEMORY(pLMRespBuffer);
    LW_SAFE_FREE_MEMORY(pNTRespBuffer);
    LW_SAFE_FREE_STRING(pUserName);
    LW_SAFE_FREE_STRING(pDomainName);
    LW_SAFE_FREE_STRING(pWorkstation);
    LW_SAFE_FREE_STRING(pDomainInstance);

    return dwError;
error:
    goto cleanup;
}
예제 #4
0
DWORD
NtlmCreateValidatedContext(
    IN PNTLM_RESPONSE_MESSAGE_V1 pNtlmRespMsg,
    IN DWORD dwMsgSize,
    IN PNTLM_CONTEXT pNtlmCtxtChlng,
    IN PBYTE pSessionKey,
    IN DWORD dwSessionKeyLen,
    IN NTLM_CRED_HANDLE hCred,
    OUT PNTLM_CONTEXT *ppNtlmContext
    )
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PNTLM_CONTEXT pNtlmContext = NULL;
    SEC_CHAR* pUserName = NULL;
    SEC_CHAR* pDomainName = NULL;
    PNTLM_RESPONSE_MESSAGE_V2 pV2Message = NULL;
    RC4_KEY Rc4Key;

    *ppNtlmContext = NULL;

    dwError = NtlmCreateContext(hCred, &pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

    pNtlmContext->NtlmState = NtlmStateResponse;

    pNtlmContext->NegotiatedFlags = pNtlmCtxtChlng->NegotiatedFlags;

    dwError = LwAllocateStringPrintf(
                    &pNtlmContext->pszClientUsername,
                    "%s\\%s",
                    pNtlmCtxtChlng->pUserInfo->pszDomain,
                    pNtlmCtxtChlng->pUserInfo->pszAccount);
    BAIL_ON_LSA_ERROR(dwError);

    memcpy(pNtlmContext->SessionKey, pSessionKey, NTLM_SESSION_KEY_SIZE);
    pNtlmContext->cbSessionKeyLen = dwSessionKeyLen;
    pNtlmContext->bInitiatedSide = FALSE;

    if (pNtlmContext->NegotiatedFlags & NTLM_FLAG_KEY_EXCH)
    {
        pV2Message = (PNTLM_RESPONSE_MESSAGE_V2)pNtlmRespMsg;
        if (dwMsgSize < sizeof(*pV2Message))
        {
            dwError = ERROR_INVALID_PARAMETER;
            BAIL_ON_LSA_ERROR(dwError);
        }

        if (LW_LTOH32(pV2Message->SessionKey.dwOffset) +
                LW_LTOH16(pV2Message->SessionKey.usLength) > dwMsgSize)
        {
            dwError = ERROR_INVALID_PARAMETER;
            BAIL_ON_LSA_ERROR(dwError);
        }

        if (LW_LTOH16(pV2Message->SessionKey.usLength) != NTLM_SESSION_KEY_SIZE)
        {
            dwError = ERROR_INVALID_PARAMETER;
            BAIL_ON_LSA_ERROR(dwError);
        }

        RC4_set_key(
                &Rc4Key,
                pNtlmContext->cbSessionKeyLen,
                pNtlmContext->SessionKey);
        RC4(&Rc4Key,
                NTLM_SESSION_KEY_SIZE,
                LW_LTOH32(pV2Message->SessionKey.dwOffset) + (PBYTE)pV2Message,
                pNtlmContext->SessionKey);
    }

    dwError = NtlmInitializeKeys(pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

cleanup:
    LW_SAFE_FREE_MEMORY(pUserName);
    LW_SAFE_FREE_MEMORY(pDomainName);
    *ppNtlmContext = pNtlmContext;
    return dwError;

error:
    if (pNtlmContext)
    {
        NtlmFreeContext(&pNtlmContext);
    }
    goto cleanup;
}
예제 #5
0
DWORD
NtlmCreateChallengeContext(
    IN const NTLM_NEGOTIATE_MESSAGE_V1* pNtlmNegMsg,
    IN NTLM_CRED_HANDLE hCred,
    OUT PNTLM_CONTEXT *ppNtlmContext,
    OUT PSecBuffer pOutput
    )
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PNTLM_CREDENTIALS pCred = (PNTLM_CREDENTIALS)hCred;
    PNTLM_CONTEXT pNtlmContext = NULL;
    DWORD dwMessageSize = 0;
    PNTLM_CHALLENGE_MESSAGE pMessage = NULL;
    PSTR pServerName = NULL;
    PSTR pDomainName = NULL;
    PSTR pDnsServerName = NULL;
    PSTR pDnsDomainName = NULL;
    BOOLEAN bInLock = FALSE;

    *ppNtlmContext = NULL;

    dwError = NtlmCreateContext(hCred, &pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

    if (pCred)
    {
        NTLM_LOCK_MUTEX(bInLock, &pCred->Mutex);

        dwError = NtlmGetNameInformation(
            pCred->pszDomainName,
            &pServerName,
            &pDomainName,
            &pDnsServerName,
            &pDnsDomainName);
        BAIL_ON_LSA_ERROR(dwError);

        NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex);
    }
    else
    {
        dwError = NtlmGetNameInformation(
            NULL,
            &pServerName,
            &pDomainName,
            &pDnsServerName,
            &pDnsDomainName);
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = NtlmGetRandomBuffer(
        pNtlmContext->Challenge,
        NTLM_CHALLENGE_SIZE
        );
    BAIL_ON_LSA_ERROR(dwError);

    dwError = NtlmCreateChallengeMessage(
        pNtlmNegMsg,
        pServerName,
        pDomainName,
        pDnsServerName,
        pDnsDomainName,
        (PBYTE)&gW2KSpoof,
        pNtlmContext->Challenge,
        &dwMessageSize,
        &pMessage
        );

    BAIL_ON_LSA_ERROR(dwError);

    pNtlmContext->NegotiatedFlags = LW_LTOH32(pMessage->NtlmFlags);
    pOutput->cbBuffer = dwMessageSize;
    pOutput->BufferType = SECBUFFER_TOKEN;
    pOutput->pvBuffer = pMessage;
    pNtlmContext->NtlmState = NtlmStateChallenge;

cleanup:
    *ppNtlmContext = pNtlmContext;

    LW_SAFE_FREE_STRING(pServerName);
    LW_SAFE_FREE_STRING(pDomainName);
    LW_SAFE_FREE_STRING(pDnsServerName);
    LW_SAFE_FREE_STRING(pDnsDomainName);

    if (pCred)
    {
        NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex);
    }

    return dwError;

error:
    LW_SAFE_FREE_MEMORY(pMessage);

    if (pNtlmContext)
    {
        NtlmReleaseContext(&pNtlmContext);
        *ppNtlmContext = NULL;
    }
    pOutput->cbBuffer = 0;
    pOutput->BufferType = 0;
    pOutput->pvBuffer = NULL;
    goto cleanup;
}
예제 #6
0
DWORD
NtlmCreateResponseContext(
    IN PNTLM_CHALLENGE_MESSAGE pChlngMsg,
    IN NTLM_CRED_HANDLE hCred,
    IN BOOLEAN bDoAnonymous,
    OUT PNTLM_CONTEXT* ppNtlmContext,
    OUT PSecBuffer pOutput
)
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PNTLM_RESPONSE_MESSAGE_V1 pMessage = NULL;
    PCSTR pUserNameTemp = NULL;
    PCSTR pPassword = NULL;
    PNTLM_CONTEXT pNtlmContext = NULL;
    PBYTE pMasterKey = NULL;
    BYTE LmUserSessionKey[NTLM_SESSION_KEY_SIZE] = {0};
    BYTE NtlmUserSessionKey[NTLM_SESSION_KEY_SIZE] = {0};
    BYTE LanManagerSessionKey[NTLM_SESSION_KEY_SIZE] = {0};
    BYTE SecondaryKey[NTLM_SESSION_KEY_SIZE] = {0};
    PLSA_LOGIN_NAME_INFO pUserNameInfo = NULL;
    DWORD dwMessageSize = 0;
    NTLM_CONFIG config;
    DWORD dwNtRespType = 0;
    DWORD dwLmRespType = 0;

    *ppNtlmContext = NULL;

    dwError = NtlmReadRegistry(&config);
    BAIL_ON_LSA_ERROR(dwError);

    if (bDoAnonymous)
    {
        pUserNameTemp = "";
        pPassword = "";
    }
    else
    {
        NtlmGetCredentialInfo(
            hCred,
            &pUserNameTemp,
            &pPassword,
            NULL);

        if (!pUserNameTemp[0] && !pPassword[0])
        {
            bDoAnonymous = TRUE;
        }
    }

    if (bDoAnonymous)
    {
        dwError = LwAllocateMemory(
                      sizeof(*pUserNameInfo),
                      OUT_PPVOID(&pUserNameInfo));
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateString(
                      "",
                      &pUserNameInfo->pszName);
        BAIL_ON_LSA_ERROR(dwError);
        dwError = LwAllocateString(
                      "",
                      &pUserNameInfo->pszDomain);
        BAIL_ON_LSA_ERROR(dwError);
    }
    else
    {
        dwError = LsaSrvCrackDomainQualifiedName(
                      pUserNameTemp,
                      &pUserNameInfo);
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = NtlmCreateContext(hCred, &pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwAllocateString(
                  pUserNameTemp,
                  &pNtlmContext->pszClientUsername);
    BAIL_ON_LSA_ERROR(dwError);

    if (bDoAnonymous)
    {
        dwNtRespType = NTLM_RESPONSE_TYPE_ANON_NTLM;
        dwLmRespType = NTLM_RESPONSE_TYPE_ANON_LM;
    }
    else if (config.bSendNTLMv2)
    {
        dwNtRespType = NTLM_RESPONSE_TYPE_NTLMv2;
        // TODO: the correct thing is to use LMv2
        dwLmRespType = NTLM_RESPONSE_TYPE_LM;
    }
    else if(LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_NTLM2)
    {
        dwLmRespType = NTLM_RESPONSE_TYPE_NTLM2;
        dwNtRespType = NTLM_RESPONSE_TYPE_NTLM2;
    }
    else
    {
        dwNtRespType = NTLM_RESPONSE_TYPE_NTLM;
        dwLmRespType = NTLM_RESPONSE_TYPE_LM;
    }

    dwError = NtlmCreateResponseMessage(
                  pChlngMsg,
                  pUserNameInfo->pszName,
                  pUserNameInfo->pszDomain,
                  pPassword,
                  (PBYTE)&gXpSpoof,
                  dwNtRespType,
                  dwLmRespType,
                  &dwMessageSize,
                  &pMessage,
                  LmUserSessionKey,
                  NtlmUserSessionKey
              );
    BAIL_ON_LSA_ERROR(dwError);

    // As a side effect of creating the response, we must also set/produce the
    // master session key...

    pMasterKey = NtlmUserSessionKey;

    if (LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_LM_KEY)
    {
        NtlmGenerateLanManagerSessionKey(
            pMessage,
            LmUserSessionKey,
            LanManagerSessionKey);

        pMasterKey = LanManagerSessionKey;
    }

    if (LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_KEY_EXCH)
    {
        // This is the key we will use for session security...
        dwError = NtlmGetRandomBuffer(
                      SecondaryKey,
                      NTLM_SESSION_KEY_SIZE);
        BAIL_ON_LSA_ERROR(dwError);

        // Encrypt it with the "master key" set above and send it along with the
        // response
        NtlmStoreSecondaryKey(
            pMasterKey,
            SecondaryKey,
            pMessage);

        pMasterKey = SecondaryKey;
    }

    NtlmWeakenSessionKey(
        pChlngMsg,
        pMasterKey,
        &pNtlmContext->cbSessionKeyLen);

    memcpy(pNtlmContext->SessionKey, pMasterKey, NTLM_SESSION_KEY_SIZE);

    pNtlmContext->NegotiatedFlags = LW_LTOH32(pChlngMsg->NtlmFlags);
    pOutput->cbBuffer = dwMessageSize;
    pOutput->BufferType = SECBUFFER_TOKEN;
    pOutput->pvBuffer = pMessage;
    pNtlmContext->NtlmState = NtlmStateResponse;
    pNtlmContext->bInitiatedSide = TRUE;
    pNtlmContext->bDoAnonymous = bDoAnonymous;

    dwError = NtlmInitializeKeys(pNtlmContext);
    BAIL_ON_LSA_ERROR(dwError);

cleanup:
    if (pUserNameInfo)
    {
        LsaSrvFreeNameInfo(pUserNameInfo);
    }

    *ppNtlmContext = pNtlmContext;

    return dwError;
error:
    LW_SAFE_FREE_MEMORY(pMessage);
    if (pNtlmContext)
    {
        NtlmFreeContext(&pNtlmContext);
    }
    pOutput->cbBuffer = 0;
    pOutput->BufferType = 0;
    pOutput->pvBuffer = NULL;

    goto cleanup;
}