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

CVE-2018-17582: Heap based Buffer Over-read vulnerability in get_next_packet() - tcpreplay 4.3

Vulnerability Reports
September 28, 2018
Profile Icon

Jason Franscisco

Heap based Buffer Over-read vulnerability in get_next_packet() - tcpreplay 4.3

Loginsoft-2018-17582

September 28, 2018

CVE Number

CVE-2018-17582

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:https://tcpreplay.appneta.com/

Vulnerable Versions

4.3 branch

Vulnerability Details

Tcp replay v4.3.0 beta1 contains a heap-based buffer over-read. The get_next_packet() function in the send_packets.c file uses the memcpy() function unsafely to copy sequences from the source buffer pkt data to the destination (*prev_packet)->pkt data. This will result in a Denial of Service (DoS) and potentially Information Exposure when the application attempts to process a file.

SYNOPSIS

Another heap overflow in tcrepay was discovered while processing a packet from a corrupted pcapfile. Below is in-short layout of a pcapfile format, which briefs about the vulnerability. Pcap file strcuture(as perlibpcap3.4)Apcapfile consists of various blocks which sum up & form a file.- Section Header Block: Also called global headers, it identifies the beginning of a pcapfile. Fields are - Major version, minor version, section length etc.


typedef struct pcap_hdr_s { 

        guint32 magic_number;   /* magic number */ 

        guint16 version_major;  /* major version number */ 

        guint16 version_minor;  /* minor version number */ 

        gint32  thiszone;       /* GMT to local correction */ 

        guint32 sigfigs;        /* accuracy of timestamps */ 

        guint32 snaplen;        /* max length of captured packets, in octets */ 

        guint32 network;        /* data link type */ 

} pcap_hdr_t;
  

- Interface description block: Specified the characteristics of network interface on which the capture has been made. Fields:LinkType,Snaplen, Reserved etc.- Packet block: It's of our interest. It contains a single captured packet, or a portion of it. It's again separated into two sections, packet header & packet data.The fields contained in packet header are - Timestamp, captured length, packet length etc.


typedef struct pcaprec_hdr_s { 

        guint32 ts_sec;         /* timestamp seconds */ 

        guint32 ts_usec;        /* timestamp microseconds */ 

        guint32 incl_len;       /* number of octets of packet saved in file (Captured length) */ 

        guint32 orig_len;       /* actual length of packet (Packet length)*/ 

} pcaprec_hdr_t; 
  

Reference

http://www.tcpdump.org/pcap/pcap.html

https://wiki.wireshark.org/Development/LibpcapFileFormat

Another important point to note is the maximum size for a tcp packet is 65535, the same information about every individual packet is contained inside the packet header(packet lengthfield).

Root cause analysis


Void preload_pcap_file(tcpreplay_t *ctx, int idx) [1] 

{ 

. 
. 
. 

dlt = pcap_datalink(pcap); 

    while ((pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) { [2] 

        packetnum++;   


(*prev_packet)->pktdata = safe_malloc(pktlen); 

                    memcpy((*prev_packet)->pktdata, pktdata, pktlen); [3] 

                    memcpy(&((*prev_packet)->pkthdr), pkthdr, sizeof(struct pcap_pkthdr)); 
  

Moving on to the vulnerability, the function preload_pcap_file() [1] loads the pcapfile into the RAM for performance improvement . The function is invoked by the switch–K[5] ,which enables the caching of packets to internal memory. A per official documentation- "Cache pcapfile(s) the first time they are cached in RAM so that subsequent loops don’t incur any disk I/O latency in order to increase performance. It then calls get_next_packet()[2] which is responsible for getting the next packet to be sent out (this will either read from the pcap file or will retrieve the packet from the internal cache).

While getting the next package, it utilized a memcpy()[3]where the length field `pktlen`, being received from pkthdr->lenis invalid (packet length larger than the actual packet limit), causing an invalid read as it tries reading beyond the actual limitation of at cp packet which is of 65535, causing a heap based buffer over-read.

Analysis

1044                      (*prev_packet)->pktdata = safe_malloc(pktlen);

                // prev_packet=0xbfffef60 -> [...] -> 0x00000000, pktdata=0xbfffef24 -> [...] -> 0x07290c00

->1045                       memcpy((*prev_packet)->pktdata, pktdata, pktlen);   //Buffer overflow

   1046                      memcpy(&((*prev_packet)->pkthdr), pkthdr, sizeof(struct pcap_pkthdr));

   1047                  }

   1048              }

   1049          }
[#0] 0x8052f3a->Name: get_next_packet(ctx=0xb6403280, pcap=0xb4203280, pkthdr=0xbffff000, idx=0x0, prev_packet=0xbfffefc0)

[#1] 0x804e922->Name: preload_pcap_file(ctx=0xb6403280, idx=0x0)

[#2] 0x805615c->Name: main(argc=0x1, argv=0xbffff724)
gef> info locals

options = 0xb6200200

pktdata = 0xb3514800 ""

pktlen = 0x80003e

__PRETTY_FUNCTION__ = "get_next_packet"

__FUNCTION__ = "get_next_packet"




gef> ptype (*prev_packet)->pktdata

type = unsigned char *

gef> p pktdata

$30 = (u_char *) 0xb3514800 ""

gef> p (*prev_packet)->pktdata

$27 = (u_char *) 0xb2afe800 ""

gef> x (*prev_packet)->pktdata

0xb2afe800:     0


gef> ptype pktlen

type = unsigned int

gef> p/d pktlen

$25 = 8388670
gef> i r

eax            0xb4800320          0xb4800320

ecx            0x3                 0x3

edx            0x0                 0x0

ebx            0xb4800310          0xb4800310

esp            0xbfffef00          0xbfffef00

ebp            0xbfffef48          0xbfffef48

esi            0x0                 0x0

edi            0xb2afe800          0xb2afe800

eip            0x8052f3a           0x8052f3a 

eflags         0x246               [ PF ZF IF ]

cs             0x73                0x73

ss             0x7b                0x7b

ds             0x7b                0x7b

es             0x7b                0x7b

fs             0x0                 0x0

gs             0x33                0x33
  
ASAN Output

=================================================================

==22604==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb35247ff at pc 0xb7adba75 bp 0xbfffeec8 sp 0xbfffea9c

READ of size 8388670 at 0xb35247ff thread T0

    #0 0xb7adba74 in __asan_memcpy (/usr/lib/i386-linux-gnu/libasan.so.2+0x8aa74)

    #1 0xb7adbc2f in memcpy (/usr/lib/i386-linux-gnu/libasan.so.2+0x8ac2f)

    #2 0x8052fb6 in get_next_packet /home/loginsoft/ACE/tcpreplay/src/send_packets.c:1045

    #3 0x804e921 in preload_pcap_file /home/loginsoft/ACE/tcpreplay/src/send_packets.c:445

    #4 0x805615b in main /home/loginsoft/ACE/tcpreplay/src/tcpreplay.c:126

    #5 0xb784c636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)

    #6 0x804a7a0  (/usr/local/bin/tcpreplay+0x804a7a0)




0xb35247ff is located 0 bytes to the right of 65535-byte region [0xb3514800,0xb35247ff)

allocated by thread T0 here:

    #0 0xb7ae7dee in malloc (/usr/lib/i386-linux-gnu/libasan.so.2+0x96dee)

    #1 0xb7a28e7c  (/usr/lib/i386-linux-gnu/libpcap.so.0.8+0x1ce7c)




SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 __asan_memcpy

Shadow bytes around the buggy address:

  0x366a48a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x366a48b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x366a48c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x366a48d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x366a48e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

=>0x366a48f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[07]

  0x366a4900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

  0x366a4910: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

  0x366a4920: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

  0x366a4930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

  0x366a4940: 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

==22604==ABORTING

[Inferior 1 (process 22604) exited with code 01]
  
Valgrind Report

==13353== Source and destination overlap in memcpy(0x467d028, 0x4648c50, 8388670)

==13353==    at 0x4030D39: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)

==13353==    by 0x804D24B: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804BCC0: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804E3FA: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x40DD636: (below main) (libc-start.c:291)

==13353==

==13353== Invalid read of size 4

==13353==    at 0x4030DD0: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)

==13353==    by 0x804D24B: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804BCC0: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804E3FA: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x40DD636: (below main) (libc-start.c:291)

==13353==  Address 0x467d024 is 4 bytes before a block of size 8,388,670 alloc'd

==13353==    at 0x402C17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)

==13353==    by 0x8053B5B: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804D22E: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804BCC0: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804E3FA: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x40DD636: (below main) (libc-start.c:291)

==13353==

==13353== Invalid read of size 4

==13353==    at 0x4030DDE: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)

==13353==    by 0x804D24B: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804BCC0: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804E3FA: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x40DD636: (below main) (libc-start.c:291)

==13353==  Address 0x467d020 is 8 bytes before a block of size 8,388,670 alloc'd

==13353==    at 0x402C17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)

==13353==    by 0x8053B5B: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804D22E: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804BCC0: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x804E3FA: ??? (in /usr/local/bin/tcpreplay)

==13353==    by 0x40DD636: (below main) (libc-start.c:291)

==13353==
  
Proof of Concept

tcpreplay -i en33  -t –K –loop 4 –unique-ip $POC-t switch is for performanceimprovementto send the packets as fast as possible.-K[5]--loop is used to specify the loopnumber, to loop through the capture file N times.The issue istriggeredwhen supplied a craftedpcapfile via the above given command.

Timeline

Vendor Disclosure: 2018-09-25

Public Disclosure: 2018-09-28

Credit

Discovered by ACE Team - Loginsoft

Explore Cybersecurity Platforms

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

Discover Lovi

Sign up to our Newsletter