团队里管理淘宝团队技术博客的大神只给了我一个可怜巴巴的发布权限。

最近在做 D2 的票务相关的事情,缺少系统支撑和服务器资源。于是,考虑借用“淘宝技术博客”的机器来解决问题。我机器用户账号得到了 sudo 权限,可能是出于技术博客对淘宝团队还挺重要的考虑,给我创建的 WordPress 系统里的用户权限只有最低的发布权限。

为了解决上面提到的 D2 报名和签到的问题,我写了一个 WordPress 插件。然而因为“淘宝技术博客”使用了一个奇葩的 WordPress 版本,插件激活启用,必须要管理员访问 WordPress 的插件管理页面手动激活,哪怕是通过 mu-plugins 的方式想自动激活都不行。而且每更新一次插件,也都必须“重启”插件才能“刷掉”插件的缓存。

因为时间比较赶,这个事情只能等到下班后再做。等我发现这个问题之后,大半夜的,也实在不好意思喊大神起来帮我手动做这个事情,尤其这个事情不能一次性解决。那么,就只好进行一次手动的用户提权啦。

虽说我有机器 sudo 权限,想干啥都行,但看过 WordPress DB 结构的童鞋应该知道最靠谱的权限提升,还是从 WordPress 自由逻辑下手更为靠谱,可以避免只提升了用户权限,导致某些插件信息不同步的问题。

所以,就有了这篇内容。通过“正常”找回密码逻辑,顺带提升用户权限,解决权限不足的问题。

提权之路

翻阅 WordPress 文档,公开 API 中没有能够直接完成“提权”功能的接口。于是开始啃代码,看到 WP_USER->set-role 这个方法,感觉可以达到目的,本地测试一番,果不其然。

接下来,写了一个脚本,将脚本保存到站点的根目录,起个喜欢的名称,然后在浏览器中打开,添加需要提升权限账号的 ID 和新密码,提交之后就好了。

特别注意:请不要用这货来干坏事,尤其是结合最近的某些方法…

脚本内容

<?php
/**
 * WordPress For PassWord Reset Tools
 * 2014.9.29
 * [@soulteary](http://www.soulteary.com)
 */

define('FILE_NAME', basename($_SERVER['SCRIPT_FILENAME']));

require(dirname(__FILE__) . '/wp-load.php');
require_once(dirname(__FILE__) . '/wp-admin/includes/user.php');

function makeTpl($title, $event = false){
?><!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>WordPress 芝麻开门 &rsaquo; <?= $title; ?></title>
    <?php
    wp_admin_css('wp-admin', true);
    wp_admin_css('colors-fresh', true);
    wp_admin_css('login', true);
    ?>
    <meta name='robots' content='noindex,nofollow'/>
</head>
<body class="login login-action-login wp-core-ui locale-zh-cn">
<div id="login">
    <div id="loginform">
        <h1><a href="http://cn.wordpress.org/" title="基于 WordPress">WordPress 芝麻开门</a></h1>
        <?php if ($event == 'TOKEN'): ?>
            <div id="login_error"><strong>错误</strong>:您输入的Key不正确。<br></div>
        <?php elseif ('TOOLS-INFO' == $event): ?>
            <style type="text/css">
                .login #login_error {
                    background-color: #E8F8FF;
                    border-color: #009BCC;
                }
            </style>
            <div id="login_error">请输入芝麻开门的Key。<br></div>
        <?php
        elseif ('RESET-EMPTY' == $event): ?>
            <style type="text/css">
                .login #login_error {
                    background-color: #E8F8FF;
                    border-color: #009BCC;
                }
            </style>
            <div id="login_error"><strong>提示</strong>:请将表单填写完整。<br></div>
        <?php
        elseif ('RESET-ERROR' == $event): ?>
            <div id="login_error"><strong>错误</strong>:重置密码失败。<br></div>
        <?php
        elseif ('RESET-DONE' == $event): ?>
            <style type="text/css">
                .login #login_error {
                    background-color: #E9FFE8;
                    border-color: #00CC49;
                }
            </style>
            <div id="login_error">
                <strong>成功</strong>:重置密码完成,请使用新密码登录。<br>新的登录密码:<span class="code"><?= trim($_POST['password']) ?></span></div>
        <?php endif; ?>
        <?php if ('TOOLS-INFO' == $event || 'TOKEN' == $event): ?>
        <form name="loginform" id="loginform" action="./<?= FILE_NAME ?>" method="post" style="padding-bottom: 20px;">
            <p>
                <label for="token">Sina App Engine Secret Key<br/>
                    <input type="password" name="token" id="token" class="input" value="" size="20"/></label>
            </p>

            <p class="submit">
                <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large"
                       value="验证"/>
            </p>
            <?php elseif ('RESET-EMPTY' == $event || 'RESET-ERROR' == $event): ?>
            <form name="loginform" id="loginform" action="./<?= FILE_NAME ?>" method="post"
                  style="padding-bottom: 20px;">
                <input type="hidden" name="token" value="<?= md5(TOKEN); ?>"/>

                <p>
                    <label for="username">帐号名称<br/>
                        <input type="text" name="username" id="username" class="input" value="" size="20"/></label>
                </p>

                <p>
                    <label for="password">新的密码<br/>
                        <input type="password" name="password" id="password" class="input" value="" size="20"/></label>
                </p>

                <p class="submit">
                    <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large"
                           value="修改"/>
                </p>
                <?php elseif ('RESET-DONE' == $event): ?>
                <form name="loginform" id="loginform" method="post" style="padding-bottom: 20px;">
                    <p class="submit">
                        <style type="text/css">
                            #bye-bye {
                                float: left;
                                margin: 0 0 0 86px;
                            }
                        </style>
                        <a id="bye-bye" class="button button-primary button-large" href="./wp-login.php"/>前往登录</a>
                    </p>
                    <?php endif; ?>
                </form>
    </div>
</div>
<div class="clear"></div>
</body>
</html>
<?php
exit();
}

define('TOKEN', 'zhimakaimen');
if (!isset($_POST['token']) || empty($_POST['token'])) {
    makeTpl('管理员验证', 'TOOLS-INFO');
} else {
    if ($_POST['token'] != TOKEN && ($_POST['token'] != md5(TOKEN))) {
        makeTpl('管理员验证', 'TOKEN');
    }
}

$username = trim($_POST['username']);
$password = trim($_POST['password']);

if (!isset($password) || !isset($username) || empty($username) || empty($password)) {
    makeTpl('重置帐号', 'RESET-EMPTY');
} else {

    $username = wp_slash($username);
    $user = WP_User::get_data_by('login', $username);
    $user2 = new WP_User( (int)$user->ID );
    $user2->set_role("administrator");
    wp_cache_delete((int)$user2->ID, 'users');
    wp_cache_delete($user1->user_login, 'userlogins');

    if (!$user) {
        makeTpl('重置帐号', 'RESET-ERROR');
    }
    wp_set_password($password, $user->ID);
    wp_password_change_notification($user);
    makeTpl('重置帐号', 'RESET-DONE');
}
?>