FreeRDP
Loading...
Searching...
No Matches
TestFuzzNTLMMessage.c
1
6#include <stddef.h>
7#include <stdint.h>
8
9#include <winpr/crt.h>
10#include <winpr/sspi.h>
11#include <winpr/wlog.h>
12
13#include "../sspi.h"
14
15#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
16#define NTLM_PACKAGE_NAME NTLM_SSP_NAME
17
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 };
23
24typedef struct
25{
26 CtxtHandle context;
27 ULONG cbMaxToken;
28 ULONG fContextReq;
29 ULONG pfContextAttr;
30 TimeStamp expiration;
31 SecBuffer inputBuffer[1];
32 SecBuffer outputBuffer[1];
33 BOOL haveContext;
34 BOOL haveInputBuffer;
35 SecBufferDesc inputBufferDesc;
36 SecBufferDesc outputBufferDesc;
37 CredHandle credentials;
38 SecPkgInfo* pPackageInfo;
39 SecurityFunctionTable* table;
40 SEC_WINNT_AUTH_IDENTITY identity;
41} FUZZ_NTLM_CLIENT;
42
43typedef struct
44{
45 CtxtHandle context;
46 ULONG cbMaxToken;
47 ULONG fContextReq;
48 ULONG pfContextAttr;
49 TimeStamp expiration;
50 SecBuffer inputBuffer[1];
51 SecBuffer outputBuffer[1];
52 BOOL haveContext;
53 BOOL haveInputBuffer;
54 SecBufferDesc inputBufferDesc;
55 SecBufferDesc outputBufferDesc;
56 CredHandle credentials;
57 SecPkgInfo* pPackageInfo;
58 SecurityFunctionTable* table;
59} FUZZ_NTLM_SERVER;
60
61static void fuzz_ntlm_client_uninit(FUZZ_NTLM_CLIENT* client)
62{
63 if (!client)
64 return;
65
66 free(client->outputBuffer[0].pvBuffer);
67 client->outputBuffer[0].pvBuffer = nullptr;
68
69 free(client->identity.User);
70 free(client->identity.Domain);
71 free(client->identity.Password);
72
73 if (client->table)
74 {
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);
81 }
82}
83
84static BOOL fuzz_ntlm_client_init(FUZZ_NTLM_CLIENT* client)
85{
86 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
87
88 WINPR_ASSERT(client);
89
90 ZeroMemory(client, sizeof(*client));
91 SecInvalidateHandle(&client->context);
92 SecInvalidateHandle(&client->credentials);
93
94 client->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
95 if (!client->table)
96 return FALSE;
97
98 if (sspi_SetAuthIdentity(&client->identity, TEST_NTLM_USER, TEST_NTLM_DOMAIN,
99 TEST_NTLM_PASSWORD) < 0)
100 return FALSE;
101
102 status = client->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &client->pPackageInfo);
103 if (status != SEC_E_OK)
104 return FALSE;
105
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)
111 return FALSE;
112
113 client->fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
114 return TRUE;
115}
116
117static SECURITY_STATUS fuzz_ntlm_client_step(FUZZ_NTLM_CLIENT* client)
118{
119 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
120
121 WINPR_ASSERT(client);
122
123 free(client->outputBuffer[0].pvBuffer);
124 client->outputBuffer[0].pvBuffer = nullptr;
125
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;
134
135 if (client->haveInputBuffer)
136 {
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;
141 }
142
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);
148
149 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
150 {
151 if (client->table->CompleteAuthToken)
152 (void)client->table->CompleteAuthToken(&client->context, &client->outputBufferDesc);
153
154 if (status == SEC_I_COMPLETE_NEEDED)
155 status = SEC_E_OK;
156 else
157 status = SEC_I_CONTINUE_NEEDED;
158 }
159
160 if (!IsSecurityStatusError(status))
161 client->haveContext = TRUE;
162
163 return status;
164}
165
166static void fuzz_ntlm_server_uninit(FUZZ_NTLM_SERVER* server)
167{
168 if (!server)
169 return;
170
171 free(server->outputBuffer[0].pvBuffer);
172 server->outputBuffer[0].pvBuffer = nullptr;
173
174 if (server->table)
175 {
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);
182 }
183}
184
185static BOOL fuzz_ntlm_server_init(FUZZ_NTLM_SERVER* server)
186{
187 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
188
189 WINPR_ASSERT(server);
190
191 ZeroMemory(server, sizeof(*server));
192 SecInvalidateHandle(&server->context);
193 SecInvalidateHandle(&server->credentials);
194
195 server->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
196 if (!server->table)
197 return FALSE;
198
199 status = server->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &server->pPackageInfo);
200 if (status != SEC_E_OK)
201 return FALSE;
202
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)
208 return FALSE;
209
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;
213 return TRUE;
214}
215
216static SECURITY_STATUS fuzz_ntlm_server_step(FUZZ_NTLM_SERVER* server)
217{
218 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
219
220 WINPR_ASSERT(server);
221
222 free(server->outputBuffer[0].pvBuffer);
223 server->outputBuffer[0].pvBuffer = nullptr;
224
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;
229
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;
238
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);
243
244 if (!IsSecurityStatusError(status))
245 server->haveContext = TRUE;
246
247 if (status == SEC_I_CONTINUE_NEEDED)
248 {
249 SecPkgContext_AuthNtlmHash hash = WINPR_C_ARRAY_INIT;
250 hash.Version = 2;
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));
254 }
255
256 return status;
257}
258
259static void fuzz_ntlm_set_input(SecBuffer* buffer, BOOL* haveInputBuffer, const uint8_t* data,
260 size_t size)
261{
262 WINPR_ASSERT(buffer);
263 WINPR_ASSERT(haveInputBuffer);
264
265 buffer[0].BufferType = SECBUFFER_TOKEN;
266 buffer[0].pvBuffer = (void*)data;
267 buffer[0].cbBuffer = (ULONG)size;
268 *haveInputBuffer = TRUE;
269}
270
271static void fuzz_ntlm_negotiate(const uint8_t* data, size_t size)
272{
273 FUZZ_NTLM_SERVER server = WINPR_C_ARRAY_INIT;
274
275 if (!fuzz_ntlm_server_init(&server))
276 goto fail;
277
278 fuzz_ntlm_set_input(server.inputBuffer, &server.haveInputBuffer, data, size);
279 (void)fuzz_ntlm_server_step(&server);
280
281fail:
282 fuzz_ntlm_server_uninit(&server);
283}
284
285static void fuzz_ntlm_challenge(const uint8_t* data, size_t size)
286{
287 FUZZ_NTLM_CLIENT client = WINPR_C_ARRAY_INIT;
288
289 if (!fuzz_ntlm_client_init(&client))
290 goto fail;
291
292 if (IsSecurityStatusError(fuzz_ntlm_client_step(&client)))
293 goto fail;
294
295 fuzz_ntlm_set_input(client.inputBuffer, &client.haveInputBuffer, data, size);
296 (void)fuzz_ntlm_client_step(&client);
297
298fail:
299 fuzz_ntlm_client_uninit(&client);
300}
301
302static void fuzz_ntlm_authenticate(const uint8_t* data, size_t size)
303{
304 FUZZ_NTLM_CLIENT client = WINPR_C_ARRAY_INIT;
305 FUZZ_NTLM_SERVER server = WINPR_C_ARRAY_INIT;
306
307 if (!fuzz_ntlm_client_init(&client))
308 goto fail;
309 if (!fuzz_ntlm_server_init(&server))
310 goto fail;
311
312 if (fuzz_ntlm_client_step(&client) != SEC_I_CONTINUE_NEEDED)
313 goto fail;
314
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)
318 goto fail;
319
320 fuzz_ntlm_set_input(server.inputBuffer, &server.haveInputBuffer, data, size);
321 (void)fuzz_ntlm_server_step(&server);
322
323fail:
324 fuzz_ntlm_client_uninit(&client);
325 fuzz_ntlm_server_uninit(&server);
326}
327
328int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
329{
330 static BOOL loggingInitialized = FALSE;
331
332 if (!loggingInitialized)
333 {
334 (void)WLog_SetLogLevel(WLog_GetRoot(), WLOG_TRACE);
335 loggingInitialized = TRUE;
336 }
337
338 if (size < 2)
339 return 0;
340 if (size > (1u << 20))
341 return 0;
342
343 switch (data[0] % 3)
344 {
345 case 0:
346 fuzz_ntlm_negotiate(data + 1, size - 1);
347 break;
348 case 1:
349 fuzz_ntlm_challenge(data + 1, size - 1);
350 break;
351 case 2:
352 fuzz_ntlm_authenticate(data + 1, size - 1);
353 break;
354 default:
355 break;
356 }
357
358 return 0;
359}