10#include <winpr/sspi.h>
11#include <winpr/wlog.h>
15#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
16#define NTLM_PACKAGE_NAME NTLM_SSP_NAME
18static const char* TEST_NTLM_USER =
"Username";
19static const char* TEST_NTLM_DOMAIN =
"Domain";
20static const char* TEST_NTLM_PASSWORD =
"P4ss123!";
21static const BYTE TEST_NTLM_V2_HASH[16] = { 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9,
22 0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 };
38 SecPkgInfo* pPackageInfo;
39 SecurityFunctionTable* table;
40 SEC_WINNT_AUTH_IDENTITY identity;
57 SecPkgInfo* pPackageInfo;
58 SecurityFunctionTable* table;
61static void fuzz_ntlm_client_uninit(FUZZ_NTLM_CLIENT* client)
66 free(client->outputBuffer[0].pvBuffer);
67 client->outputBuffer[0].pvBuffer =
nullptr;
69 free(client->identity.User);
70 free(client->identity.Domain);
71 free(client->identity.Password);
75 if (SecIsValidHandle(&client->credentials))
76 (void)client->table->FreeCredentialsHandle(&client->credentials);
77 if (client->pPackageInfo)
78 (void)client->table->FreeContextBuffer(client->pPackageInfo);
79 if (client->haveContext && SecIsValidHandle(&client->context))
80 (
void)client->table->DeleteSecurityContext(&client->context);
84static BOOL fuzz_ntlm_client_init(FUZZ_NTLM_CLIENT* client)
86 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
90 ZeroMemory(client,
sizeof(*client));
91 SecInvalidateHandle(&client->context);
92 SecInvalidateHandle(&client->credentials);
94 client->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
98 if (sspi_SetAuthIdentity(&client->identity, TEST_NTLM_USER, TEST_NTLM_DOMAIN,
99 TEST_NTLM_PASSWORD) < 0)
102 status = client->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &client->pPackageInfo);
103 if (status != SEC_E_OK)
106 client->cbMaxToken = client->pPackageInfo->cbMaxToken;
107 status = client->table->AcquireCredentialsHandle(
108 nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND,
nullptr, &client->identity,
nullptr,
109 nullptr, &client->credentials, &client->expiration);
110 if (status != SEC_E_OK)
113 client->fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
117static SECURITY_STATUS fuzz_ntlm_client_step(FUZZ_NTLM_CLIENT* client)
119 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
121 WINPR_ASSERT(client);
123 free(client->outputBuffer[0].pvBuffer);
124 client->outputBuffer[0].pvBuffer =
nullptr;
126 client->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
127 client->outputBufferDesc.cBuffers = ARRAYSIZE(client->outputBuffer);
128 client->outputBufferDesc.pBuffers = client->outputBuffer;
129 client->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
130 client->outputBuffer[0].cbBuffer = client->cbMaxToken;
131 client->outputBuffer[0].pvBuffer = calloc(1, client->outputBuffer[0].cbBuffer);
132 if (!client->outputBuffer[0].pvBuffer)
133 return SEC_E_INSUFFICIENT_MEMORY;
135 if (client->haveInputBuffer)
137 client->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
138 client->inputBufferDesc.cBuffers = ARRAYSIZE(client->inputBuffer);
139 client->inputBufferDesc.pBuffers = client->inputBuffer;
140 client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
143 status = client->table->InitializeSecurityContext(
144 &client->credentials, client->haveContext ? &client->context : nullptr, nullptr,
145 client->fContextReq, 0, SECURITY_NATIVE_DREP,
146 client->haveInputBuffer ? &client->inputBufferDesc : nullptr, 0, &client->context,
147 &client->outputBufferDesc, &client->pfContextAttr, &client->expiration);
149 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
151 if (client->table->CompleteAuthToken)
152 (void)client->table->CompleteAuthToken(&client->context, &client->outputBufferDesc);
154 if (status == SEC_I_COMPLETE_NEEDED)
157 status = SEC_I_CONTINUE_NEEDED;
160 if (!IsSecurityStatusError(status))
161 client->haveContext = TRUE;
166static void fuzz_ntlm_server_uninit(FUZZ_NTLM_SERVER* server)
171 free(server->outputBuffer[0].pvBuffer);
172 server->outputBuffer[0].pvBuffer =
nullptr;
176 if (SecIsValidHandle(&server->credentials))
177 (void)server->table->FreeCredentialsHandle(&server->credentials);
178 if (server->pPackageInfo)
179 (void)server->table->FreeContextBuffer(server->pPackageInfo);
180 if (SecIsValidHandle(&server->context))
181 (
void)server->table->DeleteSecurityContext(&server->context);
185static BOOL fuzz_ntlm_server_init(FUZZ_NTLM_SERVER* server)
187 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
189 WINPR_ASSERT(server);
191 ZeroMemory(server,
sizeof(*server));
192 SecInvalidateHandle(&server->context);
193 SecInvalidateHandle(&server->credentials);
195 server->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
199 status = server->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &server->pPackageInfo);
200 if (status != SEC_E_OK)
203 server->cbMaxToken = server->pPackageInfo->cbMaxToken;
204 status = server->table->AcquireCredentialsHandle(
205 nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_INBOUND,
nullptr,
nullptr,
nullptr,
nullptr,
206 &server->credentials, &server->expiration);
207 if (status != SEC_E_OK)
210 server->fContextReq = ASC_REQ_MUTUAL_AUTH | ASC_REQ_CONFIDENTIALITY | ASC_REQ_CONNECTION |
211 ASC_REQ_USE_SESSION_KEY | ASC_REQ_REPLAY_DETECT |
212 ASC_REQ_SEQUENCE_DETECT | ASC_REQ_EXTENDED_ERROR;
216static SECURITY_STATUS fuzz_ntlm_server_step(FUZZ_NTLM_SERVER* server)
218 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
220 WINPR_ASSERT(server);
222 free(server->outputBuffer[0].pvBuffer);
223 server->outputBuffer[0].pvBuffer =
nullptr;
225 server->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
226 server->inputBufferDesc.cBuffers = ARRAYSIZE(server->inputBuffer);
227 server->inputBufferDesc.pBuffers = server->inputBuffer;
228 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
230 server->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
231 server->outputBufferDesc.cBuffers = ARRAYSIZE(server->outputBuffer);
232 server->outputBufferDesc.pBuffers = server->outputBuffer;
233 server->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
234 server->outputBuffer[0].cbBuffer = server->cbMaxToken;
235 server->outputBuffer[0].pvBuffer = calloc(1, server->outputBuffer[0].cbBuffer);
236 if (!server->outputBuffer[0].pvBuffer)
237 return SEC_E_INSUFFICIENT_MEMORY;
239 status = server->table->AcceptSecurityContext(
240 &server->credentials, server->haveContext ? &server->context : nullptr,
241 &server->inputBufferDesc, server->fContextReq, SECURITY_NATIVE_DREP, &server->context,
242 &server->outputBufferDesc, &server->pfContextAttr, &server->expiration);
244 if (!IsSecurityStatusError(status))
245 server->haveContext = TRUE;
247 if (status == SEC_I_CONTINUE_NEEDED)
251 CopyMemory(hash.NtlmHash, TEST_NTLM_V2_HASH,
sizeof(TEST_NTLM_V2_HASH));
252 (void)server->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_HASH,
253 &hash,
sizeof(hash));
259static void fuzz_ntlm_set_input(
SecBuffer* buffer, BOOL* haveInputBuffer,
const uint8_t* data,
262 WINPR_ASSERT(buffer);
263 WINPR_ASSERT(haveInputBuffer);
265 buffer[0].BufferType = SECBUFFER_TOKEN;
266 buffer[0].pvBuffer = (
void*)data;
267 buffer[0].cbBuffer = (ULONG)size;
268 *haveInputBuffer = TRUE;
271static void fuzz_ntlm_negotiate(
const uint8_t* data,
size_t size)
273 FUZZ_NTLM_SERVER server = WINPR_C_ARRAY_INIT;
275 if (!fuzz_ntlm_server_init(&server))
278 fuzz_ntlm_set_input(server.inputBuffer, &server.haveInputBuffer, data, size);
279 (void)fuzz_ntlm_server_step(&server);
282 fuzz_ntlm_server_uninit(&server);
285static void fuzz_ntlm_challenge(
const uint8_t* data,
size_t size)
287 FUZZ_NTLM_CLIENT client = WINPR_C_ARRAY_INIT;
289 if (!fuzz_ntlm_client_init(&client))
292 if (IsSecurityStatusError(fuzz_ntlm_client_step(&client)))
295 fuzz_ntlm_set_input(client.inputBuffer, &client.haveInputBuffer, data, size);
296 (void)fuzz_ntlm_client_step(&client);
299 fuzz_ntlm_client_uninit(&client);
302static void fuzz_ntlm_authenticate(
const uint8_t* data,
size_t size)
304 FUZZ_NTLM_CLIENT client = WINPR_C_ARRAY_INIT;
305 FUZZ_NTLM_SERVER server = WINPR_C_ARRAY_INIT;
307 if (!fuzz_ntlm_client_init(&client))
309 if (!fuzz_ntlm_server_init(&server))
312 if (fuzz_ntlm_client_step(&client) != SEC_I_CONTINUE_NEEDED)
315 fuzz_ntlm_set_input(server.inputBuffer, &server.haveInputBuffer,
316 client.outputBuffer[0].pvBuffer, client.outputBuffer[0].cbBuffer);
317 if (fuzz_ntlm_server_step(&server) != SEC_I_CONTINUE_NEEDED)
320 fuzz_ntlm_set_input(server.inputBuffer, &server.haveInputBuffer, data, size);
321 (void)fuzz_ntlm_server_step(&server);
324 fuzz_ntlm_client_uninit(&client);
325 fuzz_ntlm_server_uninit(&server);
328int LLVMFuzzerTestOneInput(
const uint8_t* data,
size_t size)
330 static BOOL loggingInitialized = FALSE;
332 if (!loggingInitialized)
334 (void)WLog_SetLogLevel(WLog_GetRoot(), WLOG_TRACE);
335 loggingInitialized = TRUE;
340 if (size > (1u << 20))
346 fuzz_ntlm_negotiate(data + 1, size - 1);
349 fuzz_ntlm_challenge(data + 1, size - 1);
352 fuzz_ntlm_authenticate(data + 1, size - 1);