Mercurial > dropbear
comparison fuzz/fuzz-sshpacketmutator.c @ 1774:833bf9947603
Fuzzing - get rid of "prefix" for streams
Improved packet generation with sshpacketmutator
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 01 Nov 2020 23:44:58 +0800 |
parents | af9ed0815818 |
children | 8179eabe16c9 |
comparison
equal
deleted
inserted
replaced
1773:c3ca130d193a | 1774:833bf9947603 |
---|---|
12 #include "dbutil.h" | 12 #include "dbutil.h" |
13 | 13 |
14 size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); | 14 size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); |
15 | 15 |
16 static const char* FIXED_VERSION = "SSH-2.0-dbfuzz\r\n"; | 16 static const char* FIXED_VERSION = "SSH-2.0-dbfuzz\r\n"; |
17 static const size_t MAX_FUZZ_PACKETS = 500; | 17 static const char* FIXED_IGNORE_MSG = |
18 "\x00\x00\x00\x10\x06\x02\x00\x00\x00\x00\x11\x22\x33\x44\x55\x66"; | |
19 static const unsigned int FIXED_IGNORE_MSG_LEN = 16; | |
20 #define MAX_FUZZ_PACKETS 500 | |
18 /* XXX This might need tuning */ | 21 /* XXX This might need tuning */ |
19 static const size_t MAX_OUT_SIZE = 50000; | 22 static const size_t MAX_OUT_SIZE = 50000; |
20 | 23 |
21 /* Splits packets from an input stream buffer "inp". | 24 /* Splits packets from an input stream buffer "inp". |
22 The initial SSH version identifier is discarded. | 25 The initial SSH version identifier is discarded. |
60 buf_decrpos(inp, 3); | 63 buf_decrpos(inp, 3); |
61 continue; | 64 continue; |
62 } | 65 } |
63 packet_len = MIN(packet_len, inp->len - inp->pos); | 66 packet_len = MIN(packet_len, inp->len - inp->pos); |
64 | 67 |
65 /* Copy to output buffer. We're reusing buffers */ | 68 /* Check the packet length makes sense */ |
66 buffer* new_packet = out_packets[*num_out_packets]; | 69 if (packet_len >= MIN_PACKET_LEN-4) { |
67 (*num_out_packets)++; | 70 /* Copy to output buffer. We're reusing buffers */ |
68 buf_setlen(new_packet, 0); | 71 buffer* new_packet = out_packets[*num_out_packets]; |
69 buf_putint(new_packet, packet_len); | 72 (*num_out_packets)++; |
70 buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len); | 73 buf_setlen(new_packet, 0); |
74 // packet_len doesn't include itself | |
75 buf_putint(new_packet, packet_len); | |
76 buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len); | |
77 } | |
71 buf_incrpos(inp, packet_len); | 78 buf_incrpos(inp, packet_len); |
72 } | 79 } |
73 } | 80 } |
74 | 81 |
75 /* Mutate a packet buffer in-place */ | 82 /* Mutate a packet buffer in-place. |
76 static void buf_llvm_mutate(buffer *buf) { | 83 Returns DROPBEAR_FAILURE if it's too short */ |
84 static int buf_llvm_mutate(buffer *buf) { | |
85 int ret; | |
77 /* Position it after packet_length and padding_length */ | 86 /* Position it after packet_length and padding_length */ |
78 const unsigned int offset = 5; | 87 const unsigned int offset = 5; |
79 if (buf->len < offset) { | 88 buf_setpos(buf, 0); |
80 return; | 89 buf_incrwritepos(buf, offset); |
81 } | |
82 buf_setpos(buf, offset); | |
83 size_t max_size = buf->size - buf->pos; | 90 size_t max_size = buf->size - buf->pos; |
84 size_t new_size = LLVMFuzzerMutate(buf_getwriteptr(buf, max_size), | 91 size_t new_size = LLVMFuzzerMutate(buf_getwriteptr(buf, max_size), |
85 buf->len - buf->pos, max_size); | 92 buf->len - buf->pos, max_size); |
86 buf_setpos(buf, 0); | 93 size_t new_total = new_size + 1 + 4; |
87 buf_putint(buf, new_size); | 94 // Round down to a block size |
88 buf_setlen(buf, offset + new_size); | 95 new_total = new_total - (new_total % dropbear_nocipher.blocksize); |
96 | |
97 if (new_total >= 16) { | |
98 buf_setlen(buf, new_total); | |
99 // Fix up the length fields | |
100 buf_setpos(buf, 0); | |
101 // packet_length doesn't include itself, does include padding_length byte | |
102 buf_putint(buf, new_size+1); | |
103 // always just put minimum padding length = 4 | |
104 buf_putbyte(buf, 4); | |
105 ret = DROPBEAR_SUCCESS; | |
106 } else { | |
107 // instead put a fake packet | |
108 buf_setlen(buf, 0); | |
109 buf_putbytes(buf, FIXED_IGNORE_MSG, FIXED_IGNORE_MSG_LEN); | |
110 ret = DROPBEAR_FAILURE; | |
111 } | |
112 return ret; | |
89 } | 113 } |
90 | 114 |
91 | 115 |
92 /* Persistent buffers to avoid constant allocations */ | 116 /* Persistent buffers to avoid constant allocations */ |
93 static buffer *oup; | 117 static buffer *oup; |
94 static buffer *alloc_packetA; | 118 static buffer *alloc_packetA; |
95 static buffer *alloc_packetB; | 119 static buffer *alloc_packetB; |
96 buffer* packets1[MAX_FUZZ_PACKETS]; | 120 static buffer* packets1[MAX_FUZZ_PACKETS]; |
97 buffer* packets2[MAX_FUZZ_PACKETS]; | 121 static buffer* packets2[MAX_FUZZ_PACKETS]; |
98 | 122 |
99 /* Allocate buffers once at startup. | 123 /* Allocate buffers once at startup. |
100 'constructor' here so it runs before dbmalloc's interceptor */ | 124 'constructor' here so it runs before dbmalloc's interceptor */ |
101 static void alloc_static_buffers() __attribute__((constructor)); | 125 static void alloc_static_buffers() __attribute__((constructor)); |
102 static void alloc_static_buffers() { | 126 static void alloc_static_buffers() { |
120 buf_setlen(alloc_packetA, 0); | 144 buf_setlen(alloc_packetA, 0); |
121 buf_setlen(alloc_packetB, 0); | 145 buf_setlen(alloc_packetB, 0); |
122 buf_setlen(oup, 0); | 146 buf_setlen(oup, 0); |
123 | 147 |
124 unsigned int i; | 148 unsigned int i; |
149 size_t ret_len; | |
125 unsigned short randstate[3] = {0,0,0}; | 150 unsigned short randstate[3] = {0,0,0}; |
126 memcpy(randstate, &Seed, sizeof(Seed)); | 151 memcpy(randstate, &Seed, sizeof(Seed)); |
127 | 152 |
128 // printhex("mutator input", Data, Size); | 153 // printhex("mutator input", Data, Size); |
129 | 154 |
130 /* 0.1% chance straight llvm mutate */ | 155 /* 0.1% chance straight llvm mutate */ |
131 if (nrand48(randstate) % 1000 == 0) { | 156 // if (nrand48(randstate) % 1000 == 0) { |
132 return LLVMFuzzerMutate(Data, Size, MaxSize); | 157 // ret_len = LLVMFuzzerMutate(Data, Size, MaxSize); |
133 } | 158 // // printhex("mutator straight llvm", Data, ret_len); |
159 // return ret_len; | |
160 // } | |
134 | 161 |
135 buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0}; | 162 buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0}; |
136 buffer *inp = &inp_buf; | 163 buffer *inp = &inp_buf; |
137 | 164 |
138 /* Parse packets */ | 165 /* Parse packets */ |
139 unsigned int num_packets = MAX_FUZZ_PACKETS; | 166 unsigned int num_packets = MAX_FUZZ_PACKETS; |
140 buffer **packets = packets1; | 167 buffer **packets = packets1; |
141 fuzz_get_packets(inp, packets, &num_packets); | 168 fuzz_get_packets(inp, packets, &num_packets); |
142 | 169 |
143 if (num_packets == 0) { | 170 if (num_packets == 0) { |
144 // gotta do something | 171 // Make up a packet, writing direct to the buffer |
145 memcpy(Data, FIXED_VERSION, MIN(strlen(FIXED_VERSION), MaxSize)); | 172 inp->size = MaxSize; |
146 return LLVMFuzzerMutate(Data, Size, MaxSize); | 173 buf_setlen(inp, 0); |
174 buf_putbytes(inp, FIXED_VERSION, strlen(FIXED_VERSION)); | |
175 buf_putbytes(inp, FIXED_IGNORE_MSG, FIXED_IGNORE_MSG_LEN); | |
176 // printhex("mutator no input", Data, inp->len); | |
177 return inp->len; | |
147 } | 178 } |
148 | 179 |
149 /* Start output */ | 180 /* Start output */ |
150 /* Put a new banner to output */ | 181 /* Put a new banner to output */ |
151 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); | 182 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); |
155 // These are pointers to output | 186 // These are pointers to output |
156 buffer *out_packetA = NULL, *out_packetB = NULL; | 187 buffer *out_packetA = NULL, *out_packetB = NULL; |
157 buf_setlen(alloc_packetA, 0); | 188 buf_setlen(alloc_packetA, 0); |
158 buf_setlen(alloc_packetB, 0); | 189 buf_setlen(alloc_packetB, 0); |
159 | 190 |
160 /* 5% chance each */ | 191 /* 2% chance each */ |
161 const int optA = nrand48(randstate) % 20; | 192 const int optA = nrand48(randstate) % 50; |
162 if (optA == 0) { | 193 if (optA == 0) { |
163 /* Copy another */ | 194 /* Copy another */ |
164 unsigned int other = nrand48(randstate) % num_packets; | 195 unsigned int other = nrand48(randstate) % num_packets; |
165 out_packetA = packets[other]; | 196 out_packetA = packets[other]; |
197 // printf("copy another %d / %d len %u\n", other, num_packets, out_packetA->len); | |
166 } | 198 } |
167 if (optA == 1) { | 199 if (optA == 1) { |
168 /* Mutate another */ | 200 /* Mutate another */ |
169 unsigned int other = nrand48(randstate) % num_packets; | 201 unsigned int other = nrand48(randstate) % num_packets; |
202 out_packetA = alloc_packetA; | |
170 buffer *from = packets[other]; | 203 buffer *from = packets[other]; |
171 buf_putbytes(alloc_packetA, from->data, from->len); | 204 buf_putbytes(out_packetA, from->data, from->len); |
172 out_packetA = alloc_packetA; | 205 if (buf_llvm_mutate(out_packetA) == DROPBEAR_FAILURE) { |
173 buf_llvm_mutate(out_packetA); | 206 out_packetA = NULL; |
207 } | |
208 // printf("mutate another %d / %d len %u -> %u\n", other, num_packets, from->len, out_packetA->len); | |
174 } | 209 } |
175 | 210 |
176 if (i < num_packets) { | 211 if (i < num_packets) { |
177 int optB = nrand48(randstate) % 10; | 212 int optB = nrand48(randstate) % 100; |
178 if (optB == 1) { | 213 if (optB == 1) { |
179 /* 10% chance of drop */ | 214 /* small chance of drop */ |
180 /* Drop it */ | 215 /* Drop it */ |
181 // printf("%d drop\n", i); | 216 //printf("%d drop\n", i); |
182 } else if (optB <= 6) { | 217 } else { |
183 /* Mutate it, 50% chance */ | 218 /* Odds of modification are proportional to packet position. |
184 // printf("%d mutate\n", i); | 219 First packet has 20% chance, last has 100% chance */ |
185 buffer *from = packets[nrand48(randstate) % num_packets]; | 220 int optC = nrand48(randstate) % 1000; |
186 buf_putbytes(alloc_packetB, from->data, from->len); | 221 int mutate_cutoff = MAX(200, (1000 * (i+1) / num_packets)); |
187 out_packetB = alloc_packetB; | 222 if (optC < mutate_cutoff) { |
188 buf_llvm_mutate(out_packetB); | 223 // // printf("%d mutate\n", i); |
189 } else { | 224 out_packetB = alloc_packetB; |
190 /* Copy as-is */ | 225 buffer *from = packets[i]; |
191 out_packetB = packets[i]; | 226 buf_putbytes(out_packetB, from->data, from->len); |
192 // printf("%d as-is\n", i); | 227 if (buf_llvm_mutate(out_packetB) == DROPBEAR_FAILURE) { |
193 } | 228 out_packetB = from; |
229 } | |
230 // printf("mutate self %d / %d len %u -> %u\n", i, num_packets, from->len, out_packetB->len); | |
231 } else { | |
232 /* Copy as-is */ | |
233 out_packetB = packets[i]; | |
234 // printf("%d as-is len %u\n", i, out_packetB->len); | |
235 } | |
236 } | |
194 } | 237 } |
195 | 238 |
196 if (out_packetA && oup->len + out_packetA->len <= oup->size) { | 239 if (out_packetA && oup->len + out_packetA->len <= oup->size) { |
197 buf_putbytes(oup, out_packetA->data, out_packetA->len); | 240 buf_putbytes(oup, out_packetA->data, out_packetA->len); |
198 } | 241 } |
199 if (out_packetB && oup->len + out_packetB->len <= oup->size) { | 242 if (out_packetB && oup->len + out_packetB->len <= oup->size) { |
200 buf_putbytes(oup, out_packetB->data, out_packetB->len); | 243 buf_putbytes(oup, out_packetB->data, out_packetB->len); |
201 } | 244 } |
202 } | 245 } |
203 | 246 |
204 size_t ret_len = MIN(MaxSize, oup->len); | 247 ret_len = MIN(MaxSize, oup->len); |
205 memcpy(Data, oup->data, ret_len); | 248 memcpy(Data, oup->data, ret_len); |
206 // printhex("mutator done", Data, ret_len); | 249 // printhex("mutator done", Data, ret_len); |
207 return ret_len; | 250 return ret_len; |
208 } | 251 } |
209 | 252 |
223 unsigned int num_packets1 = MAX_FUZZ_PACKETS; | 266 unsigned int num_packets1 = MAX_FUZZ_PACKETS; |
224 fuzz_get_packets(inp1, packets1, &num_packets1); | 267 fuzz_get_packets(inp1, packets1, &num_packets1); |
225 unsigned int num_packets2 = MAX_FUZZ_PACKETS; | 268 unsigned int num_packets2 = MAX_FUZZ_PACKETS; |
226 fuzz_get_packets(inp2, packets2, &num_packets2); | 269 fuzz_get_packets(inp2, packets2, &num_packets2); |
227 | 270 |
271 // fprintf(stderr, "input 1 %u packets\n", num_packets1); | |
272 // printhex("crossover input1", Data1, Size1); | |
273 // fprintf(stderr, "input 2 %u packets\n", num_packets2); | |
274 // printhex("crossover input2", Data2, Size2); | |
275 | |
228 buf_setlen(oup, 0); | 276 buf_setlen(oup, 0); |
229 /* Put a new banner to output */ | 277 /* Put a new banner to output */ |
230 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); | 278 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); |
231 | 279 |
232 for (i = 0; i < num_packets1+1; i++) { | 280 if (num_packets1 == 0 && num_packets2 == 0) { |
233 if (num_packets2 > 0 && nrand48(randstate) % 10 == 0) { | 281 buf_putbytes(oup, FIXED_IGNORE_MSG, FIXED_IGNORE_MSG_LEN); |
234 /* 10% chance of taking another packet at each position */ | 282 } else { |
235 int other = nrand48(randstate) % num_packets2; | 283 unsigned int min_out = MIN(num_packets1, num_packets2); |
236 // printf("inserted other packet %d at %d\n", other, i); | 284 unsigned int max_out = num_packets1 + num_packets2; |
237 buffer *otherp = packets2[other]; | 285 unsigned int num_out = min_out + nrand48(randstate) % (max_out-min_out+1); |
238 if (oup->len + otherp->len <= oup->size) { | 286 |
239 buf_putbytes(oup, otherp->data, otherp->len); | 287 for (i = 0; i < num_out; i++) { |
288 int choose = nrand48(randstate) % (num_packets1 + num_packets2); | |
289 buffer *p = NULL; | |
290 if (choose < num_packets1) { | |
291 p = packets1[choose]; | |
292 } else { | |
293 p = packets2[choose-num_packets1]; | |
240 } | 294 } |
241 } | 295 if (oup->len + p->len <= oup->size) { |
242 if (i < num_packets1) { | 296 buf_putbytes(oup, p->data, p->len); |
243 buffer *thisp = packets1[i]; | |
244 if (oup->len + thisp->len <= oup->size) { | |
245 buf_putbytes(oup, thisp->data, thisp->len); | |
246 } | 297 } |
247 } | 298 } |
248 } | 299 } |
249 | 300 |
250 size_t ret_len = MIN(MaxOutSize, oup->len); | 301 size_t ret_len = MIN(MaxOutSize, oup->len); |
251 memcpy(Out, oup->data, ret_len); | 302 memcpy(Out, oup->data, ret_len); |
303 // printhex("crossover output", Out, ret_len); | |
252 return ret_len; | 304 return ret_len; |
253 } | 305 } |
254 | 306 |