Skip to content

Instantly share code, notes, and snippets.

@rbmm
Created August 31, 2023 14:17
Show Gist options
  • Save rbmm/d2de710d29ef67a6fb63cd4c8392a27e to your computer and use it in GitHub Desktop.
Save rbmm/d2de710d29ef67a6fb63cd4c8392a27e to your computer and use it in GitHub Desktop.
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