Maison > php教程 > PHP开发 > le corps du texte

La fonction getimagesize n'est pas complètement fiable

黄舟
Libérer: 2016-12-28 13:04:37
original
1772 Les gens l'ont consulté

La fonction getimagesize ne fait pas partie de l'extension GD. Cette fonction peut être utilisée par PHP installé en standard. Vous pouvez d'abord jeter un œil à la description du document de cette fonction : http://php.net/manual/zh/function.getimagesize.php

Si le fichier spécifié n'est pas une image valide, false sera renvoyé et les données seront renvoyées. Il existe également des champs représentant le type de document. Si vous ne l'utilisez pas pour obtenir la taille du fichier mais que vous l'utilisez pour déterminer si le fichier téléchargé est un fichier image, cela semble être une très bonne solution. Bien sûr, cela doit bloquer d'éventuels avertissements. le code est écrit comme ceci :

<?php
$filesize = @getimagesize(&#39;/path/to/image.png&#39;);
if ($filesize) {
    do_upload();
}
# 另外需要注意的是,你不可以像下面这样写:
# if ($filesize[2] == 0)
# 因为 $filesize[2] 可能是 1 到 16 之间的整数,但却绝对不对是0。
Copier après la connexion

Mais si vous faites simplement une telle vérification, alors malheureusement, vous avez réussi à implanter une vulnérabilité Webshell dans le code.

Pour analyser ce problème, jetons d'abord un coup d'œil au prototype de cette fonction :

static void php_getimagesize_from_stream(php_stream *stream, zval **info, INTERNAL_FUNCTION_PARAMETERS)
{
    ...
    itype = php_getimagetype(stream, NULL TSRMLS_CC);
    switch( itype) {
        ...
    }
    ...
}

static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) {
    ...
    php_getimagesize_from_stream(stream, info, INTERNAL_FUNCTION_PARAM_PASSTHRU);
    php_stream_close(stream);
}

PHP_FUNCTION(getimagesize)
{
    php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
}
Copier après la connexion

L'espace limité a caché certains détails. Nous savons maintenant deux choses du code ci-dessus : Assez. :

La fonction de traitement final est php_getimagesize_from_stream

La fonction chargée de déterminer le type de fichier est php_getimagetype

Jetons un coup d'œil à l'implémentation de php_getimagetype :

PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
{
    ...
    if (!memcmp(filetype, php_sig_gif, 3)) {
        return IMAGE_FILETYPE_GIF;
    } else if (!memcmp(filetype, php_sig_jpg, 3)) {
        return IMAGE_FILETYPE_JPEG;
    } else if (!memcmp(filetype, php_sig_png, 3)) {
        ...
    }
}
Copier après la connexion

Certains détails ont été supprimés. php_sig_gif php_sig_png et ainsi de suite sont définis dans l'en-tête du fichier :

PHPAPI const char php_sig_gif[3] = {&#39;G&#39;, &#39;I&#39;, &#39;F&#39;};
...
PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
                                    (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
Copier après la connexion

On peut voir que le type d'image est jugé en fonction des premiers octets du fichier. flux (en-tête de fichier). Alors dans ce cas, pouvons-nous construire un fichier PHP spécial pour contourner ce jugement ? Pourquoi ne pas essayer.

Trouvez un éditeur hexadécimal pour écrire une instruction PHP, par exemple :

<?php phpinfo(); ?>
Copier après la connexion

L'encodage hexadécimal (UTF-8) de ces caractères est comme ceci :

3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
Copier après la connexion

Structureons-le et ajoutons l'octet d'en-tête du fichier PNG devant pour devenir comme ceci :

8950 4E47 0D0A 1A0A 3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
Copier après la connexion

Enfin, enregistrons-le sous forme de fichier avec un suffixe .php (notez que ce qui précède est la valeur hexadécimale du fichier), tel que test.php. Exécutez php test.php et vous constaterez qu’il peut être exécuté avec succès. Alors, pouvez-vous utiliser getimagesize pour lire les informations de son fichier ? Créez un nouveau fichier et écrivez le code pour essayer :

<?php
print_r(getimagesize(&#39;test.php&#39;));
Copier après la connexion

Résultat de l'exécution :

Array
(
    [0] => 1885957734
    [1] => 1864902971
    [2] => 3
    [3] => width="1885957734" height="1864902971"
    [bits] => 32
    [mime] => image/png
)
Copier après la connexion

a été lu avec succès et le fichier a été reconnu comme un fichier PNG normalement, bien que la largeur et hauteur Les valeurs sont un peu scandaleuses.

Vous devez maintenant comprendre pourquoi il est dit ci-dessus qu'il existe un danger caché de webshell. S'il n'existe qu'un tel jugement de téléchargement et que le fichier téléchargé est accessible, du code arbitraire peut être injecté et exécuté via cette entrée.

Alors pourquoi le fichier ci-dessus peut-il être exécuté normalement par PHP ? Utilisez la fonction token_get_all pour regarder ce fichier :

<?phpprint_r(token_get_all(file_get_contents(&#39;test.php&#39;)));
Copier après la connexion

Si l'affichage est normal, vous pouvez voir que le code de l'analyseur du premier élément du tableau de sortie est 312, et le nom obtenu via token_name sera be T_INLINE_HTML, En d'autres termes, les informations contenues dans l'en-tête du fichier sont traitées comme du code HTML intégré normal et ignorées.

Quant à la raison pour laquelle il y a une largeur et une hauteur absurdement grandes, vous pouvez le savoir en regardant l'implémentation de la fonction php_handle_png. Cette information est également obtenue en lisant les bits d'en-tête de fichier spécifiques.

Ainsi, pour les fichiers image normaux, getimagesize est entièrement capable, mais pour certaines structures de fichiers délibérément construites, ce n'est pas le cas.

Lors du traitement des fichiers téléchargés par les utilisateurs, c'est également un moyen efficace de déterminer simplement et grossièrement l'extension du fichier et de traiter le nom du fichier pour s'assurer qu'il ne peut pas être directement exécuté sur le serveur à moins qu'il ne s'agisse d'un fichier php. Vous pouvez ensuite utiliser getimagesize pour effectuer un traitement auxiliaire.

Ce qui précède est le contenu pour lequel la fonction getimagesize n'est pas complètement fiable. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Recommandations populaires
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal