/
/
/
CVE-2018-17974: Heap based Buffer Over-read vulnerability in dlt_en10mb_encode() - tcpreplay 4.3

CVE-2018-17974: Heap based Buffer Over-read vulnerability in dlt_en10mb_encode() - tcpreplay 4.3

Vulnerability Reports
October 3, 2018
Profile Icon

Jason Franscisco

Heap based buffer Over-read vulnerability in dlt_en10mb_encode() - tcpreplay 4.3

Loginsoft-2018-17974

‍October 3, 2018

CVE Number

CVE-2018-17974

CWE

CWE-126: Buffer Over-read

Product Details

Tcpreplay is a suite of free Open Source utilities for editing and replaying previously captured network traffic.‍

URL: Tcp replay

Vulnerable Versions

4.3 branch

Vulnerability Details

An issue was discovered in Tcpreplay 4.3.0 beta1. A heap-based buffer over-read was triggered in the function dlt_en10mb_encode() of the file plugins/dlt_en10mb/en10mb.c, due to inappropriate values in the function memmove(). The length (pktlen + ctx -> l2len) can be larger than source value (packet + ctx->l2len) because the function fails to ensure the length of a packet is valid. This leads to Denial of Service.

SYNOPSIS

Another interesting package on our hit list wastcpreplay, which consists of manybinaries. This report recites about a heap overflow vulnerability discovered in the `tcpreplay-edit` binary, which includes all the functionality of bothtcpreplayandtcprewrite.An heap overflow was triggered in function `dlt_en10mb_encode()` at file `en10mb.c`, due to inappropriate values inmemmove()[1].The workflow1. Packet is read2. Packet is passed to source DLT (Data link type) decoder3. Decoder fills out tcpedit internal data structure (tcpeditdlt_t)4. tcpeditdlt_t is passed to destination DLT encoder5. DLT Decoder returns new L2 header6. Packet is rebuilt7. L3 and above is processed8.

Root cause analysis

```
/* rewrite Layer 2 */
if ((pktlen = tcpedit_dlt_process(tcpedit->dlt_ctx, pktdata, (*pkthdr)->caplen, direction)) == TCPEDIT_ERROR) [2]
errx(-1, "%s", tcpedit_geterr(tcpedit));
```

```
int
tcpedit_dlt_decode(tcpeditdlt_t *ctx, const u_char *packet, const int pktlen) [3]
{
return ctx->decoder->plugin_decode(ctx, packet, pktlen);
}
```

```
int
tcpedit_dlt_encode(tcpeditdlt_t* ctx, u_char *packet, int pktlen, tcpr_dir_t direction) [4]
{
return ctx->encoder->plugin_encode(ctx, packet, pktlen, direction);
}
```

```
if (newl2len != ctx->l2len)
memmove(packet + newl2len, packet + ctx->l2len, pktlen - ctx->l2len); [5]

/* update the total packet length */
pktlen += newl2len - ctx->l2len;

```
  

The function tcpedit_packet() Processes a given packet and edits the pkthdr/pktdata structures according to the rules specified in tcpedit. It then calls tcpedit_dlt_process(), which is responsible for rewriting the Layer 2 headers (edit) & returns the new total packet length [2]. This helps in resending the traffic to a number of forwarding devices.Now the packet is passed to source DLT decoder [3], which fills out tcpedit internal data structure (tcpeditdlt_t) & then is passed to destination DLT encoder tcpedit_dlt_encode() [4], which then calls dlt_en10mb_encode(), where our issue gets triggered while creating space for the new L2 header calling memmove() [5]. The memmove utilized the old l2 length to create the new layer 2 header, of length pktlen received from pkthdr->len.

Analysis

-----------------------------------------------------------------------------------------------------------------------------------------------[ code:i386 ]----
0x8079355  mov eax, DWORD PTR [eax+0x28]
0x8079358  cmp eax, DWORD PTR [ebp-0x44]
0x807935b  je 0x807938f 
-> 0x807935d  mov eax, DWORD PTR [ebp+0x8]
0x8079360  mov eax, DWORD PTR [eax+0x28]
0x8079363  mov edx, DWORD PTR [ebp+0x10]
0x8079366  sub edx, eax
0x8079368  mov eax, edx
0x807936a  mov ebx, eax
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


-------[ source:./plugins/dlt_en10mb/en10mb.c+488 ]----
483 return TCPEDIT_ERROR;
484 }
485
486 /* Make space for our new L2 header */
487 if (newl2len != ctx->l2len)
// ctx=0xbfffe6c0 -> [...] -> 0x00000001, packet=0xbfffe6c4 -> [...] -> 0xbfb32500, pktlen=0xbeL, newl2len=0x12L
-> 488 memmove(packet + newl2len, packet + ctx->l2len, pktlen - ctx->l2len); // Buffer overflow
489
490 /* update the total packet length */
491 pktlen += newl2len - ctx->l2len;
492
493 /* always set the src & dst address as the first 12 bytes */

-------[ source:./plugins/dlt_en10mb/en10mb.c+488 ]----

[#0] 0x807935d->Name: dlt_en10mb_encode(ctx=0xb4c01910, packet=0xb6001640 "", pktlen=0xbe, dir=TCPR_DIR_C2S)
[#1] 0x8075218->Name: tcpedit_dlt_encode(ctx=0xb4c01910, packet=0xb6001640 "", pktlen=0xbe, direction=TCPR_DIR_C2S)
[#2] 0x8074857->Name: tcpedit_dlt_process(ctx=0xb4c01910, packet=0xbfffe940, pktlen=0xbe, direction=TCPR_DIR_C2S)
[#3] 0x80655dd->Name: tcpedit_packet(tcpedit=0xb6402880, pkthdr=0xbfffe9c0, pktdata=0xbfffe940, direction=TCPR_DIR_C2S)
[#4] 0x805158b->Name: send_packets(ctx=0xb6403280, pcap=0xb4203000, idx=0x0)
[#5] 0x8063194->Name: replay_file(ctx=0xb6403280, idx=0x0)
[#6] 0x8061fb1->Name: tcpr_replay_index(ctx=0xb6403280)
[#7] 0x8060e81->Name: tcpreplay_replay(ctx=0xb6403280)
[#8] 0x80586eb->Name: main(argc=0x1, argv=0xbffff4d8)

//tcpedit.c:133
gef> p/d pktlen - ctx->l2len
$61 = 176
gef> p/d ctx->l2len
$62 = 14
gef> p/d newl2len
$63 = 18
gef> x packet
0xb6001640:     0

//tcpedit.c+133
gef> ptype pkthdr->caplen
type = unsigned int
gef> p/d pkthdr->caplen
$21 = 190
  
ASAN Output

=================================================================
==5237==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb600167e at pc 0xb7adbfc8 bp 0xbfffe628 sp 0xbfffe1fc
READ of size 76 at 0xb600167e thread T0
#0 0xb7adbfc7 in __asan_memmove (/usr/lib/i386-linux-gnu/libasan.so.2+0x8afc7)
#1 0xb7adc3df in __interceptor_memmove (/usr/lib/i386-linux-gnu/libasan.so.2+0x8b3df)
#2 0x807938b in dlt_en10mb_encode plugins/dlt_en10mb/en10mb.c:488
#3 0x8075217 in tcpedit_dlt_encode plugins/dlt_plugins.c:402
#4 0x8074856 in tcpedit_dlt_process plugins/dlt_plugins.c:245
#5 0x80655dc in tcpedit_packet /home/ace/ACE/tcpreplay/src/tcpedit/tcpedit.c:133
#6 0x805158a in send_packets /home/ace/ACE/tcpreplay/src/send_packets.c:554
#7 0x8063193 in replay_file /home/ace/ACE/tcpreplay/src/replay.c:188
#8 0x8061fb0 in tcpr_replay_index /home/ace/ACE/tcpreplay/src/replay.c:61
#9 0x8060e80 in tcpreplay_replay /home/ace/ACE/tcpreplay/src/tcpreplay_api.c:1135
#10 0x80586ea in main /home/ace/ACE/tcpreplay/src/tcpreplay.c:139
#11 0xb784c636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
#12 0x804a985 (/usr/local/bin/tcpreplay-edit+0x804a985)

0xb600167e is located 0 bytes to the right of 62-byte region [0xb6001640,0xb600167e)
allocated by thread T0 here:
#0 0xb7ae7dee in malloc (/usr/lib/i386-linux-gnu/libasan.so.2+0x96dee)
#1 0x808c354 in _our_safe_malloc /home/ace/ACE/tcpreplay/src/common/utils.c:50
#2 0x805515d in get_next_packet /home/ace/ACE/tcpreplay/src/send_packets.c:1044
#3 0x80506d1 in preload_pcap_file /home/ace/ACE/tcpreplay/src/send_packets.c:445
#4 0x8058626 in main /home/ace/ACE/tcpreplay/src/tcpreplay.c:126
#5 0xb784c636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 __asan_memmove
Shadow bytes around the buggy address:
0x36c00270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x36c00280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x36c00290: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x36c002a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x36c002b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x36c002c0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00[06]
0x36c002d0: fa fa fa fa fd fd fd fd fd fd fd fa fa fa fa fa
0x36c002e0: 00 00 00 00 00 00 04 fa fa fa fa fa 00 00 00 00
0x36c002f0: 00 00 06 fa fa fa fa fa 00 00 00 00 00 00 04 fa
0x36c00300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x36c00310: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
==5237==ABORTING
[Inferior 1 (process 5237) exited with code 01]
  
Proof of Concept

sudo tcpreplay-edit --cachefile=example.cache --intf1=ens33 --intf2=lo --enet-vlan=add --enet-vlan-tag=40 $POC

‍--cachefiletakesa .cachefile as an input which is generated bytcpprepbinary. Itconsists of some rules to split traffic between differentinterfaces specified.

Interfaces can be specified using the intf switch:--intf1=ens33 --intf2=lo

-enet-vlan switch takes add or del as an input. The operations are adding or removing 802.1q VLAN tag information from ethernet frames.

The issue is triggered when supplied a crafted pcap file via the above given command.

Timeline

Vendor Disclosure: 2018-10-02

Public Disclosure: 2018-10-03

Credit

Discovered by ACE Team - Loginsoft

Explore Cybersecurity Platforms

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.

Discover Lovi
Stay Ahead

Get the Latest Cybersecurity Insights

Security research, threat intelligence, vulnerability updates, product news, and expert insights, delivered directly to your inbox. Stay informed. Stay secure.