WordPress5.0.0 遠程代碼執行

原文鏈接:https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/


a06603d0617c5d4e5b9c883234c74675.png

這篇博文講述了利用目錄穿越和本地文件包含漏洞的“組合拳”在WordPress核心功能實現遠程代碼執行。過去6年,該WordPress漏洞一直未被揭示。

影響

POC視頻1

攻擊者需要在目標WordPress網站擁有至少作者級權限的賬戶,然後就能在後臺服務器執行任意的php代碼,從而遠程攻陷目標。我們向WordPress安全團隊報告了另一個漏洞的詳情,該漏洞可以讓攻擊者入侵任何的WordPress站點,目前尚在修復中。

受影響版本

受一個安全補丁的限制,文中描述的漏洞在這4.9.9和5.0.1版本中無法利用。但目錄穿越漏洞依然存在並且未被修補。本漏洞可利用在安裝了對Post Meta記錄處理不當的插件的WordPress網站上。在之前的WordPress安全月活動中,我們已經見識過一些存在問題的安裝量過百萬的插件。

據WordPress網站的下載頁面稱,全網超過33%的網站在使用WordPress。考慮到插件可能會重新引入漏洞,以及其他因素如網站WordPress版本過舊等,受影響的網站數仍然是百萬級。

技術分析

目錄穿越和本地文件包含漏洞都是由我公司的主打的SAST(靜態應用安全測試)解決方案RIPS自動檢測到的,你只需要點擊按鈕,它就會在3分鐘內完成掃描。不過,這些bug一開始看上去無法利用。事實證明,利用這些漏洞要複雜的多,好在有可能利用。

POC視頻2

背景知識——WordPress圖片管理

當圖片上傳到WordPress網站時,它先被存儲到上傳目錄(wp-content/uploads)下。WordPress會在數據庫中生成一條關於圖片的引用,來記錄圖片屬主、上傳時間等元信息。這些元信息在庫中以Post Meta記錄的形式存在,每條記錄都是鍵值對,並被分配一個確定ID。

0a026c44b09f5cdedda315b8ef791cd9.png

如上圖,已爲圖片分配的post_ID號爲50,如果用戶以後想使用或修改ID所屬的圖片,WordPress將查找匹配_wp_attached_file的元記錄,並用它的值去wp-content/uploads目錄下尋找文件。

核心問題——Post Meta記錄被覆蓋

在WordPress4.9.9和5.0.1之前的版本中,主要問題在於可以修改任意Post Meta記錄並將設置它們的值。當圖片更新時(例如,它的描述發生變化)會調用edit_post()函數。該函數直接操作$ _POST數組。

1   function edit_post( $post_data = null ) {
2
3       if ( empty($postarr) )
4            $postarr = &$_POST;
56       if ( ! empty( $postarr['meta_input'] ) ) {
7           foreach ( $postarr['meta_input'] as $field => $value ) {
8               update_post_meta( $post_ID, $field, $value );
9           }
10     }

如上所示,我們可以注入任意的Post Meta記錄。因爲沒有關於記錄修改得檢查,攻擊者可以更新_wp_attached_file 元記錄並把它設置爲任何值。這並不會重命名真實文件,但它會更改WordPress在編輯圖像時要尋找的文件名。這將導致之後的目錄穿越漏洞。

修改Post Meta造成目錄穿越

當用戶裁剪圖片時會調用wp_crop_image()函數,目錄穿越漏洞就發生在這裏。

該函數獲取要裁剪圖片的ID($attachment_id)並從數據庫中提取對應的_wp_attached_filePost Meta記錄。

還記得麼,由於edit_post()函數的缺陷,$src_file可以被設定成任意值。

1   function wp_crop_image( $attachment_id, $src_x, ...) {
2
3       $src_file = $file = get_post_meta( $attachment_id, '_wp_attached_file' );
4

接下來,WordPress必須確保圖片實際存在並加載它。 WordPress有兩種加載指定圖片的方法。第一種是簡單地查找wp-content/uploads目錄中的由_wp_attached_filePost Meta記錄提供的文件名(下一代碼段的第2行)。

如果這一方法失敗,WordPress將嘗試從其自己的服務器下載圖片以作備用。爲此,它將生成一個下載URL,該URL由wp-content/uploads目錄的URL和存儲在_wp_attached_filePost Meta記錄中的文件名構成(下一代碼段的第6行)。

舉個栗子:如果存儲在_wp_attached_filePost Meta記錄中的值是evil.jpg,那麼WordPress將首先嚐試檢查文件wp-content/uploads/evil.jpg是否存在。如果不存在,它將從以下URL下載該文件:https://targetserver.com/wp-content/uploads/evil.jpg

之所以選擇下載圖片而不是在本地查找,是因爲有時某些插件會在用戶訪問URL時動態生成圖像。

請注意,這裏沒有任何過濾。WordPress將簡單地拼接上傳目錄的基礎URL和用戶輸入的$src_file

一旦WordPress通過wp_get_image_editor()函數成功加載了有效圖片,它便開始裁剪圖片。

   12    if ( ! file_exists( "wp-content/uploads/" . $src_file ) ) {
   3            // If the file doesn't exist, attempt a URL fopen on the src link.
   4            // This can occur with certain file replication plugins.
   5         $uploads = wp_get_upload_dir();
   6         $src = $uploads['baseurl'] . "/" . $src_file;
   7     } else {
   8         $src = "wp-content/uploads/" . $src_file;
   9     }
  10
  11     $editor = wp_get_image_editor( $src );
  12

接着,裁剪後的圖片會被保存迴文件系統(無論是下載的還是本地的)。生成的文件名是get_post_meta()返回的$src_file的值,它正好可以由攻擊者控制。生成的文件名由一條規則生成:在文件的原始名稱前添加cropped-(下一代碼段的第4行)。在本例中,生成的文件名爲cropped-evil.jpg

然後WordPress就會通過wp_mkdir_p()函數(第6行)在結果路徑中創建任何之前不存在的目錄。

最後,它使用圖像編輯器對象的save()方法將其寫入文件系統。save()方法也不對給定的文件名做目錄穿越漏洞檢查。

    12   $src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs );
    3
    4   $dst_file = str_replace( basename( $src_file ), 'cropped-' . basename( $src_file ), $src_file );
    5
    6   wp_mkdir_p( dirname( $dst_file ) );
    7
    8   $result = $editor->save( $dst_file );

利用思路

到目前爲止,我們發現由於沒有做檢查,可以確定哪個文件被加載到圖像編輯器中。但是,如果文件不是張有效圖像,圖像編輯器對象將拋出異常。這裏可以假設:WordPress只能裁剪上傳目錄之外的圖片。

但是,如果WordPress未找到圖片,會嘗試下載圖片,將會導致遠程執行代碼漏洞。

本地文件 HTTP下載
已上傳文件 evil.jpg evil.jpg
_wp_attached_file evil.jpg?shell.php evil.jpg?shell.php
加載時結果文件 wp-content/uploads/evil.jpg?shell.php https://targetserver.com/wp-content/uploads/evil.jpg?shell.php
實際位置 wp-content/uploads/evil.jpg https://targetserver.com/wp-content/uploads/evil.jpg
生成的文件名 None-image loading fails evil.jpg?cropped-shell.php

我們的思路是將_wp_attached_file設置爲evil.jpg?shell.php,這將導致對以下URL發出HTTP請求:https://targetserver.com/wp-content/uploads/evil.jpg?shell.php,這個請求會返回一個有效的圖像文件。因爲在此處的上下文中,文件名?之後的部分會被忽略。生成的文件名將是evil.jpg?shell.php

圖像編輯器的save()方法雖然不會檢查目錄穿越漏洞,但它會添加加載圖片的mime類型的擴展名到生成的文件名中。在本例中,生成的文件名是evil.jpg?cropped-shell.php.jpg。這使得新創建的文件再次無法利用。

但是,仍然可以使用諸如evil.jpg?/../../evil.jpg之類的有效攻擊載荷將生成的圖像植入任何目錄。

在主題目錄下利用目錄穿越&LFI

每個WordPress主題都是wp-content/themes目錄下的一個目錄,併爲不同的情形提供模板。例如,如果博客的訪問者想看帖子,WordPress會在當前活動主題的目錄中查找post.php文件。如果該PHP文件找到了模板,就會include()它。

WordPress中允許爲某些帖子選擇自定義模板。用戶需要將數據庫中的_wp_page_templatePost Meta記錄設定爲特定的文件名。這裏的唯一限制是被include()的文件必須位於當前活動主題的目錄中。

通常,該目錄無法訪問,也無法上載文件。但是,通過利用上述的目錄穿越漏洞,可以將惡意製作的圖像植入到當前使用的主題的目錄中。然後,攻擊者可以利用同一漏洞創建一個新帖子,使他能夠更新_wp_attached_file的Post Meta記錄來include()圖像。通過將PHP代碼注入圖片數據中,攻擊者可以拿到遠程執行代碼漏洞。

構造惡意圖片——GD和Imagick

WordPress的PHP支持兩種圖像編輯擴展:GD和Imagick。它們的區別在於Imagick不會刪除圖像的exif元數據,而exif中可以存儲PHP代碼。 GD會壓縮它編輯的每個圖像並刪除所有exif元數據。

但是,通過精心構造圖片的像素仍然可以實現利用。這些像素將在GD處理完圖像後以某種方式翻轉,最終執行PHP代碼。在研究PHP GD擴展的內部結構時,我們在libgd中發現了可利用的內存損壞漏洞。(CVE-2019-69772)

時間線

日期 事件
2018/10/16 在Hackerone上向WordPress安全團隊報告了漏洞。
2018/10/18 WordPress安全團隊成員確認該報告,並表示他們將在報告得到驗證後返回。
2018/10/19 另一位WordPress安全團隊成員要求提供更多信息。
2018/10/22 我們爲WordPress提供了更多信息,並提供了完整的270行漏洞利用腳本來幫助驗證漏洞,
2018/11/15 WordPress對漏洞進行了分類,並表示他們能夠複製漏洞。
2018/12/06 WordPress 5.0已發佈,沒有針對該漏洞的補丁。
2018/12/12 WordPress 5.0.1已發佈,是一個安全更新。其中一個補丁通過阻止攻擊者設置任意設置元記錄,使漏洞無法利用。但是,目錄穿越仍然可以使用,如果安裝了錯誤處理Post Meta記錄的插件,則可以利用它。 WordPress 5.0.1不解決路徑遍歷或本地文件包含漏洞。
2018/12/19 WordPress 5.0.2發佈了。沒有針對漏洞的補丁。
2019/01/09 WordPress 5.0.3發佈了。沒有針對漏洞的補丁。
2019/01/28 我們要求WordPress提供下一個安全版本的ETA,以方便我們安排博客日程,並在WordPress新版本發佈後發表博客。
2019/02/14 WordPress提出了一個補丁。
2019/02/14 我們提供有關補丁的反饋,並驗證它是否可以防止利用。

總結

本文詳細介紹了WordPress核心功能中的遠程執行代碼,該漏洞已存在超過6年。根據RIPS的報告,在5.0.1和4.9.9版本中由於另一個漏洞的補丁,它變得不可利用。但是,目錄穿越仍然可以使用,如果安裝了仍允許任意覆蓋Post Data的插件,則可以利用該漏洞。由於在攻擊目標WordPress站點時需要通過身份認證,因此我們決定在首次報告漏洞的4個月後公開此漏洞。

感謝WordPress安全團隊的志願者,他們在這個問題上與我們合作得十分友好,也很專業。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章