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