網管當心身後眼!WordPress這次漏了你的用戶數據(WordPress錯誤處理:WP_Error 類)
網管當心身後眼!WordPress這次漏了你的用戶數據
WordPress是一種使用PHP語言開發的博客平台,用戶可以在支持PHP和MySQL資料庫的伺服器上架設屬於自己的網站。也可以把 WordPress當作一個內容管理系統來使用。
WordPress 在4.7.0版本以及之後版本將REST API插件集成到默認功能之中。REST API為WordPress的使用者提供了一個方便快捷的管理介面。在WordPress 4.7.0版本中,存在著一個越權漏洞,成功的利用這個漏洞,可以繞過管理員許可權查看wordpress上所有發布過文章的用戶信息列表。
影響版本
● WordPress 4.7.0
漏洞分析
在正式的漏洞分析開始前,先來簡單介紹下REST API的使用。官網給出的介紹如下:
具體使用詳情請參照REST API Handbook
https://developer.wordpress.org/rest-api/
漏洞利用
先從exploitdb上面提供的poc入手
https://www.exploit-db.com/exploits/41497/
POC看起來比較簡單,就是調用了wordpress的rest api介面進行users查詢,但是在筆者的環境中,需要對這個poc進行一點小改動,如下圖,需要加上一個index.php,否則找不到目錄。
接下來看一下代碼, 請求首先進入get_items_permissions_check模塊進行許可權檢查
看上面的注釋可以大概了解這個函數的功能:當請求users參數時,用來檢查請求是否有讀的許可權,否則爆出WP_Error錯誤。
這個函數一共有三個if判斷,這三個if判斷都是由兩部分組成的,每一個後半部分都是不可控的current_user_can( 『list_users』 ),經測試,它的值還為false,所以只能使三個if得可控的前半部分不為真,才能最終繞過判定。
我們var_dump下這三個$request值
有意思的事情發生了,我們什麼事情也沒做,竟然完美的避開了許可權檢查的三個判定,接下來進入下個環節get_items函數,檢索所有的用戶。
上面代碼省略了些內容,前半部分省略的是一些相關的參數配置,然後讀到注釋部分了解到下面參數經過過濾,就要進入WP_User_Query部分了,我們通過給出的鏈接看一下查詢部分的WP_User_Query是怎麼解釋的。
在跟進WP_User_Query中我們可以看到一個構造方法
在這裡可以看到如果$query不為空,則先調用prepare_query,接著再執行$this->query
我們看一下prepare_query是做什麼的。
看注釋可以了解到,它是準備查詢變數的作用,可以看做是對變數的預處理。接下來往後看$this->query;。跟進query函數看看它最終執行了什麼。
query函數使用當前變數來執行查詢,下面$this->request構造了一個sql查詢語句,我們查看下它的值
可以看出這裡可以查詢的wp_users信息是有約束條件的,這裡可以查詢的用戶必須滿足發表過『publish』類型的文章,並且類型還要是『post』、『page』、『attachment』中的一個
我們分別看一下wp_users表和wp_posts表
wp_posts表
wp_users表
最終通過api返回的用戶信息
修補防禦
升級wordpress至最新版本。
詳情請點擊文末「閱讀原文」
請點擊屏幕右上方「…」
關注綠盟科技公眾號
NSFOCUS-weixin
↑↑↑長按二維碼,下載綠盟雲APP
WordPress錯誤處理:WP_Error 類
在WordPress的運行中難免會產生一些錯誤,我們不希望錯誤直接阻止了用戶對網站的順暢訪問。
這裡指的錯誤並不是 PHP 代碼錯誤。而是在處理一些數據的時候產生的,尤其是處理表單數據,因為不可能所有用戶都會完全按照我們的要求提交數據。
比如,在註冊用戶的時候需要用戶填寫電子郵件。用戶可能會輸入不符合電子郵件格式的內容,或者這個電子郵件已經有用戶使用,那麼就會產生一個錯誤,導致用戶無法順利註冊。
由於錯誤多種多樣,WordPress 使用了一個 WP_Error 類來統一錯誤的保存方式,有了統一的方式,插件和主題就能更好的讀取和添加一些錯誤,也能簡化錯誤的儲存代碼。
屬性
$errors
用於儲存所有的錯誤。
$error_data
儲存錯誤的額外數據。
這些屬性均為類私有(private)。
方法
get_error_codes()
獲取所有錯誤代碼。
get_error_code()
獲取第一個可用的錯誤代碼,如果沒有則返回空。
get_error_messages( $code = ” )
獲取一個錯誤的所有錯誤消息。
get_error_message( $code = ” )
獲取一個錯誤的第一個錯誤消息。
get_error_data( $code = ” )
獲取錯誤的額外數據,沒有額外數據返回 null.
add( $code, $message, $data = ” )
添加一個錯誤信息。
add_data( $data, $code = ” )
添加錯誤的額外數據。
WP_Error( $code = ”, $message = ”, $data = ” ), __construct( $code = ”, $message = ”, $data = ” )
WP_Error 的構造函數,實例化類的時候自動運行,所有的參數都是可選的。可以直接在實例化類的時候添加一個錯誤。
使用方法
比如下邊這個郵件發送函數,如果發生錯誤,就會把錯誤返回出去。任何錯誤都沒產生,而且郵件發送順利則返回 True.
1 2 3 4 5 6 7 8 9 |
function tiezhu_send_mail( $email ){ if( empty( $email ) ) return new WP_Error( \'empty_email\', \'郵箱不能為空\' ); if( !is_email( $email ) ) return new WP_Error( \'invalid_email\', \'郵箱格式不正確\' ); if( wp_mail( $email, \'測試郵件\', \'Hello World\' ) ) return true; return new WP_Error( \'send_error\', \'郵件發送失敗\' ); } |
下方是一個註冊表單的處理函數,裡邊多次使用了 WP_Error:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
function tiezhu_register_user(){ $sanitized_user_login = sanitize_user( $_POST[\'username\'] ); $user_email = apply_filters( \'user_registration_email\', $_POST[\'email\'] ); $register_errors = new WP_Error; //驗證用戶名 if( empty( $sanitized_user_login ) ) $register_errors->add( \'empty_username\', __( \'用戶名不能為空\', \'Bing\' ) ); elseif( !validate_username( $sanitized_user_login ) ) $register_errors->add( \'invalid_username\', __( \'用戶名包含無效字元\', \'Bing\' ) ); elseif( username_exists( $sanitized_user_login ) ) $register_errors->add( \'username_exists\', __( \'用戶名已經存在\', \'Bing\' ) ); //驗證郵箱 if( empty( $user_email ) ) $register_errors->add( \'empty_email\', __( \'郵箱不能為空\', \'Bing\' ) ); elseif( !is_email( $user_email ) ) $register_errors->add( \'invalid_email\', __( \'郵箱格式不正確\', \'Bing\' ) ); elseif( email_exists( $user_email ) ) $register_errors->add( \'email_exists\', __( \'郵箱已經存在\', \'Bing\' ) ); //註冊表單提交事件 do_action( \'register_post\', $sanitized_user_login, $user_email, $register_errors ); //錯誤過濾器 $register_errors = apply_filters( \'registration_errors\', $register_errors, $sanitized_user_login, $user_email ); //註冊用戶 if( !$register_errors->get_error_message() ){ $register_new_user = register_new_user( $sanitized_user_login, $user_email ); if( is_wp_error( $register_new_user ) ) return $register_new_user; return true; } return $register_errors; } |
判斷 WP_Error
在很多時候我們要判斷函數返回的到底是 WP_Error 還是其它內容,因為 WP_Error 是一個類,所以無法通過 True 或 False 直接判斷。
WordPress 提供了一個 is_wp_error() 函數,用它我們就能判斷變數是否是 WP_Error:
1. 帶 [親測] 說明源碼已經被站長親測過!
2. 下載後的源碼請在24小時內刪除,僅供學慣用途!
3. 分享目的僅供大家學習和交流,請不要用於商業用途!
4. 本站資源售價只是贊助,收取費用僅維持本站的日常運營所需!
5. 本站所有資源來源於站長上傳和網路,如有侵權請郵件聯繫站長!
6. 沒帶 [親測] 代表站長時間緊促,站長會保持每天更新 [親測] 源碼 !
7. 盜版ripro用戶購買ripro美化無擔保,若設置不成功/不生效我們不支持退款!
8. 本站提供的源碼、模板、插件等等其他資源,都不包含技術服務請大家諒解!
9. 如果你也有好源碼或者教程,可以到審核區發布,分享有金幣獎勵和額外收入!
10.如果您購買了某個產品,而我們還沒來得及更新,請聯繫站長或留言催更,謝謝理解 !
GG資源網 » 網管當心身後眼!WordPress這次漏了你的用戶數據(WordPress錯誤處理:WP_Error 類)