idnits 2.17.1 draft-dashevskyi-dnsrr-antipatterns-00.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- == The page length should not exceed 58 lines per page, but there was 1 longer page, the longest (page 1) being 618 lines Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- No issues found here. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (March 23, 2021) is 1129 days in the past. Is this intentional? Checking references for intended status: Informational ---------------------------------------------------------------------------- -- Looks like a reference, but probably isn't: '255' on line 347 -- Obsolete informational reference (is this intentional?): RFC 6982 (ref. 'RFC6895') (Obsoleted by RFC 7942) Summary: 0 errors (**), 0 flaws (~~), 2 warnings (==), 3 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 1 Independent Submission S. Dashevskyi 2 Internet-Draft D. dos Santos 3 Intended status: Informational J. Wetzels 4 Expires: September 23, 2021 A. Amri 5 Forescout Technologies 6 March 23, 2021 8 Common implementation anti-patterns related 9 to Domain Name System (DNS) resource record (RR) processing 10 draft-dashevskyi-dnsrr-antipatterns-00 12 Abstract 14 This memo describes common vulnerabilities related to Domain Name 15 System (DNS) response record (RR) processing as seen in several DNS 16 client implementations. These vulnerabilities may lead to successful 17 Denial-of-Service and Remote Code Execution attacks against the 18 affected software. Where applicable, violations of RFC 1035 are 19 mentioned. 21 Status of This Memo 23 This Internet-Draft is submitted in full conformance with the 24 provisions of BCP 78 and BCP 79. 26 Internet-Drafts are working documents of the Internet Engineering 27 Task Force (IETF). Note that other groups may also distribute 28 working documents as Internet-Drafts. The list of current Internet- 29 Drafts is at https://datatracker.ietf.org/drafts/current/. 31 Internet-Drafts are draft documents valid for a maximum of six months 32 and may be updated, replaced, or obsoleted by other documents at any 33 time. It is inappropriate to use Internet-Drafts as reference 34 material or to cite them other than as "work in progress." 36 This Internet-Draft will expire on September 23, 2021. 38 Copyright Notice 40 Copyright (c) 2021 IETF Trust and the persons identified as the 41 document authors. All rights reserved. 43 This document is subject to BCP 78 and the IETF Trust's Legal 44 Provisions Relating to IETF Documents 45 (http://trustee.ietf.org/license-info) in effect on the date of 46 publication of this document. Please review these documents 47 carefully, as they describe your rights and restrictions with respect 48 to this document. 50 Table of Contents 52 1. Introduction 53 2. Compression Pointer and Offset Validation 54 2.1. Compression Pointer Pointing Out of Bounds 55 2.2. Compression Pointer Loops 56 2.3. Invalid Compression Pointer Check 57 3. Label and Name Length Validation 58 4. NULL-terminator Placement Validation 59 5. Response Data Length Validation 60 6. Record Count Validation 61 7. General Recommendations 62 7.1. Compression Pointer 63 7.2. Name, Label, and Resource Record Lengths 64 7.3. Resource Record Count Fields 65 8. Security Considerations 66 9. IANA Considerations 67 10. References 68 10.1. Normative References 69 10.2. Informative References 70 Acknowledgements 71 Authors' Addresses 73 1. Introduction 75 Recently, there have been major vulnerabilities on DNS 76 implementations that raised attention to this protocol as an 77 important attack vector, such as CVE-2020-1350, known as "SIGRed", 78 CVE-2020-2705, known as "SAD DNS", and "DNSpooq", a set of 7 critical 79 issues affecting the DNS forwarder "dnsmasq" 80 (). 82 The authors of this memo have analyzed the DNS client implementations 83 of several major TCP/IP protocol stacks and found a set of 84 vulnerabilities that share common implementation flaws 85 (anti-patterns). These flaws are related to processing DNS RRs 86 (discussed in [RFC1035]) and may lead to critical security 87 vulnerabilities. 89 While implementation flaws may differ from one software project to 90 another, these anti-patterns are highly likely to span across 91 multiple implementations. In fact, one of the first CVEs related to 92 one of the anti-patters (CVE-2000-0333) dates back to the year 2000. 93 The affected software is not limited to DNS client implementations, 94 and any software that attempts to process DNS RRs may be affected, 95 such as firewalls, intrusion detection systems, or general purpose 96 DNS packet dissectors (i.e., Wireshark). 98 [COMP-DRAFT] and [RFC5625] briefly mention some of these 99 anti-patterns, but the main purpose of this memo is to provide 100 technical details behind these anti-patterns, so that the common 101 mistakes can be eradicated. 103 2. Compression Pointer and Offset Validation 105 [RFC1035] defines the DNS message compression scheme that can be used 106 to reduce the size of messages. When it is used, an entire domain 107 name or several name labels are replaced with a (compression) pointer 108 to a prior occurrence of the same name. 110 The compression pointer is a combination of two octets: the two most 111 significant bits are set to 1, and the remaining 14 bits are the 112 OFFSET field. This field specifies the offset from the beginning of 113 the DNS header, at which another domain name or label is located: 115 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 116 | 1 1| OFFSET | 117 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 119 The message compression scheme explicitly allows a domain name to be 120 represented as: (1) a sequence of unpacked labels ending with a zero 121 octet; (2) a pointer; (3) a sequence of labels ending with a pointer. 123 However, [RFC1035] does not explicitly state that blindly following 124 compression pointers of any kind can be harmful [COMP-DRAFT], as the 125 authors could not have had any assumptions about various 126 implementations that would follow. 128 Yet, any DNS packet parser that attempts to uncompress domain names 129 without validating the value of OFFSET is likely susceptible to 130 memory corruption bugs and buffer overruns. These bugs allow for easy 131 Denial-of-Service attacks, and may result in successful Remote Code 132 Execution attacks. 134 Pseudocode that illustrates typical domain name parsing 135 implementations is shown below (Snippet 1): 137 1:uncompress_domain_name(*name, *dns_payload) { 138 2: 139 3: name_buffer[255]; 140 4: copy_offset = 0; 141 5: 142 6: label_len_octet = name; 143 7: dest_octet = name_buffer; 144 8: 145 9: while (*label_len_octet != 0x00) { 146 10: 147 11: if (is_compression_pointer(*label_len_octet)) { 148 12: ptr_offset = get_offset(label_len_octet, 149 label_len_octet+1); 150 13: label_len_octet = dns_payload + ptr_offset + 1; 151 14: } 152 15: 153 16: else { 154 17: length = *label_len_octet; 155 18: copy(dest_octet + copy_offset, 156 label_len_octet+1, *length); 157 19: 158 20: copy_offset += length; 159 21: label_len_octet += length + 1; 160 22: } 161 23: 162 24: } 163 25:} 164 Snippet 1 - A typical implementation of a function 165 that is used for uncompressing DNS domain names (pseudocode) 167 Such implementations typically have a dedicated function for 168 uncompressing domain names. Among other parameters, these functions 169 may accept a pointer to the beginning of the first name label within 170 a RR ("name") and a pointer to the beginning of the DNS payload to be 171 used as a starting point for the compression pointer ("dns_payload"). 172 The destination buffer for the domain name ("name_buffer") is 173 typically limited to 255 bytes as per [RFC1035] and can be allocated 174 either in the stack or in the heap memory region. 176 The code of the function at Snippet 1 reads the domain name 177 label-by-label from a RR until it reaches the NULL octet (0x00) that 178 signifies the end of a domain name. If the current label length octet 179 ("label_len_octet") is a compression pointer, the code extracts the 180 value of the compression offset and uses it to "jump" to another 181 label length octet. If the current label length octet is not a 182 compression pointer, the label bytes will be copied into the name 183 buffer, and the number of bytes copied will correspond to the value 184 of the current label length octet. After the copy operation, the code 185 will move on to the next label length octet. 187 There are multiple issues with this implementation. In this Section 188 we discuss the issues related to the handling of compression 189 pointers. 191 The first issue is due to unchecked compression offset values. The 192 second issue is due to the absence of checks that ensure that a 193 pointer will eventually arrive at an uncompressed domain label. We 194 describe these issues in more detail below. 196 2.1 Compression Pointer Pointing Out of Bounds 198 [RFC1035] states that "... [compression pointer is] a pointer to a 199 prior occurrence of the same name". Also, according to [RFC1035], 200 the maximum size of DNS packets that can be sent over the UDP 201 protocol is limited to 512 octets. 203 The pseudocode at Snippet 1 violates these constraints, as it will 204 accept a compression pointer that forces the code to read out of the 205 bounds of a DNS packet. For instance, the compression pointer of 206 0xffff will produce the offset of 16383 octets, which is most 207 definitely pointing to a label length octet somewhere past the 208 original DNS packet. Supplying such offset values will most likely 209 cause memory corruption issues and may lead to Denial-of-Service 210 conditions (e.g., a NULL pointer dereference after "label_len_octet" 211 is set to an invalid address in memory). 213 2.2 Compression Pointer Loops 215 The pseudocode at Snippet 1 allows for jumping from a compression 216 pointer to another compression pointer and it does not restricts the 217 number of such jumps. That is, if a label length octet which is 218 currently being parsed is a compression pointer, the code will 219 perform a jump to another label, and if that other label is a 220 compression pointer as well, the code will perform another jump, and 221 so forth until it reaches an uncompressed label. This may lead to 222 unforeseen side-effects that result in security issues. 224 Consider the excerpt from a DNS packet illustrated below: 226 +----+----+----+----+----+----+----+----+----+----+----+----+ 227 +0x00 | ID | FLAGS | QCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | 228 +----+----+----+----+----+----+----+----+----+----+----+----+ 229 ->+0x0c |0xc0|0x0c| TYPE | CLASS |0x04| t | e | s | t |0x03| 230 | +----+--|-+----+----+----+----+----+----+----+----+----+----+ 231 | +0x18 | c | o| | m |0x00| TYPE | CLASS | ................ | 232 | +----+--|-+----+----+----+----+----+----+----+----+----+----+ 233 | | 234 ---------------- 236 The packet begins with a DNS header at the offset +0x00, and its DNS 237 payload contains several RRs. The first RR begins at the offset of 12 238 octets (+0xc0) and its first label length octet is set to the value 239 "0xc0", which indicates that it is a compression pointer. The 240 compression pointer offset is computed from the two octets "0xc00c" 241 and it is equal to 12. Since the implementation at Snippet 1 follows 242 this offset value blindly, the pointer will jump back to the first 243 octet of the first RR (+0xc0) over and over again. The code at 244 Snippet 1 will enter an infinite loop state, since it will never 245 leave the "TRUE" branch of the "while" loop. 247 Apart from achieving infinite loops, the implementation flaws at 248 Snippet 1 make it possible to achieve various pointer loops that have 249 different effects. For instance, consider the DNS packet excerpt 250 shown below: 252 +----+----+----+----+----+----+----+----+----+----+----+----+ 253 +0x00 | ID | FLAGS | QCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | 254 +----+----+----+----+----+----+----+----+----+----+----+----+ 255 ->+0x0c |0x04| t | e | s | t |0xc0|0x0c| ...................... | 256 | +----+----+----+----+----+----+--|-+----+----+----+----+----+ 257 | | 258 ----------------------------------------- 260 With such a domain name, the implementation at Snippet 1 will first 261 copy the domain label at the offset 0xc0 ("test"), then it will fetch 262 the next label length octet, which is a compression pointer (0xc0). 263 The compression pointer offset is computed from the two octets 264 "0xc00c" and is equal to 12 octets. The code will jump back at the 265 offset 0xc0 where the first label "test" is located. The code will 266 again copy the "test" label, and jump back to it, following the 267 compression pointer, over and over again. 269 Snippet 1 does not contain any logic that restricts multiple jumps 270 from the same compression pointer and does not ensure that no more 271 than 255 octets are copied into the name buffer ("name_buffer"). In 272 fact, the code will continue to write the label "test" into it, 273 overwriting the name buffer and the stack of the heap metadata. In 274 fact, attackers would have a significant degree of freedom in 275 constructing shell-code, since they can create arbitrary copy chains 276 with various combinations of labels and compression pointers. 278 Therefore, blindly following compression pointers may not only lead 279 to Denial-of-Service as pointed by [COMP-DRAFT], but also to 280 successful Remote Code Execution attacks, as there may be other 281 implementation issues present within the corresponding code. 283 2.3 Invalid compression pointer check 285 Some implementations may not follow [RFC1035], which states: "the 286 first two bits [of a compression pointer octet] are ones; this allows 287 a pointer to be distinguished from a label, the label must begin 288 with two zero bits because labels are restricted to 63 octets or less 289 (the 10 and 01 combinations are reserved for future use)". Snippets 2 290 and 3 show pseudocode that implements two functions that check 291 whether a given octet is a compression pointer: correct and incorrect 292 implementations respectively. 294 1: unsigned char is_compression_pointer(*octet) { 295 2: if ((*octet & 0xc0) == 0xc0) 296 3: return true; 297 4: } else { 298 5: return false; 299 6: } 300 7: } 301 Snippet 2 - Correct compression pointer check 303 1: unsigned char is_compression_pointer(*octet) { 304 2: if (*octet & 0xc0) { 305 3: return true; 306 4: } else { 307 5: return false; 308 6: } 309 7: } 310 Snippet 3 - Incorrect compression pointer check 312 The correct implementation (Snippet 2) ensures that the two most 313 significant bits of an octet are both set, while the incorrect 314 implementation (Snippet 3) would consider an octet with only one of 315 the two bits set as a compression pointer. This is likely an 316 implementation mistake rather than an intended violation of 317 [RFC1035], because there are no benefits in supporting such 318 compression pointer values. 320 While incorrect implementations alone do not lead to vulnerabilities, 321 they may have unforeseen side-effects when combined with other 322 vulnerabilities. For instance, the first octet of the value "0x4130" 323 represents an invalid label length (65) which is larger than 63 (as 324 per [RFC1035]) and a packet that has this value should be discarded. 325 However, the function shown on Snippet 3 will consider "0x41" to be a 326 valid compression pointer, and the packet may pass the validation 327 steps. 329 This might give an additional leverage for attackers in constructing 330 payloads and circumventing the existing DNS packet validation 331 mechanisms. 333 3. Label and Name Length Validation 335 [RFC1035] restricts the length of name labels to 63 octets, and 336 lengths of domain names to 255 octets. Some implementations do not 337 explicitly enforce these restrictions. 339 Consider the pseudocode function "copy_domain_name()" shown on 340 Snippet 4 below. The function is a variant of the 341 "uncompress_domain_name" function (Snippet 1), with the difference 342 that it does not support compressed labels, and copies only 343 uncompressed labels into the name buffer. 345 1:copy_domain_name(*name, *dns_payload) { 346 2: 347 3: name_buffer[255]; 348 4: copy_offset = 0; 349 5: 350 6: label_len_octet = name; 351 7: dest_octet = name_buffer; 352 8: 353 9: while (*label_len_octet != 0x00) { 354 10: 355 11: if (is_compression_pointer(*label_len_octet)) { 356 12: length = 2; 357 13: label_len_octet += length + 1; 358 14: } 359 15: 360 16: else { 361 17: length = *label_len_octet; 362 18: copy(dest_octet + copy_offset, 363 label_len_octet+1, *length); 364 19: 365 20: copy_offset += length; 366 21: label_len_octet += length + 1; 367 22: } 368 23: 369 24: } 370 25:} 371 Snippet 4 - A typical implementation of a function 372 that is used for copying non-compressed domain names (pseudocode) 374 This implementation does not explicitly check for the value of the 375 label length octet: this value can be up to 255 octets, and a single 376 label can fill the name buffer. Depending on the memory layout of the 377 target, how the name buffer is allocated, and the size of the 378 malformed packet, it is possible to trigger various memory corruption 379 issues. 381 Both Snippets 1 and 4 restrict the size of the name buffer to 255 382 octets, however there are no restrictions on the actual number of 383 octets that will be copied into this buffer. In this particular case, 384 a subsequent copy operation (if another label is present in the 385 packet) will write past the name buffer, allowing to overwrite heap 386 or stack metadata in a controlled manner. 388 4. NULL-terminator Placement Validation 390 A domain name must end with a NULL (0x00) octet, as per [RFC1035]. 391 The implementations shown at Snippets 1 and 4 assume that this is the 392 case for the RRs that they process, however names that do not have a 393 NULL octet placed at the proper position within a RR are not 394 discarded. 396 This issue is closely related to the absence of label and name length 397 checks. For example, the logic behind Snippets 1 and 4 will continue 398 to copy octets into the name buffer, until a NULL octet is 399 encountered. This octet can be placed at an arbitrary position 400 within a RR, or not placed at all. 402 Consider a pseudocode function shown on Snippet 5. The function 403 returns the length of a domain name ("name") in octets to be used 404 elsewhere (e.g., to allocate a name buffer of a certain size): for 405 compressed domain names the function returns 2, for uncompressed 406 names it returns their true length using the "strlen()" function. 408 1: get_name_length(*name) { 409 2: 410 3: if (is_compression_pointer(name)) 411 4: return 2; 412 5: 413 6: name_len = strlen(name) + 1; 414 7: return name_len; 415 8: } 416 Snippet 5 - A function that returns the length of a domain name 418 "strlen()" is a standard C library function that returns the length 419 of a given sequence of characters terminated by the NULL (0x00) 420 octet. Since this function also expects names to be explicitly 421 NULL-terminated, the return value "strlen()" may be also controlled 422 by attackers. Through the value of "name_len" attackers may control 423 the allocation of internal buffers, or specify the number by octets 424 copied into these buffers, or other operations depending on the 425 implementation specifics. 427 The absence of explicit checks for the NULL octet placement may also 428 facilitate controlled memory reads and writes. 430 5. Response Data Length Validation 432 As stated in [RFC1035], every RR contains a variable length string of 433 octets that contains the retrieved resource data (RDATA) (e.g., an IP 434 address that corresponds to a domain name in question). The length of 435 the RDATA field is regulated by the resource data length field 436 (RDLENGTH), that is also present in an RR. 438 Implementations that process RRs may not check for the validity of 439 the RDLENGTH field value, when retrieving RDATA. Failing to do so may 440 lead to out-of-bound read issues (similarly to the label and name 441 length validation issues discussed in Section 3), whose impact may 442 vary significantly depending on the implementation specifics. The 443 authors observed instances of Denial-of-Service conditions and 444 information leaks. 446 6. Record Count Validation 448 According to [RFC1035], the DNS header contains four two-octet 449 fields that specify the amound of question records (QDCOUNT), answer 450 records (ANCOUNT), authority records (NSCOUNT), and additional 451 records (ARCOUNT). 453 1: process_dns_records(dns_header, ...) { 454 // ... 455 2: num_answers = dns_header->ancount 456 3: data_ptr = dns_header->data 457 4: 458 5: while (num_answers > 0) { 459 6: name_length = get_name_length(data_ptr); 460 7: data_ptr += name_length + 1; 461 8: 462 9: answer = (struct dns_answer_record *)data_ptr; 463 10: 464 11: // process the answer record 465 12: 466 13: --num_answers; 467 14: } 468 // ... 469 15: } 470 Snippet 6 - A RR processing function 472 Snippet 6 illustrates a recurring implementation anti-pattern for a 473 function that processes DNS RRs. The function "process_dns_records()" 474 extracts the value of ANCOUNT ("num_answers") and the pointer to the 475 DNS data payload ("data_ptr"). The function processes answer records 476 in a loop decrementing the "num_answers" value after processing each 477 record, until the value of "num_answers" becomes zero. For 478 simplicity, we assume that there is only one domain name per answer. 479 Inside the loop, the code calculates the domain name length 480 "name_length", and adjusts the data payload pointer "data_ptr" by the 481 offset that corresponds to "name_length + 1", so that the pointer 482 lands on the first answer record. Next, the answer record is 483 retrieved and processed, and the "num_answers" value is decremented. 485 If the ANCOUNT number retrieved from the header 486 ("dns_header->ancount") is not checked against the amount of data 487 available in the packet and it is, e.g., larger than the number of 488 answer records available, the data pointer "data_ptr" will read out 489 of the bounds of the packet. This may result in Denial-of-Service 490 conditions. 492 In this section, we used an example of processing answer records. 493 However, the same logic is often reused for processing other types of 494 records. Therefore all record count fields must be checked before 495 parsing the contents of a packet. [RFC5625] recommends that DNS 496 packets with wrong RR count fields should be dropped. 498 7. General Recommendations 500 7.1. Compression Pointer 502 A compression pointer (a byte with the 2 highest bits set to 1) must 503 resolve to a byte within a DNS record with the value that is greater 504 than 0 (i.e., it must not be a NULL terminator) and less than 64. The 505 offset at which this byte is located must be smaller than the offset 506 at which the compression pointer is located. There is no valid reason 507 for nesting compression pointers. The code that implements domain 508 name parsing should check the offset not only with respect to the 509 bounds of a packet, but also its position with respect to the 510 compression pointer in question. A compression pointer must not be 511 "followed" more than once. This might be difficult to implement 512 within the logic of TCP/IP stacks, as the authors have seen several 513 implementations using a check that ensures that a compression pointer 514 is not followed more than several times. While this is not a perfect 515 solution, it may still be a practical one. 517 7.2 Name, Label, and Resource Record Lengths 519 A domain name length byte must have the value of more than 0 and less 520 than 64 ([RFC1035]). If this is not the case, an invalid value has 521 been provided within the packet, or a value at an invalid position 522 might be interpreted as a domain name length due to other errors in 523 the packet (e.g., misplaced NULL terminator or invalid compression 524 pointer). The characters of the domain label allowed for Internet 525 hosts must strictly conform to [RFC1035], and the number of domain 526 label characters must correspond to the value of the domain label 527 byte. The domain name length must not be more than 255 bytes, 528 including the size of uncompressed domain names. The NULL octet 529 (0x00) must be present at the end of the domain name, and within the 530 maximum name length (255 octets). 532 The value of the data length byte in response DNS records (RDLENGTH) 533 must reflect the number of bytes available in the field that 534 describes the resource (RDATA). The format of RDATA must conform to 535 the TYPE and CLASS fields of the RR. 537 7.3 Resource Record Count Fields 539 The values of the bytes within a DNS header that reflect the number 540 of Question (QCOUNT), Answer (ANCOUNT), Authority (NSCOUNT) and 541 Additional (ARCOUNT) must correspond to the actual data present 542 within the packet. The packets with with invalid RR counts must be 543 discarded, in accordance with [RFC5625]. 545 8. Security Considerations 547 Security issues are discussed throughout this memo. 549 9. IANA Considerations 551 This document introduces no new IANA considerations. Please see 552 [RFC6895] for a complete review of the IANA considerations 553 introduced by DNS. 555 10. References 557 10.1 Normative References 559 [RFC1035] Mockapetris, P., "Domain names - implementation and 560 specification", RFC 1035, November 1987, 561 . 563 10.2 Informative References 565 [COMP-DRAFT] Koch, P., "A New Scheme for the Compression of 566 Domain Names", Internet-Draft, draft-ietf-dnsind-local- 567 compression-05, June 1999, Work in progress, 568 . 571 [RFC5625] Bellis, R., "DNS Proxy Implementation Guidelines", RFC 572 5625, August 2009, 573 . 575 [RFC6895] Eastlake 3rd, D., "Domain Name System (DNS) IANA 576 Considerations", RFC 6895, April 2013, 577 . 579 Acknowledgements 581 We would like to thank Shlomi Oberman, who has greatly contributed to 582 the research that led to this document. 584 Authors' Addresses 586 Stanislav Dashevskyi 587 Forescout Technologies 588 John F. Kennedylaan, 2 589 Eindhoven, 5612AB 590 The Netherlands 592 Email: stanislav.dashevskyi@forescout.com 594 Daniel dos Santos 595 Forescout Technologies 596 John F. Kennedylaan, 2 597 Eindhoven, 5612AB 598 The Netherlands 600 Email: daniel.dossantos@forescout.com 602 Jos Wetzels 603 Forescout Technologies 604 John F. Kennedylaan, 2 605 Eindhoven, 5612AB 606 The Netherlands 608 Email: jos.wetzels@forescout.com 610 Amine Amri 611 Forescout Technologies 612 John F. Kennedylaan, 2 613 Eindhoven, 5612AB 614 The Netherlands 616 Email: amine.amri@forescout.com