NULL POINTER DEREFERENCE Vulnerability in function get_layer4_v6() – tcpreplay-4.3.1

Loginsoft-2018-1093

February 13, 2019

CVE Number

CVE-2019-8376

CWE

CWE-476: NULL Pointer Dereference

Product Details

tcpreplay is a tool for replaying network traffic from files saved with tcpdump or other tools which write pcap files. Tcpreplay is to resend all packets from the input files at the speed at which they were recorded, or a specified data rate, up to as fast as the hardware is capable.
URL: https://github.com/appneta/tcpreplay.git

Vulnerable Versions

4.3.1

Vulnerability Details

We observed a NULL pointer dereference occurred in function get_layer4_v6 () located at get.c .The same be triggered by sending a crafted pcap file to the tcpreplay-edit binary. It allows an attacker to cause Denial of Service (Segmentation fault) or possibly have unspecified other impact.

SYNOPSIS

We observed in the fix_ipv4_checksums () where this code re-calcs the IP and Layer 4 checksums the Layer 4 header is contiguous in memory after *ip_hdr we’re actually writing to the layer 4 header via the ip_hdr ptr, it consists of parameters, ip_hl = (u_char*)get_layer4_v6(ipv6, len) – (u_char*)data; here it invokes to another function get_layer4_v6 () it returns a pointer to the layer 4 header which is just beyond the IPv6 header and any extension headers or NULL when there is none as in the case of v6 Frag or ESP header. Function is recursive. Here in the line proto = exthdr->ip_nh; where it is unsigned character pointer, pointing to a NULL and it triggers a NULL pointer dereference.

Vulnerable code
case TCPR_IPV6_NH_DESTOPTS:
case TCPR_IPV6_NH_HBH:
dbgx(3, "Going deeper due to extension header 0x%02X", proto);
maxlen = len - (int)((u_char *)ip6_hdr - (u_char *)next);
exthdr = get_ipv6_next(next, maxlen);
proto = exthdr->ip_nh;
next = exthdr;
break;
Analysis

 

GDB OUTPUT:
Program received signal SIGSEGV, Segmentation fault.
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x0 
$rbx : 0x00005555557b7bb8 → 0x0000337330706e65 ("enp0s3"?)
$rcx : 0xfb 
$rdx : 0x334 
$rsp : 0x00007fffffffd8f0 → 0x000000fbffffd940
$rbp : 0x00007fffffffd920 → 0x00007fffffffd990 → 0x00007fffffffd9d0 → 0x00007fffffffda70 → 0x00007fffffffdbc0 → 0x00007fffffffdd10 → 0x00007fffffffdd40 → 0x00007fffffffddd0
$rsi : 0x123 
$rdi : 0x00005555557be236 → 0x6e0000000000cb00
$rip : 0x000055555557674a →  movzx eax, BYTE PTR [rax]
$r8 : 0x2f 
$r9 : 0x00005555557be200 → 0x0000000000000000
$r10 : 0x00005555557b9700 → 0x0000000000000000
$r11 : 0x00007ffff78d6000 →  push r13
$r12 : 0x00007ffff7bbb954 → 0x6800424d30314e45 ("EN10MB"?)
$r13 : 0x00007fffffffe2f0 → 0x000000000000000e
$r14 : 0x0 
$r15 : 0x0 
$eflags: [zero CARRY PARITY adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffd8f0│+0x0000: 0x000000fbffffd940 ← $rsp
0x00007fffffffd8f8│+0x0008: 0x00005555557be20e → 0x0000322ffb000062 ("b"?)
0x00007fffffffd900│+0x0010: 0x0000000000000000
0x00007fffffffd908│+0x0018: 0x000001230000002a ("*"?)
0x00007fffffffd910│+0x0020: 0x00005555557be236 → 0x6e0000000000cb00
0x00007fffffffd918│+0x0028: 0x0000000000000000
0x00007fffffffd920│+0x0030: 0x00007fffffffd990 → 0x00007fffffffd9d0 → 0x00007fffffffda70 → 0x00007fffffffdbc0 → 0x00007fffffffdd10 → 0x00007fffffffdd40 → 0x00007fffffffddd0 ← $rbp
0x00007fffffffd928│+0x0038: 0x00005555555695b0 →  mov rdx, rax
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x55555557673d  call 0x555555576798 
0x555555576742  mov QWORD PTR [rbp-0x8], rax
0x555555576746  mov rax, QWORD PTR [rbp-0x8]
→ 0x55555557674a  movzx eax, BYTE PTR [rax]
0x55555557674d  mov BYTE PTR [rbp-0x19], al
0x555555576750  mov rax, QWORD PTR [rbp-0x8]
0x555555576754  mov QWORD PTR [rbp-0x10], rax
0x555555576758  jmp 0x555555576791 
0x55555557675a  mov eax, 0x0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:get.c+410 ────
405 case TCPR_IPV6_NH_DESTOPTS:
406 case TCPR_IPV6_NH_HBH:
407 dbgx(3, "Going deeper due to extension header 0x%02X", proto);
408 maxlen = len - (int)((u_char *)ip6_hdr - (u_char *)next);
409 exthdr = get_ipv6_next(next, maxlen);
// exthdr=0x00007fffffffd918 → 0x0000000000000000
→ 410 proto = exthdr->ip_nh;
411 next = exthdr;
412 break;
413 
414 /*
415 * Can't handle. Unparsable IPv6 fragment/encrypted data
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "tcpreplay-edit", stopped, reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x55555557674a → get_layer4_v6(ip6_hdr=0x5555557be20e, len=0xfb)
[#1] 0x5555555695b0 → do_checksum(tcpedit=0x5555557b86c0, data=0x5555557be20e "b", proto=0x8, len=0xfb)
[#2] 0x555555565fbc → fix_ipv4_checksums(tcpedit=0x5555557b86c0, pkthdr=0x7fffffffdb50, ip_hdr=0x5555557be20e)
[#3] 0x555555564991 → tcpedit_packet(tcpedit=0x5555557b86c0, pkthdr=0x7fffffffdac0, pktdata=0x7fffffffdab0, direction=TCPR_DIR_C2S)
[#4] 0x55555555c589 → send_packets(ctx=0x5555557aa260, pcap=0x5555557ba860, idx=0x0)
[#5] 0x555555563169 → replay_file(ctx=0x5555557aa260, idx=0x0)
[#6] 0x555555562a1b → tcpr_replay_index(ctx=0x5555557aa260)
[#7] 0x555555562341 → tcpreplay_replay(ctx=0x5555557aa260)
[#8] 0x55555555f112 → main(argc=0x1, argv=0x7fffffffe360)


gef➤  p exthdr->ip_nh
Cannot access memory at address 0x0
Tested environment

64-bit ubuntu 16.04 LTS

Proof of Concept

tcpreplay-edit -r 80:84 -s 20 -b -C -m 1500 -P --oneatatime -i $INTERFACE $POC

Timeline

Vendor Disclosure: 07-02-2019
Public Disclosure: 13-02-2019

Credit

Discovered by ACE Team – Loginsoft