Hervé Godquin

Aller au contenu | Aller au menu | Aller à la recherche

Mot-clé - Vulnérabilité

Fil des billets - Fil des commentaires

jeudi 23 janvier 2020

Nouvelles vulnérabilités dans PHP

Deux nouvelles vulnérabilités semblent toucher PHP.

Voici l'advisory du CERT-FR : https://www.cert.ssi.gouv.fr/avis/CERTFR-2020-AVI-054/

Il semble qu'une des vulnérabilités touche mbstring et notamment la fonction mb_decode_mimeheader qui sert à décoer des en-tête MIME  : https://www.php.net/manual/fr/function.mb-decode-mimeheader.php.

Cette librairie fait partie de l'extension mbstring.

La librairie touchée semble être la libmbfl dans la fonction : mbfl_filt_conv_big5_wchar(int c, mbfl_convert_filter *filter).

Quand on regarde la pile d'exécution on peut voir que le chemin est le suivant (dans mbstring) :

mb_decode_mimeheader() -> mbfl_mime_header_decode() -> mime_header_decoder_collector() -> mbfl_filt_conv_qprintdec() -> mbfl_filter_output_pipe() -> mbfl_filt_conv_big5_wchar()

Autant vous dire que si vous cherchez à trouver cette vulnérabilité en faisant de l'analyse de code "à la mano" vous n'avez pas le cul sorti des ronces :)

Alors cette vulnérabilité a été trouvé comment ? Fuzzing ... Par reza : reza at iseclab dot org.

Vous pouvez tester si vous êtes vulnérables en faisant ceci :

./php -r 'mb_decode_mimeheader(file_get_contents("php://stdin"));' < global-overflow-cp950_pua_tbl.poc

Le fichier PoC est disponible ici : https://github.com/gaintcome/fuzz-php/blob/master/poc/mbstrings/global-overflow-cp950_pua_tbl.poc

(Au cas ou cela disparaîtrait j'en ai mis une copie ici : https://www.paranoiac-thoughts.com/netpsycho/public-scripts-and-confs/blob/master/global-overflow-cp950_pua_tbl.poc)

Pour voir la correction du la vulnérabilité : http://git.php.net/?p=php-src.git;a=blobdiff;f=ext/mbstring/libmbfl/filters/mbfilter_big5.c;h=5e1ca815da31ed68db2baae2b3d38699b546ca83;hp=f5ab8809ce8a799bd40bda74606f181fcef36c75;hb=2bcbc95f033c31b00595ed39f79c3a99b4ed0501;hpb=0f79b1bf301f455967676b5129240140c5c45b09

Alors pourquoi j'en parle : sérieusement le contrôle de MIME c'est courant, surtout dans les fonctionnalités d'upload, donc y a moyen de se faire plaisir.

De même, c'est vrai que PHP reste vaste (et inexploré ???) c'est donc une bonne piste pour s'entraîner au fuzzing et trouver des petites vulns :).

Have fun !

Comme d'habitude vous pouvez proposer des améliorations à cet article via : https://www.paranoiac-thoughts.com/netpsycho/blog_post/blob/master/20200123_nouvelles_vulnerabilites_php

mardi 14 janvier 2020

CVE-2019-19844 : Django account takeover, revue de code et bonne année

Déjà je tiens à vous souhaiter à toutes et à tous une excellente année 2020. Maintenant que ceci est dit passons au sujet qui nous intéresse : la description d'une petite vulnérabilité intéressante.

Aujourd'hui j'ai choisi la CVE-2019-19844 touchant Django. Cette vulnérabilité touche le formulaire de reset de mot de passe dont le code source (vulnérable) est disponible ici : https://github.com/django/django/blob/4cec3cc82a09b1a60a72e5437a7f0e9e0c7d203c/django/contrib/auth/forms.py

Voici les fonctions posant problèmes :

    def get_users(self, email):
        """Given an email, return matching user(s) who should receive a reset.
        This allows subclasses to more easily customize the default policies
        that prevent inactive users and users with unusable passwords from
        resetting their password.
        """
        active_users = UserModel._default_manager.filter(**{
            '%s__iexact' % UserModel.get_email_field_name(): email,
            'is_active': True,
        })
        return (u for u in active_users if u.has_usable_password())
    
    def save(self, domain_override=None,
             subject_template_name='registration/password_reset_subject.txt',
             email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator,
             from_email=None, request=None, html_email_template_name=None,
             extra_email_context=None):
        """
        Generate a one-use only link for resetting password and send it to the
        user.
        """
        email = self.cleaned_data["email"]
        if not domain_override:
            current_site = get_current_site(request)
            site_name = current_site.name
            domain = current_site.domain
        else:
            site_name = domain = domain_override
        for user in self.get_users(email):
            context = {
                'email': email,
                'domain': domain,
                'site_name': site_name,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': 'https' if use_https else 'http',
                **(extra_email_context or {}),
            }
            self.send_mail(
                subject_template_name, email_template_name, context, from_email,
                email, html_email_template_name=html_email_template_name,
            )

On peut avouer que comme ça la vulnérabilité n'est pas forcément très facile à détecter. En effet le problème est assez particulier, et montre que certains points de bonnes pratiques peuvent avoir des implications sécuritaires pouvant être importantes.

Les gros problèmes sont là : '%s__iexact' % UserModel.get_email_field_name(): email, et ici : return (u for u in active_users if u.has_usable_password()). J'avoue même comme cela ça ne saute pas aux yeux :). Du coup je vous invite à lire ceci : http://unicode.org/reports/tr36/#Recommendations_General.

Oui il s'agit bel et bien d'un problème d'encodage de caractères, en soit les petits curieux qui ont été voir la description de la CVE avaient sans doute trouvés :

Django before 1.11.27, 2.x before 2.2.9, and 3.x before 3.0.1 allows account takeover. A suitably crafted email address (that is equal to an existing user's email address after case transformation of Unicode characters) would allow an attacker to be sent a password reset token for the matched user account. (One mitigation in the new releases is to send password reset tokens only to the registered user email address.)

Je vous laisse découvrir le patch par vous même : https://github.com/django/django/commit/5b1fbcef7a8bec991ebe7b2a18b5d5a95d72cb70?diff=unified

Alors qu'est-ce que tout cela peut nous apprendre au final (à part qu'il faut patcheer son django). En soit ça vous donne de nouvelles idées de tests pour vos pentests / bug-bounties, mais surtout si vous faîtes de la revue de code cela est assez intéressant.

Premièrement car normalement ces fonctions devraient être revue "en profondeur" si on en croit l'OWASP :

"Are all the untrusted inputs validated? Input data is constrained and validated for type, length, format, and range."

Mais un peu plus que cela, car en effet en soit, tout est bon : ce qu'il manque c'est juste un respect des bonnes pratiques Unicode. Dites à votre avis, combien de développeurs, même voir d'auditeurs les connaissent ? Lors d'un audit de type revue de code au planning serré, cela est-il toujours contrôlé ? De même lors de pentest d'ailleurs ?

Donc voilà ce que cela nous apprends : Je suis sûr qu'il y a bien d'autres cas comme cela, alors à vos git pour les contrôles :).

J'avoue que je commence gentiment pour ce premier post de l'année, mais en regardant les dernières vulnérabilités dans le monde du libre, je n'avais pas trop l'inspiration, c'était soit Django, soit OpenSSL avec la CVE-2019-1551 qui je l'avoue ne m'a pas inspiré. Je vous laisse observer ce magnifique fichier PERL : https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=419102400a2811582a7a3d4a4e317d72e5ce0a8f (y avait aussi un XSS dans wordpress mais bon ...).

Je vais tenter de préparer un nouvel article pour la semaine prochaine, sur une vulnérabilité un peu plus "costaud" ça sera sympatique.

 

Have fun !

P.S : comme toujours si vous voulez proposer des améliorations, corriger des fautes, passez par le gitlab des paranoiac-thoughts : https://www.paranoiac-thoughts.com/netpsycho/blog_post/blob/master/20200114_django

dimanche 22 septembre 2019

Quelques nouvelles vulnérabilités dans PHP

Récemment quelques vulnérabilités ont été découvertes dans PHP.

Toutes concernent le traitement des images, j'ai néanmoins choisi de montrer l'une d'entre elle car c'est comment dire ... un classique au final.

Voici le code vulnérable :

                                                       if (*(p1 + 1) == '=') {

                                                                ++p1;

                                                                --str_left;

                                                        }

 

                                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);

On voit tout de suite le problème ... que se passe-t-il si str_left = 0 ? ... forcément quelque chose de pas très bien, on le devine aisément.

Le problème est que str_left est un unsigned integer. Et ce vulnérabilité est comprise dans une boucle for qui en fin de boucle refait un str_left-- ... nous avons donc un énorme entier par la suite.

Et quand dans cette boucle nous avons des opérations de lecture nous nous retrouvons donc bien face à un : "Out-of-bounds read due to integer overflow".

La correction est assez simple :

                                                        * we can do at this point. */

                                                        if (*(p1 + 1) == '=') {

                                                                ++p1;

-                                                               --str_left;

+                                                               if (str_left > 1) {

+                                                                       --str_left;

+                                                               }

                                                        }

 

                                                        err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);

Pour plus d'informations : https://bugs.php.net/bug.php?id=78069

Concernant les autres vulnérabilités dans PHP : 

https://bugs.php.net/bug.php?id=77950

https://bugs.php.net/bug.php?id=77988

https://bugs.php.net/bug.php?id=78222

https://bugs.php.net/bug.php?id=78256

 

A vos patchs !