GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GCVE-1988-2026-0322

Vulnerability from gna-1988 – Published: 2026-09-11 07:55 – Updated: 2026-09-11 07:55
VLAI
Title
PHP 8.5.7 `mb_substr()` 'SJIS-mac' size_t underflow
Summary
# PHP 8.5.7 `mb_substr()` 'SJIS-mac' size_t underflow **Author:** Khashayar Fereidani **Disclosure Date:** 2026-06-18 **Advisory:** https://fereidani.com/php-857-mbsubstr-sjis-mac-sizet-underflow **Contact:** https://fereidani.com/contact ## Description The `mb_get_substr()` function in `ext/mbstring/mbstring.c` deliberately skips an early empty return guard for the `SJIS-mac` encoding when `from >= in_len`. As a result, it falls through to `mb_get_substr_slow()`, executing `mb_convert_buf_init(&buf, MIN(len, in_len - from), ...);`. When `from > in_len`, the parameter `in_len - from` underflows the `size_t` representation, resulting in a vastly large allocation size (near ~2^64 bytes). This leads to an immediate Out-Of-Memory (OOM) fatal error. Furthermore, if `_ZSTR_STRUCT_SIZE(initsize)` wraps past `SIZE_MAX`, it could potentially allocate a tiny buffer while the structural limit retains the pseudo-wild value, resulting in a heap buffer overflow when subsequent codepoints are decoded and written. ## Proof of concept ```php <?php /* * PoC: mb_substr() 'SJIS-mac' size_t underflow * File: ext/mbstring/mbstring.c mb_get_substr() (~L2129) + mb_get_substr_slow() (~L2102) * * mb_get_substr() deliberately skips the early "return empty" guard for SJIS-mac: * * if (len == 0 || (from >= in_len && enc != &mbfl_encoding_sjis_mac)) { * return zend_empty_string; // <-- sjis_mac bypasses this when from >= in_len * } * * ... then falls through (sjis_mac is multibyte, not SBCS/WCS2/WCS4) to * mb_get_substr_slow(), whose first line is: * * mb_convert_buf_init(&buf, MIN(len, in_len - from), ...); * * With `from > in_len` (bytes), `in_len - from` UNDERFLOWS size_t to ~2^64. * mb_convert_buf_init does emalloc(_ZSTR_STRUCT_SIZE(initsize)). * * Two outcomes, both wrong (correct result is the empty string): * (A) `from` huge -> initsize ~2^64 -> fatal "Allowed memory size exhausted * (tried to allocate 18446744073708551644 bytes)". CONFIRMED below. * (B) `from` only slightly > in_len -> initsize sits just under 2^64 and * _ZSTR_STRUCT_SIZE(initsize) WRAPS past SIZE_MAX to a tiny allocation, * while buf->limit = out + initsize stays wild -> a subsequent write of * decoded codepoints is a HEAP OVERFLOW. (Harder to trigger reliably: * needs a SJIS-mac input decoding to more codepoints than bytes, i.e. * from < codepoint_count while from > byte_count. Worth upstream review.) */ echo "PHP ", PHP_VERSION, " sjis_mac available: ", (in_array("SJIS-mac", mb_list_encodings()) ? "yes" : "no"), "\n\n"; /* control: a normal encoding with from > strlen returns "" cleanly */ echo "UTF-8, from=10 > strlen('abc'): -> "; var_dump(@mb_substr("abc", 10, null, "UTF-8")); /* The bug: SJIS-mac, from >> strlen, length omitted -> underflow -> OOM fatal. * The "tried to allocate 18...644 bytes" is literally (size_t)(3 - 1000000). */ echo "SJIS-mac, from=1000000 > strlen('abc'):\n"; @mb_substr("abc", 1000000, null, "SJIS-mac"); echo "(if you see this line, the fatal error above was caught/suppressed)\n"; ``` ## Impact An attacker could intentionally furnish conditions where `from > in_len` alongside the 'SJIS-mac' encoding, triggering a `size_t` underflow. This predictably causes a severe Out-Of-Memory (OOM) fatal error, culminating in a Denial of Service. Depending on environmental details, it might hypothetically cause a heap buffer overflow. ## Solution Adjust the constraints inside `mb_get_substr()` and `mb_get_substr_slow()` in `ext/mbstring/mbstring.c`. The calculation `in_len - from` should be adequately bounds-checked to halt computation or safely cap at zero when `from > in_len`, sidestepping the underflow when initializing string buffers. _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Impacted products
Vendor Product Version CPE status
Php PHP Affected: unknown
guessed Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "PHP",
          "vendor": "Php",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Khashayar Fereidani"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "# PHP 8.5.7 `mb_substr()` \u0027SJIS-mac\u0027 size_t underflow\n\n**Author:** Khashayar Fereidani\n**Disclosure Date:** 2026-06-18\n**Advisory:** https://fereidani.com/php-857-mbsubstr-sjis-mac-sizet-underflow\n**Contact:** https://fereidani.com/contact\n\n## Description\n\nThe `mb_get_substr()` function in `ext/mbstring/mbstring.c`\ndeliberately skips an early empty return guard for the `SJIS-mac`\nencoding when `from \u003e= in_len`. As a result, it falls through to\n`mb_get_substr_slow()`, executing `mb_convert_buf_init(\u0026buf, MIN(len,\nin_len - from), ...);`. When `from \u003e in_len`, the parameter `in_len -\nfrom` underflows the `size_t` representation, resulting in a vastly\nlarge allocation size (near ~2^64 bytes). This leads to an immediate\nOut-Of-Memory (OOM) fatal error. Furthermore, if\n`_ZSTR_STRUCT_SIZE(initsize)` wraps past `SIZE_MAX`, it could\npotentially allocate a tiny buffer while the structural limit retains\nthe pseudo-wild value, resulting in a heap buffer overflow when\nsubsequent codepoints are decoded and written.\n\n## Proof of concept\n\n```php\n\u003c?php\n/*\n * PoC: mb_substr() \u0027SJIS-mac\u0027 size_t underflow\n * File:  ext/mbstring/mbstring.c  mb_get_substr() (~L2129) +\nmb_get_substr_slow() (~L2102) *\n * mb_get_substr() deliberately skips the early \"return empty\" guard\nfor SJIS-mac:\n *\n *     if (len == 0 || (from \u003e= in_len \u0026\u0026 enc != \u0026mbfl_encoding_sjis_mac)) {\n *         return zend_empty_string;     // \u003c-- sjis_mac bypasses this\nwhen from \u003e= in_len\n *     }\n *\n * ... then falls through (sjis_mac is multibyte, not SBCS/WCS2/WCS4) to\n * mb_get_substr_slow(), whose first line is:\n *\n *     mb_convert_buf_init(\u0026buf, MIN(len, in_len - from), ...);\n *\n * With `from \u003e in_len` (bytes), `in_len - from` UNDERFLOWS size_t to ~2^64.\n * mb_convert_buf_init does emalloc(_ZSTR_STRUCT_SIZE(initsize)).\n *\n * Two outcomes, both wrong (correct result is the empty string):\n *  (A) `from` huge -\u003e initsize ~2^64 -\u003e fatal \"Allowed memory size exhausted\n *      (tried to allocate 18446744073708551644 bytes)\". CONFIRMED below.\n *  (B) `from` only slightly \u003e in_len -\u003e initsize sits just under 2^64 and\n *      _ZSTR_STRUCT_SIZE(initsize) WRAPS past SIZE_MAX to a tiny allocation,\n *      while buf-\u003elimit = out + initsize stays wild -\u003e a subsequent write of\n *      decoded codepoints is a HEAP OVERFLOW. (Harder to trigger reliably:\n *      needs a SJIS-mac input decoding to more codepoints than bytes, i.e.\n *      from \u003c codepoint_count while from \u003e byte_count. Worth upstream review.)\n */\necho \"PHP \", PHP_VERSION, \"  sjis_mac available: \",\n     (in_array(\"SJIS-mac\", mb_list_encodings()) ? \"yes\" : \"no\"), \"\\n\\n\";\n\n/* control: a normal encoding with from \u003e strlen returns \"\" cleanly */\necho \"UTF-8, from=10 \u003e strlen(\u0027abc\u0027): -\u003e \"; var_dump(@mb_substr(\"abc\",\n10, null, \"UTF-8\"));\n\n/* The bug: SJIS-mac, from \u003e\u003e strlen, length omitted -\u003e underflow -\u003e OOM fatal.\n * The \"tried to allocate 18...644 bytes\" is literally (size_t)(3 - 1000000). */\necho \"SJIS-mac, from=1000000 \u003e strlen(\u0027abc\u0027):\\n\";\n@mb_substr(\"abc\", 1000000, null, \"SJIS-mac\");\necho \"(if you see this line, the fatal error above was caught/suppressed)\\n\";\n```\n\n## Impact\n\nAn attacker could intentionally furnish conditions where `from \u003e\nin_len` alongside the \u0027SJIS-mac\u0027 encoding, triggering a `size_t`\nunderflow. This predictably causes a severe Out-Of-Memory (OOM) fatal\nerror, culminating in a Denial of Service. Depending on environmental\ndetails, it might hypothetically cause a heap buffer overflow.\n\n## Solution\n\nAdjust the constraints inside `mb_get_substr()` and\n`mb_get_substr_slow()` in `ext/mbstring/mbstring.c`. The calculation\n`in_len - from` should be adequately bounds-checked to halt\ncomputation or safely cap at zero when `from \u003e in_len`, sidestepping\nthe underflow when initializing string buffers.\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-11T07:55:54Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Jun/12"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Jun/12"
        },
        {
          "url": "https://fereidani.com/contact"
        },
        {
          "url": "https://fereidani.com/php-857-mbsubstr-sjis-mac-sizet-underflow"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Jun/12"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "PHP 8.5.7 `mb_substr()` \u0027SJIS-mac\u0027 size_t underflow",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0322",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Jun/12",
            "automated": true,
            "contentSha256": "1a56f6306615be693571f8da2403bba1e3c2530e6420451db521debf9559a671",
            "evidenceScore": 9,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Jun/12",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-06-19T06:23:43Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-09-11T07:55:54Z",
    "dateUpdated": "2026-09-11T07:55:54Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0322"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…