2 Fuzz access check using SDDL strings and a known token
3 Copyright (C) Catalyst IT 2023
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "libcli/security/security.h"
21 #include "libcli/security/conditional_ace.h"
22 #include "libcli/security/claims-conversions.h"
23 #include "lib/util/attr.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "librpc/gen_ndr/ndr_conditional_ace.h"
26 #include "lib/util/bytearray.h"
27 #include "fuzzing/fuzzing.h"
30 static struct security_token token
= {0};
32 static struct dom_sid dom_sid
= {0};
35 * For this one we initialise a security token to have a few claims
36 * and SIDs. The fuzz strings contain SDDL that will be tested against
37 * this token in se_access_check() or sec_access_check_ds() --
38 * supposing they compile.
41 int LLVMFuzzerInitialize(int *argc
, char ***argv
)
44 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
45 struct dom_sid
*sid
= NULL
;
50 const char *claim_sddl
;
60 "{\"unknown\", \"\", \" ←ā\"}"
65 "{\"unknown\", \" \", \" ←ā\"}"
69 "least favourite groups",
70 "{SID(S-1-1-0),SID(S-1-5-3),SID(S-1-57777-333-33-33-2)}"
79 const char * device_sids
[] = {
82 "S-1-2-3-4-5-6-7-8-9",
84 const char * user_sids
[] = {
90 for (i
= 0; i
< ARRAY_SIZE(user_sids
); i
++) {
91 sid
= sddl_decode_sid(mem_ctx
, &user_sids
[i
], NULL
);
95 add_sid_to_array(mem_ctx
, sid
,
100 for (i
= 0; i
< ARRAY_SIZE(device_sids
); i
++) {
101 sid
= sddl_decode_sid(mem_ctx
, &device_sids
[i
], NULL
);
105 add_sid_to_array(mem_ctx
, sid
,
107 &token
.num_device_sids
);
110 for (i
= 0; i
< ARRAY_SIZE(claims
); i
++) {
111 struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
*claim
= NULL
;
112 struct claim_def c
= claims
[i
];
114 claim
= parse_sddl_literal_as_claim(mem_ctx
,
120 add_claim_to_token(mem_ctx
, &token
, claim
, c
.type
);
123 /* we also need a global domain SID */
124 string_to_sid(&dom_sid
, device_sids
[2]);
129 int LLVMFuzzerTestOneInput(const uint8_t *input
, size_t len
)
131 TALLOC_CTX
*mem_ctx
= NULL
;
132 struct security_descriptor
*sd
= NULL
;
133 uint32_t access_desired
;
134 uint32_t access_granted
;
140 access_desired
= PULL_LE_U32(input
+ len
- 4, 0);
143 * check there is a '\0'.
145 * Note this allows double-dealing for the last 4 bytes: they are used
146 * as the access_desired mask (see just above) but also *could* be
147 * part of the sddl string. But this doesn't matter, for three
150 * 1. the desired access mask doesn't usually matter much.
152 * 2. the final '\0' is rarely the operative one. Usually the
153 * effective string ends a long time before the end of the input, and
154 * the tail is just junk that comes along for the ride.
156 * 3. Even if there is a case where the end of the SDDL is part of the
157 * mask, the evolution strategy is very likely to try a different mask,
158 * because it likes to add junk on the end.
160 * But still, you ask, WHY? So that the seeds from here can be shared
161 * back and forth with the fuzz_sddl_parse seeds, which have the same
162 * form of a null-terminated-string-with-trailing-junk. If we started
163 * the loop at `len - 5` instead of `len - 1`, there might be
164 * interesting seeds that are valid there that would fail here. That's
167 for (i
= len
- 1; i
>= 0; i
--) {
176 sddl
= (const char *)input
;
177 mem_ctx
= talloc_new(NULL
);
179 sd
= sddl_decode(mem_ctx
, sddl
, &dom_sid
);
184 #ifdef FUZZ_SEC_ACCESS_CHECK_DS
186 * The sec_access_check_ds() function has two arguments not found in
187 * se_access_check, and also not found in our fuzzing examples.
189 * One is a struct object_tree, which is used for object ACE types.
190 * The other is a SID, which is used as a default if an ACE lacks a
193 sec_access_check_ds(sd
,
200 se_access_check(sd
, &token
, access_desired
, &access_granted
);
204 talloc_free(mem_ctx
);