Skip to content

Commit 3a76fd7

Browse files
guyharrisinfrastation
authored andcommitted
CVE-2017-12995/Check for DNS compression pointers that don't point backwards.
This is what BIND 9.11.0-P2 does; it not only detects pointers that loop, as "point backwards" means "point before anything we've processed so far, including what we're processing right now", so the pointer can't point to itself (as that's what we're processing right now). This fixes an infinite loop discovered by Forcepoint's security researchers Otto Airamo & Antti Levomäki. Add a test using the capture file supplied by the reporter(s). Also, add some infinite-pointer-loop captures. More checks should be done. We might, for example, want to make sure the upper 2 bits of the label length/pointer byte are 00 or 11, and that if we encounter a pointer and jump backwards to what we think is a label the label ends before the beginning of the last label we processed, to make sure the pointer doesn't point backwards into the *middle* of a label, and also make sure the entire name is <= 255 bytes long.
1 parent 866c602 commit 3a76fd7

10 files changed

+33
-18
lines changed

Diff for: print-domain.c

+19-18
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,14 @@ ns_nprint(netdissect_options *ndo,
151151
register u_int i, l;
152152
register const u_char *rp = NULL;
153153
register int compress = 0;
154-
int chars_processed;
155154
int elt;
156-
int data_size = ndo->ndo_snapend - bp;
155+
u_int offset, max_offset;
157156

158157
if ((l = labellen(ndo, cp)) == (u_int)-1)
159158
return(NULL);
160159
if (!ND_TTEST2(*cp, 1))
161160
return(NULL);
162-
chars_processed = 1;
161+
max_offset = (u_int)(cp - bp);
163162
if (((i = *cp++) & INDIR_MASK) != INDIR_MASK) {
164163
compress = 0;
165164
rp = cp + l;
@@ -174,24 +173,28 @@ ns_nprint(netdissect_options *ndo,
174173
}
175174
if (!ND_TTEST2(*cp, 1))
176175
return(NULL);
177-
cp = bp + (((i << 8) | *cp) & 0x3fff);
176+
offset = (((i << 8) | *cp) & 0x3fff);
177+
/*
178+
* This must move backwards in the packet.
179+
* No RFC explicitly says that, but BIND's
180+
* name decompression code requires it,
181+
* as a way of preventing infinite loops
182+
* and other bad behavior, and it's probably
183+
* what was intended (compress by pointing
184+
* to domain name suffixes already seen in
185+
* the packet).
186+
*/
187+
if (offset >= max_offset) {
188+
ND_PRINT((ndo, "<BAD PTR>"));
189+
return(NULL);
190+
}
191+
max_offset = offset;
192+
cp = bp + offset;
178193
if ((l = labellen(ndo, cp)) == (u_int)-1)
179194
return(NULL);
180195
if (!ND_TTEST2(*cp, 1))
181196
return(NULL);
182197
i = *cp++;
183-
chars_processed++;
184-
185-
/*
186-
* If we've looked at every character in
187-
* the message, this pointer will make
188-
* us look at some character again,
189-
* which means we're looping.
190-
*/
191-
if (chars_processed >= data_size) {
192-
ND_PRINT((ndo, "<LOOP>"));
193-
return (NULL);
194-
}
195198
continue;
196199
}
197200
if ((i & INDIR_MASK) == EDNS0_MASK) {
@@ -212,14 +215,12 @@ ns_nprint(netdissect_options *ndo,
212215
}
213216

214217
cp += l;
215-
chars_processed += l;
216218
ND_PRINT((ndo, "."));
217219
if ((l = labellen(ndo, cp)) == (u_int)-1)
218220
return(NULL);
219221
if (!ND_TTEST2(*cp, 1))
220222
return(NULL);
221223
i = *cp++;
222-
chars_processed++;
223224
if (!compress)
224225
rp += l + 1;
225226
}

Diff for: tests/TESTLIST

+9
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ zephyr-oobr zephyr-oobr.pcap zephyr-oobr.out -vvv -e
474474
isakmp-no-none-np isakmp-no-none-np.pcap isakmp-no-none-np.out -vvv -e
475475
telnet-iac-check-oobr telnet-iac-check-oobr.pcap telnet-iac-check-oobr.out -vvv -e
476476
resp_4_infiniteloop resp_4_infiniteloop.pcap resp_4_infiniteloop.out -vvv -e
477+
dns_fwdptr dns_fwdptr.pcap dns_fwdptr.out -vvv -e
477478

478479
# RTP tests
479480
# fuzzed pcap
@@ -483,3 +484,11 @@ rtp-seg-fault-2 rtp-seg-fault-2.pcap rtp-seg-fault-2.out -v -T rtp
483484
# NFS tests
484485
# fuzzed pcap
485486
nfs-seg-fault-1 nfs-seg-fault-1.pcap nfs-seg-fault-1.out
487+
488+
# DNS infinite loop tests
489+
#
490+
# See http://marc.info/?l=tcpdump-workers&m=95552439022555
491+
#
492+
dns-zlip-1 dns-zlip-1.pcap dns-zlip-1.out
493+
dns-zlip-2 dns-zlip-2.pcap dns-zlip-2.out
494+
dns-zlip-3 dns-zlip-3.pcap dns-zlip-3.out

Diff for: tests/dns-zlip-1.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
IP 10.0.0.1.1024 > 146.84.28.88.53: 60777 Type49159 (Class 49168)? <BAD PTR>[|domain]

Diff for: tests/dns-zlip-1.pcap

117 Bytes
Binary file not shown.

Diff for: tests/dns-zlip-2.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
IP 10.0.0.1.1024 > 146.84.28.88.53: 18992 Type49164 (Class 49168)? <BAD PTR>[|domain]

Diff for: tests/dns-zlip-2.pcap

117 Bytes
Binary file not shown.

Diff for: tests/dns-zlip-3.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
IP 10.0.0.1.1024 > 146.84.28.88.53: 65483 Type49164 (Class 49164)? thisleetostringwillcrashyourlittlenameserverforsurehahahahahah.<BAD PTR>[|domain]

Diff for: tests/dns-zlip-3.pcap

187 Bytes
Binary file not shown.

Diff for: tests/dns_fwdptr.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
be:af:ca:ce:ff:ff > de:ad:be:ef:00:01, ethertype IPv4 (0x0800), length 63207: (tos 0x0, ttl 128, id 36039, offset 0, flags [none], proto UDP (17), length 63193)
2+
156.118.17.235.53 > 156.118.27.229.500: [udp sum ok] 51584 zoneRef NoChange*|$ [64259q] q: Type507 (Class 769)? M-{.^AM-{^C.M-{.^AM-{^C.M-{.^AM-{^C.M-{.^AM-{^C.M-{.^AM-{ .M-{^C^A.<BAD PTR>[|domain]

Diff for: tests/dns_fwdptr.pcap

61.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)