wordpress 暴力破解防範

1、author頁面地址


author頁面地址爲 http://yoursite/?author=1 ID是自增的

請求這個地址會 301 到一個url,這個url裏包含了做者的用戶名。雖然不算漏洞,仍是給了爆破者很大的便利。

301指向的url :  .../author/你的後臺登陸用戶名php


解決方案

1.在主題代碼裏實現,只要訪問主頁url後頭有author參數就讓他跳到主頁

將下面的代碼添加到當前主題的  functions.php  文件:

html

function my_author_link() {
    return home_url('/' );
}
add_filter('author_link','my_author_link');


2.經過.htaccess文件添加301重定向來隱藏後臺用戶名

在 .htaccess 文件里加入

nginx

redirect 301 /(這裏還有path的請自行添加)/author/你的後臺登陸用戶名/ http://yoursite/


上面這段代碼意思爲:

將 http://yoursite/.../author/你的後臺登陸用戶名/

跳轉至

http://yoursite/

當咱們輸入http://yoursite/?author=1 時會先跳轉至http://yoursite/.../author/你的後臺登陸用戶名/,因此將跳轉後的連接作301重定向便可。

此方法也能夠在你的web服務器配置文件中實現git


二.xmlrpc.php


xmlrpc 是 WordPress 中進行遠程調用的接口,而使用 xmlrpc 調用接口進行帳號爆破在很早以前就被提出並加以利用。xmlrpc登陸接口默認沒有驗證碼,最大錯誤嘗試次數限制等。利用xmlrpc.php提供的接口嘗試猜解用戶的密碼,能夠繞過wordpress對暴力破解的限制。github


1.攻擊方式

攻擊的方式直接POST如下數據到xmlrpc.php

web

<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>   <methodName>wp.getUsersBlogs</methodName>   <params>    <param><value>username</value></param>    <param><value>password</value></param>   </params>
</methodCall>

其中username字段是預先收集的用戶名。password是嘗試的密碼。關於getUsersBlogs接口的更多信息能夠參考官方的指南  。若是密碼正確,返回爲:json

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
    <params>
        <param>
            <value>
                <array>
                    <data>
                        <value>
                            <struct>
                                <member>
                                    <name>isAdmin</name>
                                    <value>
                                        <boolean>1</boolean>
                                    </value>
                                </member>
                                <member>
                                    <name>url</name>
                                    <value>
                                        <string>http://yoursite/</string>
                                    </value>
                                </member>
                                <member>
                                    <name>siteid</name>
                                    <value>
                                        <string>1</string>
                                    </value>
                                </member>
                                <member>
                                    <name>SiteName</name>
                                    <value>
                                        <string>Your Site</string>
                                    </value>
                                </member>
                                <member>
                                    <name>xmlrpc</name>
                                    <value>
                                        <string>http://yoursite/xmlrpc.php</string>
                                    </value>
                                </member>
                            </struct>
                        </value>
                    </data>
                </array>
            </value>
        </param>
    </params>
</methodResponse>


錯誤返回:api

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
    <fault>
        <value>
            <struct>
                <member>
                    <name>faultCode</name>
                    <value>
                        <int>403</int>
                    </value>
                </member>
                <member>
                    <name>faultString</name>
                    <value>
                        <string>用戶名或密碼不正確。</string>
                    </value>
                </member>
            </struct>
        </value>
    </fault>
</methodResponse>


近日 SUCURI 發佈文章介紹瞭如何利用 xmlrpc 調用接口中的 system.multicall 來提升爆破效率,使得成千上萬次的賬號密碼組合嘗試能在一次請求完成,極大的壓縮請求次數,在必定程度上可以躲避日誌的檢測。安全


2.原理分析

WordPress 中關於 xmlrpc 服務的定義代碼主要位於 wp-includes/class-IXR.php 和 wp-includes/class-wp-xmlrpc-server.php 中。基類 IXR_Server 中定義了三個內置的調用方法,分別爲 system.getCapabilities,system.listMethods 和 system.multicall,其調用映射位於 IXR_Server 基類定義中:服務器

<?php
function setCallbacks()
{
    $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
    $this->callbacks['system.listMethods'] = 'this:listMethods';
    $this->callbacks['system.multicall'] = 'this:multiCall';
}


而基類在初始化時,調用  setCallbacks()  綁定了調用映射關係:

<?php
function __construct( $callbacks = false, $data = false, $wait = false )
{
    $this->setCapabilities();
    if ($callbacks) {
        $this->callbacks = $callbacks;
    }
    $this->setCallbacks();  // 綁定默認的三個基本調用映射
    if (!$wait) {
        $this->serve($data);
    }
}


再來看看 system.multicall 對應的處理函數:

<?php
function multiCall($methodcalls)
{
    // See http://www.xmlrpc.com/discuss/msgReader$1208
    $return = array();
    foreach ($methodcalls as $call) {
        $method = $call['methodName'];
        $params = $call['params'];
        if ($method == 'system.multicall') {
            $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
        } else {
            $result = $this->call($method, $params);
        }
        if (is_a($result, 'IXR_Error')) {
            $return[] = array(
                'faultCode' => $result->code,
                'faultString' => $result->message
            );
        } else {
            $return[] = array($result);
        }
    }
    return $return;
}


能夠從代碼中看出,程序會解析請求傳遞的 XML,遍歷多重調用中的每個接口調用請求,並會將最終有調用的結果合在一塊兒返回給請求端。

這樣一來,就能夠將500種甚至是10000種賬號密碼爆破嘗試包含在一次請求中,服務端會很快處理完並返回結果,這樣極大地提升了爆破的效率,利用多重調用接口壓縮了請求次數,10000種賬號密碼嘗試只會在目標服務器上留下一條訪問日誌,必定程度上躲避了日誌的安全檢測。

經過閱讀 WordPress 中 xmlrpc 相關處理的代碼,能大量的 xmlrpc 調用都驗證了用戶名和密碼:

<?php
if ( !$user = $this->login($username, $password) )
    return $this->error;

   
經過搜索上述登陸驗證代碼能夠獲得全部可以用來進行爆破的調用方法列表以下:

wp.getUsersBlogs, wp.newPost, wp.editPost, wp.deletePost, wp.getPost, wp.getPosts, wp.newTerm, wp.editTerm, wp.deleteTerm, wp.getTerm, wp.getTerms, wp.getTaxonomy, wp.getTaxonomies, wp.getUser, wp.getUsers, wp.getProfile, wp.editProfile, wp.getPage, wp.getPages, wp.newPage, wp.deletePage, wp.editPage, wp.getPageList, wp.getAuthors, wp.getTags, wp.newCategory, wp.deleteCategory, wp.suggestCategories, wp.getComment, wp.getComments, wp.deleteComment, wp.editComment, wp.newComment, wp.getCommentStatusList, wp.getCommentCount, wp.getPostStatusList, wp.getPageStatusList, wp.getPageTemplates, wp.getOptions, wp.setOptions, wp.getMediaItem, wp.getMediaLibrary, wp.getPostFormats, wp.getPostType, wp.getPostTypes, wp.getRevisions, wp.restoreRevision, blogger.getUsersBlogs, blogger.getUserInfo, blogger.getPost, blogger.getRecentPosts, blogger.newPost, blogger.editPost, blogger.deletePost, mw.newPost, mw.editPost, mw.getPost, mw.getRecentPosts, mw.getCategories, mw.newMediaObject, mt.getRecentPostTitles, mt.getPostCategories, mt.setPostCategories


這裏是用參數傳遞最少獲取信息最直接的 wp.getUsersBlogs 進行測試,將兩次賬號密碼嘗試包含在同一次請求裏,構造 XML 請求內容爲:

<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>system.multicall</methodName>
  <params><param>
    <value><array><data>
      <value><struct>
        <member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
        <member><name>params</name><value><array><data>
          <value><string>admin</string></value>
          <value><string>admin888</string></value>
        </data></array></value></member>
      </struct></value>

      <value><struct>
        <member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
        <member><name>params</name><value><array><data>
          <value><string>guest</string></value>
          <value><string>test</string></value>
        </data></array></value></member>
      </struct></value>
    </data></array></value>
  </param></params>
</methodCall>


將上面包含兩個子調用的 XML 請求POST至 xmlrpc 服務端入口,若目標開啓了 xmlrpc 服務會返回相似以下的信息:

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param>
      <value>
      <array><data>
  <value><array><data>
  <value><array><data>
  <value><struct>
  <member><name>isAdmin</name><value><boolean>1</boolean></value></member>
  <member><name>url</name><value><string>http://172.16.96.130/xampp/wordpress-4.3.1/</string></value></member>
  <member><name>blogid</name><value><string>1</string></value></member>
  <member><name>blogName</name><value><string>WordPress 4.3.1</string></value></member>
  <member><name>xmlrpc</name><value><string>http://172.16.96.130/xampp/wordpress-4.3.1/xmlrpc.php</string></value></member>
</struct></value>
</data></array></value>
</data></array></value>
  <value><struct>
  <member><name>faultCode</name><value><int>403</int></value></member>
  <member><name>faultString</name><value><string>用戶名或密碼不正確。</string></value></member>
</struct></value>
</data></array>
      </value>
    </param>
  </params>
</methodResponse>

從結果中能夠看到在同一次請求裏面處理了兩種賬號密碼組合,並以集中形式將結果返回,經過該種方式能夠極大地提升賬號爆破效率。


3.防禦建議

1) 經過配置 Apache、Nginx 等 Web 服務器來限制 xmlrpc.php 文件的訪問;

這裏舉例一個nginx的

location =/xmlrpc.php {
    deny all;
}

2) 添加防禦代碼至WordPress配置文件

在wordpress的配置文件  wp-config.php  中添加以下代碼

add_filter('xmlrpc_enabled', '__return_false');

3) 從官方插件庫中安裝 Disable XML-RPC https://wordpress.org/plugins/disable-xml-rpc/ 並啓用。

4) 在不影響站點運行的狀況下能夠直接刪除 xmlrpc.php 文件。(不建議)

 

三. wordpress 後臺默認地址

後臺默認地址是 http://yoursite/wp-login.php 這個地址很容易讓有意爆破者,或者爆破工具(好比:wpscan) 找到,咱們須要修改掉這個默認地址。

網上找到的不少作法是這樣。在主題的 functions.php 裏添加如下代碼

function login_protection() {
    if($_GET['word'] !='press')
        header('Location: /');
}
add_action('login_enqueue_scripts','login_protection');


這樣一來,後臺登陸的惟一地址就是 http://yoursite/wp-login.php?word=press,若是不是這個地址,就會自動跳轉到 http://yoursite/

可是,這並不能徹底解決爆破入口的問題,懂一些http的人能夠經過post來爆破該入口。


解決方案:

這裏推薦三個插件
WPS Hide Login: 修改登陸路由,來達到隱藏wordpress登陸入口暴露的問題
WPS Limit Login: 限制後臺登陸試錯次數,阻止黑客的IP地址



Brute Force Login Protection :跟 WPS Limit Login 功能差很少


四.restAPI

wordpress的restAPI也是能夠暴露用戶名的

GET http://yoursite/wp-json/wp/v2/users

[
    {
        "id": 1,
        "name": "nickname",
        "url": "",
        "description": "",
        "link": "http://yoursite/author/username",
        "slug": "username",
        "avatar_urls": {
            "24": "https://secure.gravatar.com/avatar/hashNumber?s=24&d=retro&r=g",
            "48": "https://secure.gravatar.com/avatar/hashNumber?s=48&d=retro&r=g",
            "96": "https://secure.gravatar.com/avatar/hashNumber?s=96&d=retro&r=g"
        },
        "meta": [],
        "_links": {
            "self": [
                {
                    "href": "http://yoursite/wp-json/wp/v2/users/1"
                }
            ],
            "collection": [
                {
                    "href": "http://yoursite/wp-json/wp/v2/users"
                }
            ]
        }
    }
]


 "link": "http://yoursite/author/username"  中  username  就是後臺用戶名了


解決方案:

方法一: 代碼中禁止

在wordpress的主題所在 functions.php 中添加以下代碼

過濾users端點,使未登陸用戶不能訪問

add_filter( 'rest_endpoints', function( $endpoints ){
    if(!is_user_logged_in()) {
        if ( isset( $endpoints['/wp/v2/users'] ) ) {
            unset( $endpoints['/wp/v2/users'] );
        }
        if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
            unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
        }
    }
    return $endpoints;
});


或者

徹底禁用未登陸用戶獲取api

/*禁用未登陸的用戶*/
function rest_only_for_authorized_users($wp_rest_server) {
    if ( !is_user_logged_in() ) {
        wp_die('非法操做!');
    }
}
add_filter('rest_api_init', 'rest_only_for_authorized_users', 99);


兩種方法,二選一


方法二:經過Web 服務器限制restAPI的訪問

這裏用nginx來舉例子,其餘服務器的設置請自行研究


全面禁用restAPI
location ~* /wp/v2/(.*) {
    deny all;
}
只禁用users端點
location ~* /wp-json/wp/v2/users(\/)?(.*)? {
    deny all;
}

 

方法三:WPS Bidouille插件

WPS Bidouille  中有個功能,能夠直接在後臺禁用掉restAPI的用戶端點,因此,你只須要將用戶端點在後臺禁用便可。也可直接禁用REST API。
此外,該插件還支持禁用做者頁面和做者連接,省掉了本文第一節的代碼操做。其餘功能詳見這裏

參考文章

  1. http://blog.knownsec.com/2015/10/wordpress-xmlrpc-brute-force-amplification-attack-analysis/
  2. https://blog.csdn.net/u013474104/article/details/78703122
相關文章
相關標籤/搜索