Le 24 juin 2020, notre équipe Threat Intelligence a été informée d’une éventuelle vulnérabilité du plugin Adning Advertising, un plugin premium avec plus de 8000 clients. Nous avons finalement découvert 2 vulnérabilités, dont l’une était une vulnérabilité critique qui permettait à un attaquant non authentifié de télécharger des fichiers arbitraires, conduisant à l’exécution de code à distance (RCE), ce qui pourrait permettre une prise de contrôle complète du site.

Le lendemain, le 25 juin 2020, nous avons divulgué en privé ces vulnérabilités à l’auteur du plugin, Tunafish. Une version corrigée a été mise à disposition en moins de 24 heures, le 26 juin 2020. Nous vous recommandons fortement de mettre à jour la dernière version de ce plugin, 1.5.6, immédiatement.

Les utilisateurs de Wordfence Premium ont reçu une règle de pare-feu protégeant contre ces vulnérabilités le 25 juin 2020. Les utilisateurs qui utilisent toujours la version gratuite de Wordfence recevront cette règle le 25 juillet 2020.

Après avoir surveillé les attaques contre cette règle de pare-feu, nous avons déterminé que, bien que ces vulnérabilités soient attaquées dans la nature, les attaques étaient extrêmement limitées dans leur portée et leur ampleur. En tant que tel, nous avons caché les détails de la divulgation publique pendant une courte période de temps pour permettre aux utilisateurs de mettre à jour et d’empêcher une exploitation plus répandue.


L’une des fonctionnalités du plugin Adning est de permettre aux utilisateurs de télécharger des images de bannière. Afin de fournir cette fonctionnalité, il a utilisé une action AJAX, _ning_upload_image. Malheureusement, cette action AJAX était disponible avec un nopriv_ hook, ce qui signifie que tout visiteur du site peut l’utiliser, même s’il n’est pas connecté. De plus, la fonction appelée par cette action AJAX n’a ​​pas non plus pu utiliser une vérification de capacité ou une vérification nonce.

	public static function _ning_upload_image()
	{
		$_action = isset($_POST['action']) ? $_POST['action'] : '';
		$user_id = isset($_POST['uid']) ? $_POST['uid'] : 0;
		$banner_id = isset($_POST['bid']) ? $_POST['bid'] : 0;
		$max_upload_size = isset($_POST['max_upload_size']) ? $_POST['max_upload_size'] : 100;
		$upload = isset($_POST['upload']) ?  json_decode(stripslashes($_POST['upload']), true) : array();
		$valid_formats = isset($_POST['allowed_file_types']) ? explode(',', $_POST['allowed_file_types']) : array('jpg');
		if( in_array('jpg', $valid_formats) )
		{
			$valid_formats[] = 'jpeg';
		}
		
		//$max_file_size = 1024*100; //100 kb
		//$max_file_size = 1024000*15; // 15 MB (1 mb = 1000 kb)
		$max_file_size = 1024000*$max_upload_size;
		
		//$upload_path = $upload_dir.'/'.$upload_folder;
		//$upload_path = $upload_path.$upload_folder;
		$upload_path = $upload['dir'].$upload['folder'];
		$count = 0;

		// Create upload folder if not exists
		if(!is_dir($upload_path)) {
		    mkdir($upload_path, 0777, true);
		}

		if(!empty($_FILES['files'])) 
		{
			$upload_success = false;
			$upload_error = '';
			$uploaded_files = array();
			$unzip_error = array();

			// Loop $_FILES to execute all files
			foreach ($_FILES['files']['name'] as $f => $name) 
			{     
			    if ($_FILES['files']['error'][$f] == 4) 
			    {
			        continue; // Skip file if any error found
			    }	       
			    if ($_FILES['files']['error'][$f] == 0) 
			    {	           
			        if ($_FILES['files']['size'][$f] > $max_file_size) 
			        {
			            $upload_error = $name. " is too large!";
			            continue; // Skip large files
			        }
					elseif( !in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats) )
					{
						$upload_error = $name." is not a valid format";
						continue; // Skip invalid file formats
					}
			        else
			        { 
			        	// No error found! Move uploaded files 
			            if(move_uploaded_file($_FILES["files"]["tmp_name"][$f], $upload_path.$name)){
			            	$count++; // Number of successfully uploaded file
							$src = $upload['src'].$upload['folder'].$name;

			            	// Copy image to banner folder
			            	/*if(!empty($banner_id))
			        		{
			        			if(!is_dir($upload_dir.'/'.$banner_folder)) {
								    mkdir($upload_dir.'/'.$banner_folder, 0777, true);
								}
			        			copy($path.$name, $upload_dir.'/'.$banner_folder.$name);
			        		}*/

			        		$uploaded_files[] = array(
			        			'name' => $name, 
								'size' => $_FILES['files']['size'][$f],
								'upload' => $upload,
								'path' => $upload_path.$name,
			        			'src' => $src,
			        			'grid_item' => '
', 'uid' => $user_id, 'action' => $_action ); if( pathinfo($name, PATHINFO_EXTENSION) == 'zip') { $zipfile = array( 'name' => $_FILES['files']['name'][$f], 'type' => $_FILES['files']['type'][$f], 'tmp_name' => $_FILES['files']['tmp_name'][$f], 'error' => $_FILES['files']['error'][$f], 'size' => $_FILES['files']['size'][$f], ); $unzip_error = self::upload_and_unzip($zipfile, array('folder' => $upload['folder'], 'path' => $upload_path, 'src' => $upload['src'])); } } else { $upload_error = is_writable($upload_path) ? 'Could not move files.' : 'Folder is not writable.'; } } } } if(count($uploaded_files) > 0){ $upload_success = true; } echo json_encode(array("chk" => $_FILES['files'], "unzip" => $unzip_error, "upload" => $upload, "success" => $upload_success, "files" => json_encode($uploaded_files), "error" => $upload_error)); }else{ echo 'no files found.'; } exit; }

Cette fonction a également permis à l’utilisateur de fournir les types de fichiers «autorisés». En tant que tel, il était possible pour un attaquant non authentifié de télécharger du code malveillant en envoyant un POST demande à wp-admin/admin-ajax.php avec le action paramètre défini sur _ning_upload_image les allowed_file_types mis à php, et un files paramètre contenant un fichier PHP malveillant. Alternativement, un attaquant pourrait allowed_file_types à zip et téléchargez une archive compressée contenant un fichier PHP malveillant, qui serait décompressé après le téléchargement. Il était également possible pour un attaquant de modifier le répertoire de téléchargement en manipulant le contenu du upload paramètre – si le répertoire souhaité n’existait pas, le plugin le créerait.


Afin de supprimer les images téléchargées, le plugin a également enregistré une autre action ajax, _ning_remove_image, qui utilisait également un nopriv_ crochet. Comme pour la vulnérabilité de téléchargement, cette fonction n’a pas effectué de vérification de capacité ou de nonce. En tant que tel, il était possible pour un attaquant non authentifié de supprimer des fichiers arbitraires en utilisant la traversée de chemin.

Si un attaquant pouvait supprimer wp-config.php, le site serait réinitialisé, et un attaquant pourrait alors le reconstituer et le diriger vers une base de données distante sous leur contrôle, remplaçant ainsi efficacement le contenu du site par leur propre contenu.

	public static function _ning_remove_image()
	{
		$upload = wp_upload_dir();
		$upload_dir = $upload['basedir'];
		$upload_url = $upload['baseurl'];
		$upload_folder = self::$upload_folder.$_POST['uid'].'/';	

		$path = $upload_dir.'/'.$upload_folder.basename($_POST['src']);
		$removed = 0;

		if(unlink($path)){
			$remove = 1;
		}
		echo $remove;

		exit;
	}

Cette attaque peut nécessiter une étape supplémentaire de préparation, à savoir que le wp-content/uploads/path le dossier devrait exister. Cependant, comme la vulnérabilité de téléchargement de fichiers arbitraire mentionnée précédemment permettait la création de répertoires, ce n’était pas un obstacle majeur. Une fois le répertoire créé, un attaquant pourrait envoyer un POST demande à wp-admin/admin-ajax.php avec le action paramètre défini sur _ning_remove_image, les uid paramètre défini sur /../../.. et le src paramètre défini sur wp-config.php.

Chronologie

24 juin 2020 – Wordfence Threat Intelligence reçoit un rapport d’un site Web compromis exécutant le plug-in Adning. Au cours de notre enquête, nous avons découvert deux vulnérabilités.
25 juin 2020 – Règle de pare-feu publiée pour les utilisateurs Premium de Wordfence. Nous prenons contact avec l’auteur du plugin et envoyons une divulgation complète après avoir reçu une réponse.
26 juin 2020 – L’auteur du plugin publie un patch.
25 juillet 2020 – La règle de pare-feu devient disponible pour les utilisateurs gratuits de Wordfence.

Conclusion

Dans le post d’aujourd’hui, nous avons discuté de deux vulnérabilités dans le plugin Adning Advertising qui pourraient permettre à un attaquant de reprendre complètement un site Web. Ces failles ont été entièrement corrigées dans la version 1.5.6. Si vous exécutez ce plugin, il est essentiel que vous mettiez à jour cette version dès que possible. Sites en cours d’exécution Wordfence Premium sont protégés contre ces vulnérabilités depuis le 25 juin 2020, tandis que les sites utilisant toujours la version gratuite de Wordfence recevront la règle de pare-feu le 25 juillet 2020.

Un merci spécial à Tunafish, l’auteur du plugin Adning Advertising, pour leur réponse excellente et opportune lors de la publication d’un patch.


Source link

%d blogueurs aiment cette page :