Created
August 31, 2023 14:17
-
-
Save rbmm/d2de710d29ef67a6fb63cd4c8392a27e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct KERB_SMARTCARD_CSP_INFO | |
{ | |
ULONG dwCspInfoLen; // size of this structure w/ payload | |
ULONG MessageType; // info type, currently CertHashInfo | |
// payload starts, marshaled structure of MessageType | |
union { | |
PVOID ContextInformation; // Reserved | |
ULONG64 SpaceHolderForWow64; | |
}; | |
ULONG flags; // Reserved | |
ULONG KeySpec; // AT_SIGNATURE xor AT_KEYEXCHANGE | |
ULONG nCardNameOffset; | |
ULONG nReaderNameOffset; | |
ULONG nContainerNameOffset; | |
ULONG nCSPNameOffset; | |
WCHAR Buffer[]; | |
} *PKERB_SMARTCARD_CSP_INFO; | |
HRESULT Format(_Out_ PVOID* SubmitBuffer, | |
_Out_ ULONG* SubmitBufferSize, | |
_In_ PCUNICODE_STRING DomainName, | |
_In_ PCUNICODE_STRING UserName, | |
_In_ PCUNICODE_STRING Pin, | |
_In_ PCWSTR CardName, | |
_In_ PCWSTR ReaderName, | |
_In_ PCWSTR ContainerName, | |
_In_ PCWSTR CSPName) | |
{ | |
UNICODE_STRING z{}; | |
if (!DomainName) DomainName = &z; | |
if (!UserName) UserName = &z; | |
if (!Pin) Pin = &z; | |
if (!CardName) CardName = L""; | |
if (!ReaderName) ReaderName = L""; | |
if (!ContainerName) ContainerName = L""; | |
if (!CSPName) CSPName = L""; | |
PWSTR buf = 0; | |
int len = 0; | |
struct KERB_CERTIFICATE_LOGON_EX : public KERB_CERTIFICATE_LOGON | |
{ | |
KERB_SMARTCARD_CSP_INFO Csp; | |
void* operator new(size_t s, ULONG cch) | |
{ | |
return LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, s + cch * sizeof(WCHAR)); | |
} | |
void operator delete(void* pv) | |
{ | |
LocalFree(pv); | |
} | |
}; | |
KERB_CERTIFICATE_LOGON_EX* p = 0; | |
while (0 < (len = _snwprintf(buf, len, L"%s%c%s%c%s%c%s%c%wZ%c%wZ%c%wZ", | |
CardName, 0, ReaderName, 0, ContainerName, 0, CSPName, 0, DomainName, 0, UserName, 0, Pin))) | |
{ | |
if (buf) | |
{ | |
PWSTR Buffer = buf; | |
p->CspData = (PUCHAR)&p->Csp; | |
p->Csp.nCardNameOffset = 0; //(ULONG)(buf - Buffer); | |
buf += wcslen(buf) + 1; | |
p->Csp.nReaderNameOffset = (ULONG)(buf - Buffer); | |
buf += wcslen(buf) + 1; | |
p->Csp.nContainerNameOffset = (ULONG)(buf - Buffer); | |
buf += wcslen(buf) + 1; | |
p->Csp.nCSPNameOffset = (ULONG)(buf - Buffer); | |
buf += wcslen(buf) + 1; | |
p->Csp.dwCspInfoLen = p->CspDataLength = RtlPointerToOffset(&p->Csp, buf); | |
RtlInitUnicodeString(&p->DomainName, buf); | |
buf += wcslen(buf) + 1; | |
RtlInitUnicodeString(&p->UserName, buf); | |
buf += wcslen(buf) + 1; | |
RtlInitUnicodeString(&p->Pin, buf); | |
buf += wcslen(buf) + 1; | |
(ULONG_PTR&)p->DomainName.Buffer -= (ULONG_PTR)p; | |
(ULONG_PTR&)p->UserName.Buffer -= (ULONG_PTR)p; | |
(ULONG_PTR&)p->Pin.Buffer -= (ULONG_PTR)p; | |
(ULONG_PTR&)p->CspData -= (ULONG_PTR)p; | |
p->MessageType = KerbCertificateLogon; | |
p->Csp.MessageType = 1; | |
p->Csp.KeySpec = AT_KEYEXCHANGE; | |
*SubmitBuffer = p; | |
*SubmitBufferSize = RtlPointerToOffset(p, buf); | |
return S_OK; | |
} | |
p = new(++len) KERB_CERTIFICATE_LOGON_EX; | |
if (!p) | |
{ | |
return E_OUTOFMEMORY; | |
} | |
buf = p->Csp.Buffer; | |
} | |
delete p; | |
return HRESULT_FROM_NT(STATUS_INTERNAL_ERROR); | |
} | |
BOOLEAN IsDataOk(ULONG_PTR m, ULONG_PTR M, ULONG_PTR rva, ULONG size = 1, | |
ULONG_PTR type_align = 0, ULONG_PTR size_align = 0, ULONG_PTR min_size = 0) | |
{ | |
if ((rva & type_align) || (size & size_align) || size < min_size || rva < m) | |
{ | |
return FALSE; | |
} | |
ULONG_PTR end = rva + size; | |
return rva < end && end <= M; | |
} | |
BOOLEAN Validate(_In_reads_bytes_(SubmitBufferSize) PVOID ProtocolSubmitBuffer, | |
_In_ ULONG SubmitBufferSize, | |
_Out_ PUNICODE_STRING Pin, | |
_Out_ ULONG* KeySpec, | |
_Out_ PCWSTR* CardName, | |
_Out_ PCWSTR* ReaderName, | |
_Out_ PCWSTR* ContainerName, | |
_Out_ PCWSTR* CSPName) | |
{ | |
if (SubmitBufferSize <= sizeof(KERB_LOGON_SUBMIT_TYPE)) | |
{ | |
return FALSE; | |
} | |
union { | |
PVOID pv; | |
ULONG_PTR up; | |
PKERB_LOGON_SUBMIT_TYPE pMessageType; | |
PKERB_CERTIFICATE_LOGON pCertLogon; | |
PKERB_CERTIFICATE_UNLOCK_LOGON pCertUnlockLogon; | |
PKERB_SMART_CARD_LOGON pScLogon; | |
PKERB_SMART_CARD_UNLOCK_LOGON pScUnlockLogon; | |
PUCHAR CspData; // contains the smartcard CSP data | |
PKERB_SMARTCARD_CSP_INFO pksci; | |
}; | |
pv = ProtocolSubmitBuffer; | |
ULONG Length, CspDataLength, StructSize = 0; | |
DbgPrint("MessageType = %x\r\n", *pMessageType); | |
switch (*pMessageType) | |
{ | |
case KerbCertificateUnlockLogon: | |
StructSize = sizeof(LUID); | |
[[fallthrough]]; | |
case KerbCertificateLogon: | |
if (SubmitBufferSize <= (StructSize += sizeof(KERB_CERTIFICATE_LOGON))) | |
{ | |
return FALSE; | |
} | |
*Pin = pCertLogon->Pin; | |
CspDataLength = pCertLogon->CspDataLength; | |
CspData = pCertLogon->CspData; | |
break; | |
case KerbSmartCardUnlockLogon: | |
StructSize = sizeof(LUID); | |
[[fallthrough]]; | |
case KerbSmartCardLogon: | |
if (SubmitBufferSize <= (StructSize += sizeof(PKERB_SMART_CARD_LOGON))) | |
{ | |
return FALSE; | |
} | |
*Pin = pScLogon->Pin; | |
CspDataLength = pScLogon->CspDataLength; | |
CspData = pScLogon->CspData; | |
break; | |
default: | |
return FALSE; | |
} | |
if (!IsDataOk(StructSize, SubmitBufferSize, up, CspDataLength, | |
__alignof(KERB_SMARTCARD_CSP_INFO) - 1, 0, sizeof(KERB_SMARTCARD_CSP_INFO))) | |
{ | |
return FALSE; | |
} | |
if ((Length = Pin->Length) > Pin->MaximumLength || !IsDataOk(StructSize, SubmitBufferSize, (ULONG_PTR)Pin->Buffer, Length, | |
__alignof(WCHAR) - 1, __alignof(WCHAR) - 1, sizeof(WCHAR))) | |
{ | |
return FALSE; | |
} | |
(ULONG_PTR&)Pin->Buffer += (ULONG_PTR)ProtocolSubmitBuffer, up += (ULONG_PTR)ProtocolSubmitBuffer; | |
ULONG dwCspInfoLen = pksci->dwCspInfoLen; | |
if (dwCspInfoLen <= sizeof(KERB_SMARTCARD_CSP_INFO ) || dwCspInfoLen > CspDataLength) | |
{ | |
return FALSE; | |
} | |
dwCspInfoLen -= sizeof(KERB_SMARTCARD_CSP_INFO ); | |
if (!(dwCspInfoLen /= sizeof(WCHAR)) || pksci->Buffer[dwCspInfoLen - 1]) | |
{ | |
return FALSE; | |
} | |
ULONG nCardNameOffset, nReaderNameOffset, nContainerNameOffset, nCSPNameOffset; | |
if (!IsDataOk(0, dwCspInfoLen, nCardNameOffset = pksci->nCardNameOffset) || | |
!IsDataOk(0, dwCspInfoLen, nReaderNameOffset = pksci->nReaderNameOffset) || | |
!IsDataOk(0, dwCspInfoLen, nContainerNameOffset = pksci->nContainerNameOffset) || | |
!IsDataOk(0, dwCspInfoLen, nCSPNameOffset = pksci->nCSPNameOffset)) | |
{ | |
return FALSE; | |
} | |
*CardName = &pksci->Buffer[nCardNameOffset]; | |
*ContainerName = &pksci->Buffer[nContainerNameOffset]; | |
*CSPName = &pksci->Buffer[nCSPNameOffset]; | |
*ReaderName = &pksci->Buffer[nReaderNameOffset]; | |
*KeySpec = pksci->KeySpec; | |
return TRUE; | |
} | |
NTSTATUS LogonUser(_In_ ULONG AuthenticationPackage, | |
_In_ PVOID pvAuthBuffer, | |
_In_ ULONG cbAuthBuffer, | |
_Out_ PLUID LogonId, | |
_Out_ PHANDLE UserToken) | |
{ | |
NTSTATUS status, SubStatus = 0; | |
HANDLE LsaHandle; | |
if (0 <= (status = LsaConnectUntrusted(&LsaHandle))) | |
{ | |
TOKEN_SOURCE ts = {}; | |
PKERB_INTERACTIVE_PROFILE ProfileBuffer = 0; | |
ULONG ProfileBufferLength; | |
QUOTA_LIMITS Quotas; | |
LSA_STRING OriginName = RTL_CONSTANT_STRING("12345678"); | |
if (0 <= (status = LsaLogonUser(LsaHandle, &OriginName, Batch, | |
AuthenticationPackage, pvAuthBuffer, cbAuthBuffer, | |
0, &ts, (void**)&ProfileBuffer, &ProfileBufferLength, LogonId, UserToken, &Quotas, &SubStatus))) | |
{ | |
LsaFreeReturnBuffer(ProfileBuffer); | |
} | |
else | |
{ | |
DbgPrint("LsaLogonUser = %x, %x\r\n", status, SubStatus); | |
} | |
LsaDeregisterLogonProcess(LsaHandle); | |
} | |
return status; | |
} | |
void test() | |
{ | |
CREDUI_INFOW UiInfo = { sizeof(UiInfo), 0, 0, L"" }; | |
ULONG AuthenticationPackage; | |
PVOID SubmitBuffer = 0; | |
ULONG SubmitBufferSize = 0; | |
if (NOERROR == CredUIPromptForWindowsCredentialsW(&UiInfo, 0, | |
&AuthenticationPackage, 0, 0, &SubmitBuffer, &SubmitBufferSize, 0, 0)) | |
{ | |
UNICODE_STRING Pin; | |
ULONG KeySpec; | |
PCWSTR CardName, ReaderName, ContainerName, CSPName; | |
if (Validate(SubmitBuffer, SubmitBufferSize, &Pin, &KeySpec, &CardName, &ReaderName, &ContainerName, &CSPName)) | |
{ | |
PVOID pvAuthBuffer; | |
ULONG cbAuthBuffer; | |
if (0 <= Format(&pvAuthBuffer, &cbAuthBuffer, 0, 0, &Pin, CardName, ReaderName, ContainerName, CSPName)) | |
{ | |
if (Validate(pvAuthBuffer, cbAuthBuffer, &Pin, &KeySpec, &CardName, &ReaderName, &ContainerName, &CSPName)) | |
{ | |
HANDLE hToken; | |
LUID LogonId; | |
if (0 <= LogonUser(AuthenticationPackage, pvAuthBuffer, cbAuthBuffer, &LogonId, &hToken)) | |
{ | |
NtClose(hToken); | |
} | |
} | |
LocalFree(pvAuthBuffer); | |
} | |
} | |
CoTaskMemFree(SubmitBuffer); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment