Invalid memory access Vulnerability in function do_checksum() – tcpreplay-4.3.1

Loginsoft-2018-1064

February 13, 2019

CVE Number

CVE-2019-8381

CWE

CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer

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 that there is an Invalid memory access at do_checksum () in checksum.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 function tcpedit_packet (). where it Process a given packet and edit the pkthdr/pktdata structures, at line retval = fix_ipv4_checksums(tcpedit, *pkthdr, ip_hdr); here it calls to another function 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. Now here when we are passing parameters in line ret2 = do_checksum(tcpedit, (u_char *) ip_hdr, IPPROTO_IP, ip_len); it invokes to another function do_checksum (). Here in the line udp = (udp_hdr_t *) (data + ip_hl); here data contains a valid data and ip_hl exceeds the value of 1,34000. now when it moves to the next line here UDP address is invalid, if (udp->uh_sum == 0) where UDP is a pointer type, pointing to an Invalid memory and it triggers as Invalid memory access

Vulnerable code
udp = (udp_hdr_t *)(data + ip_hl);
/* No need to recalculate UDP checksums if already 0 */
if (udp->uh_sum == 0) 
break; 
udp->uh_sum = 0;
if (ipv6 != NULL) {
sum = do_checksum_math((uint16_t *)&ipv6->ip_src, 32);
Analysis

 

GDB -
Program received signal SIGSEGV, Segmentation fault.
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x555500000000 
$rbx : 0x00005555557b7bb8 → 0x0000337330706e65 ("enp0s3"?)
$rcx : 0x3 
$rdx : 0xffffffffaa841df2
$rsp : 0x00007fffffffd930 → 0x0000000000000000
$rbp : 0x00007fffffffd990 → 0x00007fffffffd9d0 → 0x00007fffffffda70 → 0x00007fffffffdbc0 → 0x00007fffffffdd10 → 0x00007fffffffdd40 → 0x00007fffffffddd0 → 0x00007fffffffe210
$rsi : 0x3 
$rdi : 0x00005555557be20e → 0x0011323003000062 ("b"?)
$rip : 0x00005555555696dc →  movzx eax, WORD PTR [rax+0x6]
$r8 : 0x15 
$r9 : 0x00005555557be200 → 0x6567616d692f0000
$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 ────
0x00007fffffffd930│+0x0000: 0x0000000000000000 ← $rsp
0x00007fffffffd938│+0x0008: 0x00000011557be239
0x00007fffffffd940│+0x0010: 0x00005555557be20e → 0x0011323003000062 ("b"?)
0x00007fffffffd948│+0x0018: 0x00005555557b86c0 → 0x0000000000000001
0x00007fffffffd950│+0x0020: 0x00007fffffffd980 → 0x00007fffffffd9d0 → 0x00007fffffffda70 → 0x00007fffffffdbc0 → 0x00007fffffffdd10 → 0x00007fffffffdd40 → 0x00007fffffffddd0
0x00007fffffffd958│+0x0028: 0x00000000aa841df2
0x00007fffffffd960│+0x0030: 0x0000000000000000
0x00007fffffffd968│+0x0038: 0x00005555557be20e → 0x0011323003000062 ("b"?)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x5555555696d1  add rax, rdx
0x5555555696d4  mov QWORD PTR [rbp-0x18], rax
0x5555555696d8  mov rax, QWORD PTR [rbp-0x18]
→ 0x5555555696dc  movzx eax, WORD PTR [rax+0x6]
0x5555555696e0  test ax, ax
0x5555555696e3  je 0x555555569939 
0x5555555696e9  mov rax, QWORD PTR [rbp-0x18]
0x5555555696ed  mov WORD PTR [rax+0x6], 0x0
0x5555555696f3  cmp QWORD PTR [rbp-0x28], 0x0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:checksum.c+99 ────
94 break;
95 
96 case IPPROTO_UDP:
97 udp = (udp_hdr_t *)(data + ip_hl);
98 /* No need to recalculate UDP checksums if already 0 */
// udp=0x00007fffffffd978 → 0x0000555500000000
→ 99 if (udp->uh_sum == 0)
100 break;
101 udp->uh_sum = 0;
102 if (ipv6 != NULL) {
103 sum = do_checksum_math((uint16_t *)&ipv6->ip_src, 32);
104 } else {
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "tcpreplay-edit", stopped, reason: SIGSEGV
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x5555555696dc → do_checksum(tcpedit=0x5555557b86c0, data=0x5555557be20e "b", proto=0x11, len=0x557be239)
[#1] 0x555555565fbc → fix_ipv4_checksums(tcpedit=0x5555557b86c0, pkthdr=0x7fffffffdb50, ip_hdr=0x5555557be20e)
[#2] 0x555555564991 → tcpedit_packet(tcpedit=0x5555557b86c0, pkthdr=0x7fffffffdac0, pktdata=0x7fffffffdab0, direction=TCPR_DIR_C2S)
[#3] 0x55555555c589 → send_packets(ctx=0x5555557aa260, pcap=0x5555557ba860, idx=0x0)
[#4] 0x555555563169 → replay_file(ctx=0x5555557aa260, idx=0x0)
[#5] 0x555555562a1b → tcpr_replay_index(ctx=0x5555557aa260)
[#6] 0x555555562341 → tcpreplay_replay(ctx=0x5555557aa260)
[#7] 0x55555555f112 → main(argc=0x1, argv=0x7fffffffe360)
────────────────────────────────────────────────────────────────────────────────────────────

gef➤ p *udp
Cannot access memory at address 0x555500000000
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: 12-02-2019
Public Disclosure: 13-02-2019

Credit

Discovered by ACE Team – Loginsoft