Incorrect Calculation of Multi-Byte String Length

Description

Incorrect Calculation of Multi-Byte String Length occurs when a program incorrectly calculates the length of strings that contain wide or multi-byte characters. In character encodings like UTF-8, UTF-16, or various Asian character sets, a single character can be represented by multiple bytes. Functions that assume one byte equals one character (like strlen() in C for ASCII) will produce incorrect lengths for multi-byte strings. This miscalculation can lead to buffer overflows when allocating buffers, truncation of data, or buffer over-reads when iterating through strings.

Risk

Multi-byte string length miscalculations are particularly dangerous in internationalized applications and systems processing user input in various languages. When ASCII-centric length functions are used on multi-byte data, buffers may be undersized (leading to overflow) or operations may read beyond intended boundaries. This vulnerability class contributed to MS08-067, one of the most significant Windows vulnerabilities exploited by the Conficker worm. Applications processing UTF-8, UTF-16, or other multi-byte encodings without proper length handling are vulnerable.

Solution

Use encoding-aware string functions appropriate for the character set being processed. For UTF-8, use functions like mbstowcs(), mbrlen(), or platform-specific alternatives. Distinguish between byte length and character count in all string operations. When allocating buffers for multi-byte strings, calculate the required byte size correctly. Use wchar_t and wide-character functions for wide character strings. Consider using libraries like ICU (International Components for Unicode) for robust Unicode handling. Validate and normalize character encoding before processing.

Common Consequences

ImpactDetails
IntegrityScope: Memory Corruption

Undersized buffer allocations based on incorrect length lead to buffer overflows during string operations.
ConfidentialityScope: Information Disclosure

Over-reads when iterating beyond string boundaries expose adjacent memory contents.
AvailabilityScope: Denial of Service

Memory corruption from incorrect string handling causes crashes and system instability.

Example Code + Solution Code

Vulnerable Code

#include <string.h>
#include <stdlib.h>
#include <wchar.h>

// VULNERABLE: Uses strlen on potentially multi-byte string
char *copy_input(const char *input) {
    // strlen counts bytes, not characters
    // For UTF-8, this may be longer than character count
    size_t len = strlen(input);

    // Allocates enough bytes BUT subsequent char-by-char
    // processing may assume different size
    char *copy = malloc(len + 1);
    strcpy(copy, input);
    return copy;
}

// VULNERABLE: Mixing byte length and character count
void truncate_string(wchar_t *dest, const wchar_t *src, size_t max_chars) {
    // Uses byte-based function on wide character string
    // sizeof(wchar_t) may be 2 or 4 bytes
    strncpy((char *)dest, (char *)src, max_chars);  // WRONG!
}

// VULNERABLE: MS08-067-like path canonicalization
void canonicalize_path(char *path) {
    char *ptr = path + strlen(path);

    // Walking backwards without considering multi-byte boundaries
    while (ptr > path && *ptr != '\\') {
        ptr--;  // May land in middle of multi-byte character
    }
    // Further processing may corrupt memory
}

Fixed Code

#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

// SAFE: Proper multi-byte string handling
char *copy_input_safe(const char *input) {
    // Use mbstowcs to count actual characters if needed
    // But strlen is correct for byte allocation
    size_t byte_len = strlen(input);

    char *copy = malloc(byte_len + 1);
    if (copy) {
        memcpy(copy, input, byte_len + 1);
    }
    return copy;
}

// SAFE: Proper wide character string handling
void truncate_wstring_safe(wchar_t *dest, size_t dest_size,
                           const wchar_t *src, size_t max_chars) {
    // Use wide character functions
    size_t src_len = wcslen(src);
    size_t copy_len = src_len < max_chars ? src_len : max_chars;

    // Ensure we don't overflow destination
    if (copy_len >= dest_size) {
        copy_len = dest_size - 1;
    }

    wcsncpy(dest, src, copy_len);
    dest[copy_len] = L'\0';
}

// SAFE: Multi-byte aware string iteration
size_t safe_char_count(const char *str) {
    setlocale(LC_ALL, "");  // Set locale for mblen

    size_t count = 0;
    const char *ptr = str;

    while (*ptr) {
        int char_len = mblen(ptr, MB_CUR_MAX);
        if (char_len <= 0) {
            char_len = 1;  // Handle invalid sequences
        }
        ptr += char_len;
        count++;
    }

    return count;
}

// SAFE: UTF-8 aware string processing
size_t utf8_char_length(unsigned char c) {
    if ((c & 0x80) == 0) return 1;      // ASCII
    if ((c & 0xE0) == 0xC0) return 2;   // 2-byte sequence
    if ((c & 0xF0) == 0xE0) return 3;   // 3-byte sequence
    if ((c & 0xF8) == 0xF0) return 4;   // 4-byte sequence
    return 1;  // Invalid, treat as single byte
}

Exploited in the Wild

MS08-067 Conficker Worm (Microsoft Windows, 2008)

CVE-2008-4250 was a buffer overflow in Windows Server Service's NetPathCanonicalize function. The vulnerability involved incorrect bounds calculation during path canonicalization with multi-byte characters, allowing attackers to bypass stack protection and achieve code execution. The Conficker worm exploited this vulnerability to infect millions of Windows systems.

Unicode Normalization Attacks (Various, Ongoing)

Multiple vulnerabilities in web applications and frameworks arise from inconsistent handling of Unicode normalization and multi-byte character lengths, enabling WAF bypasses and injection attacks.


Tools to test/exploit

  • AddressSanitizer — detects buffer overflows from string length miscalculations.

  • AFL++ — fuzzer with Unicode-aware mutators for testing multi-byte handling.

  • ICU — International Components for Unicode library for safe Unicode handling.


CVE Examples

  • CVE-2008-4250 — MS08-067 Windows Server Service RCE via path canonicalization.

  • CVE-2022-24785 — Moment.js path traversal via locale file handling.

  • CVE-2021-42574 — Unicode bidirectional text handling (Trojan Source).


References

  1. MITRE. "CWE-135: Incorrect Calculation of Multi-Byte String Length." https://cwe.mitre.org/data/definitions/135.html

  2. CERT. "STR38-C. Do not confuse narrow and wide character strings and functions." https://wiki.sei.cmu.edu/confluence/display/c/STR38-C