Skip to content

Instantly share code, notes, and snippets.

@samhemelryk
Created November 21, 2016 02:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samhemelryk/45f0d50696c6197e432894e5e1da057c to your computer and use it in GitHub Desktop.
Save samhemelryk/45f0d50696c6197e432894e5e1da057c to your computer and use it in GitHub Desktop.
Setting internal_encoding to an empty string will cause unexpected charset warnings when calling htmlspecialchars
<?php
/**
* This sets internal_encoding to an empty string and immediately
* redirects back to the index page in order to highlight the problem
* that is now present.
*/
ini_set('internal_encoding', '');
header('Location: index.php', 302);
die;
<?php
/**
* Illustrates a bug within PHP introduced when setting internal_encoding to empty within one script and not
* setting it at all in another.
*
* To reproduce, simple:
*
* 1. In terminal navigate to the location of the scripts.
* 2. Run: php -S 127.0.0.1:8000
* 3. In your browser visit to http://127.0.0.1:8000
* 4. Refresh the page several times and confirm you see no warnings.
* 5. Follow the link "Trigger the problems" (will redirect to bust.php and then back to index.php)
* 6. Refresh your browser a few times, you will likely get an PHP warning about htmlspecialchars charset.
*
* Additional testing:
*
* a) The warning in PHP 5.6.18 and above contains random content, visually looks like buffer overflow.
* 1. Note the error you got.
* 2. Kill the built in PHP Server and restart it exactly the same.
* 3. Visit index.php and click the link.
* 4. Observe the warning content has changed.
* Typically you get UTF-8 chars, however on occasion you will get code from this file or bust.php
* Filed as a security issue as oit appears possible for files containing credentials to be
* incorrectly displayed in a readable format.
*
* b) Once triggered the condition is persistent for all users until the web server is restarted.
* 1. Kill the built in PHP Server and restart it exactly the same.
* 2. In one browser visit index.php and confirm no warning. Refresh a few times for certainty.
* 3. In a second browser visit bust.php.
* 4. Back in the first browser refresh a few times and confirm you see the warning.
*
* Affects:
*
* 5.6.16 (OSX)
* - Partial, warning is printed but error contains no unexpected content.
* "PHP Warning: htmlspecialchars(): in index.php on line 7"
* 5.6.18 (OSX)
* "PHP Warning: htmlspecialchars(): charset `�`�' not supported, assuming utf-8 in index.php on line 62"
* 5.6.27_1 (Ubuntu)
* "PHP Warning: htmlspecialchars(): charset `�`T' not supported, assuming utf-8 in index.php on line 62"
* 5.6.27_4 (OSX)
* "PHP Warning: htmlspecialchars(): charset `�`T' not supported, assuming utf-8 in index.php on line 62"
* 5.6.28_1 (Ubuntu)
* "PHP Warning: htmlspecialchars(): charset `' not supported, assuming utf-8 in index.php on line 62"
*
* Does not affect:
*
* 7.0.3 (OSX)
* 7.0.10 (OSX)
* 7.1.0-rc.6_10 (OSX)
*/
// We want errors to display.
error_reporting(-1);
ini_set("display_errors", 1);
// We definitely don't want this to be cached.
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
echo "<h1>".htmlspecialchars("This script does not explicitly set any charset directives.")."</h1>";;
echo "<ul>";
echo "<li>default_charset: ".ini_get('default_charset')."</li>";
echo "<li>input_encoding: ".ini_get('input_encoding')."</li>";
echo "<li>output_encoding: ".ini_get('output_encoding')."</li>";
echo "<li>internal_encoding: ".ini_get('internal_encoding')."</li>";
echo "<li>mbstring.language: ".ini_get('mbstring.language')."</li>";
echo "</ul>";
echo "<p><a href='bust.php'>Trigger the problem</a></p>";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment