php - 报价通知插件中的漏洞

标签 php mysql vbulletin

以下插件用于为 vbulletin 论坛中的成员提供通知。

一位 friend 告诉我,因为这个插件,Mysql 数据库可能存在漏洞。我不是 mysql 专家,所以我不知道问题到底出在哪里。

如果有人发现此漏洞,我想确切地知道我应该如何修复它。

随着插件的出现,这个 php 页面将显示成员的通知列表 http://textuploader.com/d1hch 不确定这个 php 脚本是否有漏洞

问题可能与 mysqli::escape_string 或 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>

最佳答案

我在这段代码中看到的唯一潜在问题是查询是通过连接字符串而不是使用准备好的语句来构建的,例如:

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

这将查询暴露给潜在的 sql 注入(inject)攻击。

我在代码中看到采取了预防措施,例如 where 子句中的 username 由:

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

username 被转义为db->e​​scape_string 以防止注入(inject)攻击。但是该函数中的错误可能会导致代码不安全。

进行查询的唯一推荐且可靠的方法是使用准备好的状态。

此处为 prepared statements mysqli 的链接

准备好的语句让您可以将要在查询中使用的参数(例如用户名)直接传递给 mysqli 或 pdo。使用这种方法,参数中的字符或字符序列无法“中断”查询,因为当通过连接静态字符串和(转义的)变量值构建查询时可能会发生这种情况。


如果您想改进代码,您必须将每个查询替换为“准备好的语句形式”。

准备好的语句查询很容易做到(只需检查 $vbullettin->db 是否是 mysqli 或 PDO 连接以使用正确的方法)。

因为参数必须未转义传递,所以您应该检查$vbulletin->db->e​​scape_string 实际做了什么(在示例中)以便存储数据在数据库中保持其格式。

关于php - 报价通知插件中的漏洞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42083535/

相关文章:

php - 如果我没有关闭 PHP 标签,Notepad++ 函数列表 PHP 无法工作

mysql - 根据日期从 3x 列中提取行

php - 如何在一定时间后采取行动(因用户而异)?

php - 即使代码正确,也无法选择数据库表

php - 在 WooCommerce 中更新自定义订单项元

php - 带有 Joomla 站点的 XAMPP 子域

php收集两个日期之间的日期并为每个日期创建条目

php - 从动态创建的表中搜索数据

mysql - 几年前创建了这个 vBulletin 论坛,现在它向我发送垃圾邮件错误

mysql - 替换 120 多个表中的 MySQL 值