Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid memory access in do_checksum() #538

Closed
SegfaultMasters opened this issue Feb 12, 2019 · 3 comments

Comments

Projects
4 participants
@SegfaultMasters
Copy link

commented Feb 12, 2019

Description - 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.

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

POC - REPRODUCER

Debug -

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 → <do_checksum+524> movzx eax, WORD PTR [rax+0x6]
$r8 : 0x15 
$r9 : 0x00005555557be200 → 0x6567616d692f0000
$r10 : 0x00005555557b9700 → 0x0000000000000000
$r11 : 0x00007ffff78d6000 → <__fread_chk+0> 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 <do_checksum+513> add rax, rdx
0x5555555696d4 <do_checksum+516> mov QWORD PTR [rbp-0x18], rax
0x5555555696d8 <do_checksum+520> mov rax, QWORD PTR [rbp-0x18]
→ 0x5555555696dc <do_checksum+524> movzx eax, WORD PTR [rax+0x6]
0x5555555696e0 <do_checksum+528> test ax, ax
0x5555555696e3 <do_checksum+531> je 0x555555569939 <do_checksum+1129>
0x5555555696e9 <do_checksum+537> mov rax, QWORD PTR [rbp-0x18]
0x5555555696ed <do_checksum+541> mov WORD PTR [rax+0x6], 0x0
0x5555555696f3 <do_checksum+547> 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

@fklassen fklassen self-assigned this Feb 12, 2019

@fklassen fklassen added the bug label Feb 12, 2019

@carnil

This comment has been minimized.

Copy link

commented Feb 17, 2019

CVE-2019-8381 was assigned for this issue.

@cbiedl

This comment has been minimized.

Copy link

commented Mar 10, 2019

Unless I'm mistaken the problem is get_layer4_v6 may return zero, and does so as a length of 3 is way to short to extract any useful information. Fix then was to check for that situation and bail out. In other words:

--- a/src/tcpedit/checksum.c
+++ b/src/tcpedit/checksum.c
@@ -62,7 +62,10 @@ do_checksum(tcpedit_t *tcpedit, uint8_t *data, int proto, int len) {
         proto = get_ipv6_l4proto(ipv6, len);
         dbgx(3, "layer4 proto is 0x%hx", (uint16_t)proto);
 
-        ip_hl = (u_char*)get_layer4_v6(ipv6, len) - (u_char*)data;
+        u_char *layer = (u_char*)get_layer4_v6(ipv6, len);
+        if (layer == NULL)
+            return -1;
+        ip_hl = layer - (u_char*)data;
         dbgx(3, "ip_hl proto is 0x%d", ip_hl);
 
         len -= (ip_hl - TCPR_IPV6_H);

Result is:

(...)
DEBUG3 in tcpedit.c:tcpedit_packet() line 353: doing IPv4 checksum: needtorecalc=0
DEBUG3 in checksum.c:do_checksum() line 63: layer4 proto is 0x11

Fatal Error in send_packets.c:send_packets() line 553:
 Error editing packet #1: 

Did I miss something?

@fklassen fklassen added this to To do in 4.3.2 via automation Mar 12, 2019

fklassen added a commit that referenced this issue Mar 12, 2019

Merge pull request #548 from appneta/Bug_#538_CVE-2019-8381_do_checksum
Bugs #538 add check for packet length in do_checksum()

@fklassen fklassen moved this from To do to Done in 4.3.2 Mar 12, 2019

@fklassen

This comment has been minimized.

Copy link
Member

commented Mar 12, 2019

fixed in PR #548

@fklassen fklassen closed this Mar 12, 2019

GabrielGanne added a commit to GabrielGanne/tcpreplay that referenced this issue May 2, 2019

GabrielGanne added a commit to GabrielGanne/tcpreplay that referenced this issue May 9, 2019

fix do_checksum() packet dissection
prevent the function from interpreting as packet header if there is not
enough bytes.

Fixes appneta#538
Fixes appneta#556
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.