Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2023-39361 — Analyse étape par étape et configuration de laboratoire pour CVE-2023-39361, une injection SQL non authentifiée dans Cacti v1.2.24, avec une procédure d'exploitation et d'atténuation. | Kitploit
Outils/GitHubGitHub/hpt-intern-task-submission/cve-2023-39361
Analyse des VulnérabilitésExploitationExploitation d'Applications WebApprentissage et ÉducationLabs et Pratique
GitHubhpt-intern-task-submission/cve-2023-39361

CVE-2023-39361

Analyse étape par étape et configuration de laboratoire pour CVE-2023-39361, une injection SQL non authentifiée dans Cacti v1.2.24, avec une procédure d'exploitation et d'atténuation.

Voir le dépôt
10il y a 2 ansPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

[CVE-2023-39361] Injection SQL non authentifiée dans Cacti v1.2.24

Présentation

Cacti est un outil de surveillance opérationnelle open source écrit en PHP, MySQL/MariaDB, qui offre une interface conviviale. La vulnérabilité a été découverte en 2023 et affectait toutes les versions antérieures à 1.2.24. Cette faille de sécurité réside dans une implémentation incorrecte lors de l'insertion de valeurs dans une requête SQL. Il s'agit d'une injection SQL critique qui permet aux attaquants de modifier la base de données ainsi que d'exécuter du code à distance.

Configuration du laboratoire :

Dans cette analyse, je vais exécuter Cacti dans Docker par souci de simplicité. Tout d'abord, nous allons créer le fichier docker-compose.yml comme ci-dessous et exécuter la commande docker-compose up -d.

version: '3.5'

services:

  
  

cacti:

image: "smcline06/cacti"

container_name: CVE-2023-39361

domainname: example.com

hostname: cacti

ports:

- "80:80"

- "443:443"

environment:

- DB_NAME=cacti_master

- DB_USER=cactiuser

- DB_PASS=cactipassword

- DB_HOST=db

- DB_PORT=3306

- DB_ROOT_PASS=rootpassword

- INITIALIZE_DB=1

- TZ=America/Los_Angeles

volumes:

- cacti-data:/cacti

- cacti-spine:/spine

- cacti-backups:/backups

links:

- db

  
  

db:

image: "mariadb:10.3"

container_name: CVE-2023-39361_db

domainname: example.com

hostname: db

ports:

- "3306:3306"

command:

- mysqld

- --character-set-server=utf8mb4

- --collation-server=utf8mb4_unicode_ci

- --max_connections=200

- --max_heap_table_size=128M

- --max_allowed_packet=32M

- --tmp_table_size=128M

- --join_buffer_size=128M

- --innodb_buffer_pool_size=1G

- --innodb_doublewrite=ON

- --innodb_flush_log_at_timeout=3

- --innodb_read_io_threads=32

- --innodb_write_io_threads=16

- --innodb_buffer_pool_instances=9

- --innodb_file_format=Barracuda

- --innodb_large_prefix=1

- --innodb_io_capacity=5000

- --innodb_io_capacity_max=10000

environment:

- MYSQL_ROOT_PASSWORD=rootpassword

- TZ=America/Los_Angeles

volumes:

- cacti-db:/var/lib/mysql

  
  

volumes:

cacti-db:

cacti-data:

cacti-spine:

cacti-backups:

Après avoir construit le conteneur, nous pouvons accéder à Cacti en naviguant vers http://localhost:80. L'étape suivante consiste à mettre à jour Cacti vers la version 1.2.24. Vous pouvez télécharger le script de mise à jour ici : https://pastebin.com/NfRiHLjR. Enregistrez le fichier dans le même répertoire que le fichier docker-compose.yml et renommez-le en upgrade_cacti.sh. Exécutez ensuite ces 2 commandes :

docker cp upgrade_cacti.sh CVE-2023-39361:/tmp/upgrade_cacti.sh && docker exec -it CVE-2023-39361 bash -c "bash /tmp/upgrade_cacti.sh"

Maintenant, nous sommes prêts à plonger dans le code pour voir ce qui nous permet de mener une attaque par injection SQL. Le fichier vulnérable est graph_view.php et nous avons seulement besoin d'un utilisateur invité pour accéder à ce fichier, ce qui permet à tout le monde d'exploiter cette vulnérabilité. Dans ce fichier, la fonction non sécurisée est grow_right_pane_tree().

grow_right_pane_tree

Avant d'approfondir cette fonction, nous devons remonter pour comprendre comment elle est exécutée.

<?php
switch (get_nfilter_request_var('action')) {
//.... 
// De nombreux autres cas
case  'tree_content':
	//..... Du code ici
	// ---------
	if (isset_request_var('node')) {
		$parts = explode('-', sanitize_search_string(get_request_var('node')));
		// Vérifie l'ancre de l'arbre
		if (strpos(get_nfilter_request_var('node'), 'tree_anchor') !== false) {
			$tree_id = $parts[1];
			$node_id = 0;
		} 
	//..... Du code ici

	if ($tree_id > 0) {
		if (!is_tree_allowed($tree_id)) {
			header('Location: permission_denied.php');
			exit;
		}
		// La fonction vulnérable est appelée ici
		grow_right_pane_tree($tree_id, $node_id, $hgdata);
	}

D'après l'extrait de code ci-dessus, nous pouvons voir que la fonction sera exécutée si $tree_id > 0. Toutes les étapes peuvent être expliquées comme ci-dessous :

  • Tout d'abord, le programme prend la valeur du paramètre action de l'entrée utilisateur et entre dans une instruction switch/case.

  • Dans le cas tree_content, le code prend le paramètre node de la requête de l'utilisateur. Ensuite, il divise l'entrée par le caractère -, l'enregistre dans $part et vérifie enfin si tree_anchor apparaît dans node. Si toutes les conditions correspondent, $tree_id sera assigné comme second élément dans $part. Par exemple, tree_content-1 ou 1-2-tree_content seront valides et la valeur de $tree_id sera respectivement.

À partir de là, notre URL ressemblera à ceci : http://localhost:80?action=tree_content&node=tree_anchor-1. Il est maintenant temps d'analyser la fonction grow_right_pane_tree() pour exploiter le bug.

grow_right_pane_tree_analyze

Le paramètre vulnérable est rfilter qui est directement passé dans l'opérande RLIKE dans la clause WHERE. Ce qui le rend vulnérable, c'est que rfilter est entouré de guillemets doubles ", mais le paramètre est vérifié par la fonction html_validate_tree_vars(), qui ressemble à ceci :

function  html_validate_tree_vars() {
/* ================= validation des entrées et stockage en session ================= */
$filters = array(
	// .......
	'rfilter' => array(
			'filter' => FILTER_VALIDATE_IS_REGEX,
			'pageset' => true,
			'default' => '',
			),
	// ..........
	);

	validate_store_request_vars($filters, 'sess_grt');
	/* ================= validation des entrées ================= */
	// ........
}

Le type de filtre de rfilter est défini sur FILTER_VALIDATE_IS_REGEX et stocké dans $filters, puis $filter est passé dans la fonction validate_store_request_vars(). Plongeons dans cette fonction, cela révélera le reste de notre analyse :

function validate_store_request_vars($filters, $sess_prefix = '') {
	// .......
	if (cacti_sizeof($filters)) {
		foreach($filters as $variable => $options) {
		// ....
		elseif ($options['filter'] == FILTER_VALIDATE_IS_REGEX) {
					if (is_base64_encoded($_REQUEST[$variable])) {
						$_REQUEST[$variable] = base64_decode($_REQUEST[$variable]);
					}
					$valid = validate_is_regex($_REQUEST[$variable]);
					if ($valid === true) {
						$value = $_REQUEST[$variable];
					} else {
						$value = false;
						$custom_error = $valid;
					}
				}
// ........
function validate_is_regex($regex) {
// ........
    if (@preg_match("'" . $regex . "'", NULL) !== false) {
		ini_set('track_errors', $track_errors);
		return true;
	}

La fonction validate_store_request_vars() est responsable de la validation des entrées utilisateur. Lorsque le type de filtre est FILTER_VALIDATE_IS_REGEX, la fonction appelle la fonction validate_is_regex() avec la fonction preg_match pour vérifier si notre entrée est valide. Selon la documentation PHP :

preg_match() retourne 1 si le pattern correspond au subject donné, 0 si ce n'est pas le cas, ou false en cas d'échec.

Télécharger l’outil