2 votes

une vulnérabilité dans le plugin de notification de devis

Le plugin suivant est utilisé pour servir des notifications aux membres du forum vbulletin.

un ami m'a dit qu'il y a une possibilité de vulnérabilité sur la base de données Mysql à cause de ce plugin. je ne suis pas un expert mysql donc je ne peux pas dire où se trouve exactement le problème.

Si quelqu'un a trouvé cette vulnérabilité, je voudrais savoir exactement ce que je dois faire pour la corriger.

Avec le plugin vient cette page php qui montrera la liste des notifications pour le membre. http://textuploader.com/d1hch pas sûr que ce php script ait une quelconque vulnérabilité

Le problème peut être lié à mysqli::escape_string ou à l'instruction préparée de PDO.

<?xml version="1.0" encoding="ISO-8859-1"?>

<product productid="k_quote_notifications" active="0">
    <title>Quote Notifications</title>
    <description>Notify User after being quoted</description>
    <version>1.0.0</version>
    <url></url>
    <versioncheckurl></versioncheckurl>
    <dependencies>
    </dependencies>
    <codes>
        <code version="1.0.0">
            <installcode><![CDATA[$db->hide_errors();
$db->query_write("
CREATE TABLE   " . TABLE_PREFIX . "quotedatanew (
  `quoted` int(10) NOT NULL default '0',
  `quoter` int(10) NOT NULL default '0',
  `quotername` varchar(255) NOT NULL default '0',
  `postid` int(10) NOT NULL default '0',
  `threadid` int(10) NOT NULL default '0',
  `threadtitle` varchar(255) NOT NULL default '0',
  `dateline` int(10) NOT NULL default '0',
  `hasseen` int(1) NOT NULL default '0',
  KEY `quoted` (`quoted`)
)
");
$db->show_errors();]]></installcode>
            <uninstallcode><![CDATA[$db->query_write("
 DROP TABLE " . TABLE_PREFIX . "quotedatanew
");]]></uninstallcode>
        </code>
    </codes>
    <templates>
        <template name="NOTI" templatetype="template" date="1401826799" username="AAA" version="1.0.0"><![CDATA[$stylevar[htmldoctype]
<html dir="$stylevar[textdirection]" lang="$stylevar[languagecode]">
<head>
<title>$vboptions[bbtitle]</title>

<style type="text/css">
.alert-box {
    color:#555;
    border-radius:10px;
    font-family:Tahoma,Geneva,Arial,sans-serif;font-size:11px;
    padding:10px 36px;
    margin:10px;
}
.alert-box span {
    font-weight:bold;
    text-transform:uppercase;
}
.error {
    background:#ffecec url('images/error.png') no-repeat 10px 50%;
    border:1px solid #f5aca6;
}
.success {
    background:#e9ffd9 url('images/success.png') no-repeat 10px 50%;
    border:1px solid #a6ca8a;
}
.warning {
    background:#fff8c4 url('images/warning.png') no-repeat 10px 50%;
    border:1px solid #f2c779;
}
.notice {
    background:#e3f7fc url('images/notice.png') no-repeat 10px 50%;
    border:1px solid #8ed9f6;
}
.paginate {
font-family:Arial, Helvetica, sans-serif;
    padding: 3px;
    margin: 3px;
}

.paginate a {
    padding:2px 5px 2px 5px;
    margin:2px;
    border:1px solid #999;
    text-decoration:none;
    color: #666;
}
.paginate a:hover, .paginate a:active {
    border: 1px solid #999;
    color: #000;
}
.paginate span.current {
    margin: 2px;
    padding: 2px 5px 2px 5px;
        border: 1px solid #999;

        font-weight: bold;
        background-color: #999;
        color: #FFF;
    }
    .paginate span.disabled {
        padding:2px 5px 2px 5px;
        margin:2px;
        border:1px solid #eee;
        color:#DDD;
    }

 </style>
$headinclude
</head>
<body>
$header

$navbar

<table class="tborder" cellpadding="$stylevar[cellpadding]" cellspacing="$stylevar[cellspacing]" border="0" width="100%" align="center">
<tr>
    <td class="tcat">$vbphrase[notification_page_title]</td>
</tr>
<tr>
    <td class="alt1">$content</td>
</tr>
$paginate
</table>

$footer
</body>
</html>]]></template>
        <template name="TEST" templatetype="template" date="1401824077" username="AAA" version="1.0.0"><![CDATA[$stylevar[htmldoctype]
<html dir="$stylevar[textdirection]" lang="$stylevar[languagecode]">
<head>
<title>$vboptions[bbtitle]</title>
$headinclude
</head>
<body>
$header

$navbar

<table class="tborder" cellpadding="$stylevar[cellpadding]" cellspacing="$stylevar[cellspacing]" border="0" width="100%" align="center">
<tr>
    <td class="tcat">Title</td>
</tr>
<tr>
    <td class="alt1">Text</td>
</tr>
</table>

$footer
</body>
</html>]]></template>
    </templates>
    <plugins>
        <plugin active="1" executionorder="5">
            <title>Get Notifications</title>
            <hookname>global_start</hookname>
            <phpcode><![CDATA[$counter = $vbulletin->db->query_first("SELECT COUNT(*) AS id FROM quotedatanew where quoted =" . $vbulletin->userinfo['userid'] . " and hasseen= '0'");
$count   = $counter['id'];
$notifi  = $vbulletin->db->query_read("SELECT * FROM quotedatanew where quoted =" . $vbulletin->userinfo['userid'] . " and hasseen = '0' ORDER BY dateline DESC LIMIT 4");
while ($noti = $vbulletin->db->fetch_array($notifi)) {
    $threadurl    = $vbulletin->options['bburl'] . '/showthread.php?source=noti&p=' . $noti['postid'] . '#post' . $noti['postid'];
    $memberurl    = $vbulletin->options['bburl'] . '/member.php?u=' . $noti['quoter'];
    $notiurl      = $vbulletin->options['bburl'] . '/noti.php';
    $qoutername   = $noti['quotername'];
    $threadname   = $noti['threadtitle'];
    $phrasequote  = $vbphrase['has_quoted_your_post_in'];
    $seeallphrase = $vbphrase['see_all_noti'];
    $notihtml .= '<tr><td class="vbmenu_option" style="white-space:normal;max-width:200px;"><a href="' . $memberurl . '">' . $qoutername . '</a> ' . $phrasequote . ' <a href="' . $threadurl . '">' . $threadname . '</a></td></tr>';
}
if ($count > 4) {
    $notihtml .= '<tr><td class="vbmenu_option" style="white-space:normal;max-width:200px;"><a href="' . $notiurl . '">' . $seeallphrase . '</a></td></tr>';
}]]></phpcode>
        </plugin>
        <plugin active="1" executionorder="5">
            <title>Insert Notification</title>
            <hookname>newpost_complete</hookname>
            <phpcode><![CDATA[if ($vbulletin->options['wqm_system'] == true) {

    if (preg_match('/\[quote=(.*?)\]((?:.|\s)+?)\[\/quote\]/i', $post['message'])) {
        preg_match_all('/\[quote=(.*?)\]((?:.|\s)+?)\[\/quote\]/i', $post['message'], $quotematch);

        $quotecount = count($quotematch[0]);
        $tempcount  = 0;
        $quotearray = array();

        while ($tempcount < $quotecount) {
            $username     = explode(';', $quotematch[1][$tempcount]);
            $quoteduserid = $vbulletin->db->query_first("SELECT userid FROM " . TABLE_PREFIX . "user
            WHERE username = '" . $vbulletin->db->escape_string(htmlspecialchars_uni($username[0])) . "'");

            if (!in_array($quoteduserid['userid'], $quotearray)) {
                if ($quoteduserid['userid'] > 0 AND $quoteduserid['userid'] != $vbulletin->userinfo['userid']) {
                    $quotearray[] = $quoteduserid['userid'];

                    // check forum permissions
                    $quoteduserinfo = fetch_userinfo(intval($quoteduserid['userid']));
                    $forumperms     = fetch_permissions($foruminfo['forumid'], intval($quoteduserid['userid']), $quoteduserinfo);

                    if (!($forumperms & $vbulletin->bf_ugp_forumpermissions['canview']) OR !($forumperms & $vbulletin->bf_ugp_forumpermissions['canviewthreads'])) {
                        $tempcount++;
                        continue;
                    }
                    if (!($forumperms & $vbulletin->bf_ugp_forumpermissions['canviewothers']) AND ($threadinfo['postuserid'] != intval($quoteduserid['userid']) OR $vbulletin->userinfo['userid'] == 0)) {
                        $tempcount++;
                        continue;
                    }

                    $vbulletin->db->query_write("
                    INSERT INTO " . TABLE_PREFIX . "quotedatanew (quoted,quoter,postid,threadid,threadtitle,dateline,quotername)
                    VALUES ('" . $quoteduserid['userid'] . "','" . $vbulletin->userinfo['userid'] . "','" . $post['postid'] . "','" . $threadinfo[threadid] . "','" . $vbulletin->db->escape_string(htmlspecialchars_uni($threadinfo[title])) . "','" . time() . "','" . $vbulletin->db->escape_string(htmlspecialchars_uni($vbulletin->userinfo['username'])) . "')");
                }
            }
            $tempcount++;
        }
    }

}]]></phpcode>
        </plugin>
        <plugin active="1" executionorder="5">
            <title>Dismiss notification</title>
            <hookname>showthread_start</hookname>
            <phpcode><![CDATA[$postid = intval($_GET["p"]);
$source = $_GET["source"];
if ($source == "noti") {
    $vbulletin->db->query_write("update quotedatanew set hasseen = '1' where postid = '" . $postid . "' and quoted = '" . $vbulletin->userinfo['userid'] . "'");
}]]></phpcode>
        </plugin>
    </plugins>
    <phrases>
        <phrasetype name="GLOBAL" fieldname="global">
            <phrase name="delete_all_nots" date="1401999437" username="bbb" version="1.0.0"><![CDATA[Õ–› ÄÌ⁄ «· ‰»Ì« ]]></phrase>
            <phrase name="has_quoted_your_post_in" date="1401739493" username="AAA" version="1.0.0"><![CDATA[Has Quoted Your Post In]]></phrase>
            <phrase name="no_notification_text" date="1401999471" username="bbb" version="1.0.0"><![CDATA[·« ÌÊÃœ  ‰»Ì«  Ü̜…]]></phrase>
            <phrase name="noti_icon" date="1401829523" username="AAA" version="1.0.0"><![CDATA[Notifications]]></phrase>
            <phrase name="notification_read" date="1401825953" username="AAA" version="1.0.0"><![CDATA[Read]]></phrase>
            <phrase name="notification_unread" date="1401826023" username="AAA" version="1.0.0"><![CDATA[Unread]]></phrase>
            <phrase name="see_all_noti" date="1401810412" username="AAA" version="1.0.0"><![CDATA[See All Notification]]></phrase>
        </phrasetype>
        <phrasetype name="vBulletin Settings" fieldname="vbsettings">
            <phrase name="setting_wqm_system_desc" date="1401828337" username="AAA" version="1.0.0"><![CDATA[<style type="text/css">
body { background:#555;color:white; }
a:link, a:visited, a:active { color:white; }
.optiontitle { background:#10a113;color:#FFF;border:none; }
.button { background:#10A113;border:none;color:white;padding:6px 12px;}
.button:hover { background:#057c08; }
.tcat { color:white;background: #111;border:none; }
.tcat a:link, .tcat a:visited, .tcat a:active { color:white; }
.tfoot { background:#111;border:none; }
.alt1 { color:white;background:#333; }
.tborder { border:1px solid #000; -moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;-moz-box-shadow: 2px 2px 8px #000;-webkit-box-shadow: 2px 2px 8px #000;box-shadow: 2px 2px 8px #000; }
textarea, .bginput, input.col-c, input.col-i, input.col-g { border:1px solid #000;color:#EEE;background:#444; }
.pagetitle { background:#111;color:white;border:1px solid #000;-moz-box-shadow: 2px 2px 8px #000;-webkit-box-shadow: 2px 2px 8px #000;box-shadow: 2px 2px 8px #000; }
</style>]]></phrase>
            <phrase name="setting_wqm_system_title" date="1401828337" username="AAA" version="1.0.0"><![CDATA[Enable Notifications System]]></phrase>
            <phrase name="settinggroup_Notification System" date="1401828329" username="AAA" version="1.0.0"><![CDATA[Notification System]]></phrase>
        </phrasetype>
    </phrases>
    <options>
        <settinggroup name="Notification System" displayorder="590">
            <setting varname="wqm_system" displayorder="10">
                <datatype>boolean</datatype>
                <optioncode>yesno</optioncode>
                <defaultvalue>1</defaultvalue>
            </setting>
        </settinggroup>
    </options>
    <helptopics>
    </helptopics>
    <cronentries>
    </cronentries>
    <faqentries>
    </faqentries>
</product>

0voto

Paolo Points 2489

Le seul problème potentiel que je vois avec ce code est que les requêtes sont construites en concaténant des chaînes de caractères au lieu d'utiliser des instructions préparées, ex :

        $quoteduserid = $vbulletin->db->query_first("SELECT userid FROM " . TABLE_PREFIX . "user
        WHERE username = '" . $vbulletin->db->escape_string(htmlspecialchars_uni($username[0])) . "'");

Cela expose les requêtes à des attaques potentielles par injection sql.

Je vois dans le code que des précautions sont prises, par exemple l'option username dans la clause where est composé avec :

username = '" . $vbulletin->db->escape_string(htmlspecialchars_uni($username[0])) . "'"

En username s'est échappé db->escape_string qui est censé prévenir les attaques par injection. Mais un bogue dans cette fonction peut faire en sorte que le code ne soit pas sûr.

La seule façon recommandée et infaillible d'effectuer des requêtes est d'utiliser des déclarations préparées.

Voici le lien pour déclarations préparées mysqli

Les instructions préparées vous permettent de passer un paramètre à utiliser dans une requête (ex. le nom d'utilisateur). directement à mysqli ou pdo. Avec cette approche, il n'y a aucun moyen pour un caractère ou une séquence de caractères dans le paramètre de "casser" la requête comme cela pourrait se produire lorsque la requête est construite par concaténation de chaînes statiques et de valeurs de variables (échappées).


Si vous voulez améliorer le code, vous devez substituer chaque requête dans sa "forme de déclaration préparée".

Les requêtes en instructions préparées sont faciles à réaliser (il suffit de vérifier si $vbullettin->db est une connexion mysqli ou PDO pour utiliser les méthodes correctes).

Les paramètres doivent ensuite être transmis non encodé vous devriez vérifier ce que $vbulletin->db->escape_string fait (dans l'exemple) pour que les données stockées dans la base de données conservent leur format.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X