Les périphériques de stockage amovibles tels que les clés USB sont des outils indispensables pour le transfert de données, les sauvegardes et la récupération du système. Cependant, ils représentent également un risque sérieux pour la sécurité s’ils ne sont pas gérés, en particulier dans les environnements d’entreprise ou de MSP. Savoir si l’accès au stockage USB est activé sur vos systèmes Linux n’est pas seulement une question de commodité : c’est une question d’application de politique, de conformité à la sécurité et de sensibilisation opérationnelle. Cet article présente un script shell qui automatise le processus pour vérifier l’état du stockage USB dans Linux avec un script shell et qui s’intègre éventuellement à NinjaOne pour rapporter les résultats.
Contexte
Sous Linux, le contrôle de l’accès au stockage USB est principalement assuré par des modules du noyau, en particulier les pilotes usb_storage et uas (USB Attached SCSI). Les administrateurs système peuvent désactiver ces pilotes en les plaçant sur une liste noire ou en les configurant pour qu’ils exécutent des commandes inoffensives au lieu de se charger.
Le script présenté ici est conçu pour inspecter le répertoire /etc/modprobe.d, où se trouvent généralement ces règles de chargement de modules. C’est particulièrement important dans les environnements gérés par NinjaOne, où une supervision centralisée et des contrôles de conformité automatisés sont essentiels. Les fournisseurs de services gérés (MSP) et les équipes informatiques internes bénéficient de ce type d’outils pour s’assurer que les terminaux sont conformes aux politiques de l’entreprise.
Le script :
#!/usr/bin/env bash # Description: Checks if the linux machine currently allows access to USB storage devices and optionally saves the results to a custom field. # By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use. # Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. # Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. # Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. # Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. # Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. # Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. # EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA). # # The script checks the modprobe.d folder for any files that may block the USB storage driver or the USB Attached SCSI driver. # There are two methods of loading USB storage drivers that allow mounting of USB storage devices: # 1. Implicit loading: The USB storage driver is loaded automatically when a USB storage device is connected. # 2. Explicit loading: The USB storage driver is loaded manually by a user, program, or script. # # Release Notes: Initial Release # # Preset Parameter: -CustomField "usbStorageStatus" # The custom field to save the USB storage status to. # # Preset Parameter: --help # Displays the help menu. # # Functions # Print an error message and exit with a specific status code die() { local _ret="${2:-1}" test "${_PRINT_HELP:-no}" = yes && print_help >&2 echo "$1" >&2 exit "${_ret}" } print_help() { printf '\n\n%s\n\n' 'Usage: [-CustomField "custom_field_name"]' printf ' %s\n' '-CustomField' printf ' The custom field to save the USB storage status to.\n' } # Parse the command-line arguments parse_commandline() { while test $# -gt 0; do _key="$1" case "$_key" in -CustomField | --CustomField | -customfield | --customfield | -cf | --cf) _arg_customfield="CustomField" ;; --help | -help | -h | --h) _PRINT_HELP=yes die "" 0 ;; *) _PRINT_HELP=yes die "[Error] Got an unexpected argument '$1'" 1 ;; esac shift done } function SetCustomField() { if [[ -z "$1" ]] || [[ -z "$2" ]]; then echo "[Error] Missing required arguments." return 1 fi local customfieldName=$1 local customfieldValue=$2 if [ -f "${NINJA_DATA_PATH}/ninjarmm-cli" ]; then if [ -x "${NINJA_DATA_PATH}/ninjarmm-cli" ]; then if "$NINJA_DATA_PATH"/ninjarmm-cli get "$customfieldName" >/dev/null; then # check if the value is greater than 10000 characters if [ ${#customfieldValue} -gt 10000 ]; then echo "[Warn] Custom field value is greater than 10000 characters" >&2 return 1 fi if ! echo "${customfieldValue::10000}" | "$NINJA_DATA_PATH"/ninjarmm-cli set --stdin "$customfieldName"; then echo "[Warn] Failed to set custom field" >&2 return 1 else echo "[Info] Custom field value set successfully" fi else echo "[Warn] Custom Field ($customfieldName) does not exist or agent does not have permission to access it" >&2 return 1 fi else echo "[Warn] ninjarmm-cli is not executable" >&2 return 1 fi else echo "[Warn] ninjarmm-cli does not exist" >&2 return 1 fi } parse_commandline "$@" # If script form variables are used, replace the command line parameters with their value. if [[ -n "${customField}" ]]; then _arg_customfield="${customField}" fi # Variables # Modprobe.d folder modprobFolder="/etc/modprobe.d" # Check if we have read access to the modprobe.d folder if ! [ -r "${modprobFolder}" ]; then if [[ -n "${_arg_customfield}" ]]; then SetCustomField "${_arg_customfield}" "Unable to Determine" fi die "[Error] User ${USER} has no read access to modprobe.d folder" 1 fi # Check if modprobe.d folder does not exist if ! [ -d "${modprobFolder}" ]; then if [[ -n "${_arg_customfield}" ]]; then SetCustomField "${_arg_customfield}" "Unable to Determine" fi die "[Error] Modprobe folder does not exist" 1 fi # Set default values UsbStorage="Enabled" usb_storage_status="Enabled" uas_status="Enabled" usb_storage_driver_status="Enabled" uas_driver_status="Enabled" # Check if usb_storage or uas is blocked in other files for file in "${modprobFolder}"/*; do if ! [ -r "${file}" ]; then echo "[Warn] User ${USER} has no read access to ${file}" fi # Check if implicit loading is blocked if grep -q "blacklist usb_storage" "${file}"; then echo "[Info] USB storage driver is blocked in ${file}" usb_storage_status="Disabled" fi # Check if implicit loading is blocked if grep -q "blacklist uas" "${file}"; then echo "[Info] USB Attached SCSI driver is blocked in ${file}" uas_status="Disabled" fi # Check if explicit loading is blocked if grep -q "install usb-storage /bin/true" "${file}"; then echo "[Info] USB storage driver is blocked in ${file}" usb_storage_driver_status="Disabled" fi # Check if explicit loading is blocked if grep -q "install uas /bin/true" "${file}"; then echo "[Info] USB Attached SCSI driver is blocked in ${file}" uas_driver_status="Disabled" fi done # Output the status of implicit loading if [ "${usb_storage_status}" == "Disabled" ] && [ "${uas_status}" == "Disabled" ]; then echo "[Info] USB storage driver implicit loading: Blocked" elif [ "${usb_storage_status}" == "Enabled" ] && [ "${uas_status}" == "Enabled" ]; then echo "[Info] USB storage driver implicit loading: Allowed" else echo "[Info] USB storage driver implicit loading: Partially Allowed" fi # Output the status of explicit loading if [ "${usb_storage_driver_status}" == "Disabled" ] && [ "${uas_driver_status}" == "Disabled" ]; then echo "[Info] USB storage driver manual loading: Blocked" elif [ "${usb_storage_driver_status}" == "Enabled" ] && [ "${uas_driver_status}" == "Enabled" ]; then echo "[Info] USB storage driver manual loading: Allowed" else echo "[Info] USB storage driver manual loading: Partially Allowed" fi # Determine the overall status of USB storage if [ "${usb_storage_status}" == "Disabled" ] && [ "${uas_status}" == "Disabled" ] && [ "${usb_storage_driver_status}" == "Disabled" ] && [ "${uas_driver_status}" == "Disabled" ]; then UsbStorage="Disabled" elif [ "${usb_storage_status}" == "Enabled" ] && [ "${uas_status}" == "Enabled" ] && [ "${usb_storage_driver_status}" == "Enabled" ] && [ "${uas_driver_status}" == "Enabled" ]; then UsbStorage="Enabled" elif [ "${usb_storage_status}" == "Enabled" ] || [ "${uas_status}" == "Enabled" ] || [ "${usb_storage_driver_status}" == "Enabled" ] || [ "${uas_driver_status}" == "Enabled" ]; then UsbStorage="Partially Allowed" else UsbStorage="Unable to Determine" fi echo "[Info] USB storage is ${UsbStorage}" if [[ -n "${_arg_customfield}" ]]; then SetCustomField "${_arg_customfield}" "${UsbStorage}" fi
Description détaillée
Ce script shell exécute plusieurs tâches de manière structurée et tolérante aux pannes. Voici une description étape par étape :
Analyse des arguments de la ligne de commande
- Supporte l’argument optionnel -CustomField pour spécifier un champ personnalisé NinjaOne.
- Fournit une option –help pour des conseils d’utilisation.
Contrôle des autorisations et des dossiers
- Valide l’existence et la lisibilité du répertoire /etc/modprobe.d.
- Si l’accès est refusé ou si le dossier est manquant, il signale « Impossible à déterminer » et, s’il est configuré, l’écrit dans le champ personnalisé NinjaOne.
Évaluation de l’état du pilote
- Interroge chaque fichier du fichier /etc/modprobe.d.
- Recherche :
- blacklist usb_storage ou blacklist uas (bloque le chargement implicite).
- install usb-storage /bin/true ou install uas /bin/true (bloque le chargement explicite).
- Suivi de l’état de chaque méthode par pilote.
Détermination du statut
- Classe le chargement des pilotes dans les catégories suivantes : autorisé, bloqué ou partiellement autorisé.
- Agrège le résultat en un statut final : activé, désactivé ou partiellement autorisé.
Intégration avec NinjaOne
- Si -CustomField est spécifié et que l’outil ninjarmm-cli est présent, le script écrit l’état du stockage USB dans le champ personnalisé désigné.
Cas d’utilisation potentiels
Étude de cas :
Un fournisseur de services de gestion des soins de santé gère des centaines de kiosques basés sur Linux dans des cliniques. La politique de sécurité prévoit que le stockage USB doit être désactivé pour empêcher l’extraction non autorisée de données. À l’aide de ce script, l’enteprise MSP peut :
- Déployer le script sur tous les terminaux à l’aide de NinjaOne.
- Enregistrer automatiquement le statut USB dans un champ personnalisé.
- Générer des rapports de conformité.
- Alerter les techniciens si une machine n’est pas conforme à la politique.
Cette surveillance proactive de la conformité permet d’économiser des heures d’audit manuel et garantit le respect des réglementations (par exemple, HIPAA).
Comparaisons
Autres méthodes
Approche | Avantages | Inconvénients |
Inspection manuelle(lsmod, grep) | Immédiate, native CLI | Prend du temps, n’est pas évolutif |
Scripts d’audit en Python | Une analyse plus souple | Des dépendances plus lourdes |
Détection et réponse des terminaux (EDR) | Contrôle centralisé, en temps réel | Coût élevé, souvent axé sur Windows |
Ce script Shell | Léger, s’intègre à NinjaOne | Peut nécessiter l’utilisation de sudo et l’intervention de techniciens connaissant bien Linux |
La niche de ce script est sa simplicité, sa portabilité et son intégration native avec l’écosystème NinjaOne, ce qui le rend idéal pour les environnements où la simplicité et l’automatisation l’emportent sur la personnalisation.
Questions fréquentes sur la manière de vérifier l’état du stockage USB dans Linux avec un script shell
Quelles sont les distributions Linux prises en charge ?
La plupart des distributions basées sur Debian et Red Hat avec /etc/modprobe.d sont compatibles.
Ce script bloque-t-il le stockage USB ?
Non, il en vérifie uniquement le statut. Le blocage doit être géré par la configuration du système.
Qu’est-ce que ninjarmm-cli ?
Il s’agit de l’interface en ligne de commande de NinjaOne pour lire/écrire les données des champs personnalisés sur les terminaux.
Que signifie l’expression « partiellement autorisé » ?
Elle indique que certaines méthodes de chargement des pilotes sont autorisées tandis que d’autres sont bloquées.
Puis-je l’utiliser sans NinjaOne ?
Oui, mais vous ne pourrez pas enregistrer les résultats dans un champ personnalisé sans ninjarmm-cli.
Implications
Le fait de savoir si le stockage USB est autorisé a une incidence sur votre position en matière de risques. L’autorisation d’un accès USB illimité augmente le risque de fuite de données, d’introduction de logiciels malveillants et de transferts accidentels de données. Dans les secteurs réglementés (finance, santé, administration), il est souvent obligatoire de montrer que l’on contrôle l’accès USB. Ce script permet une telle surveillance d’une manière peu invasive et reproductible.
Recommandations
- Exécutez le script avec les autorisations élevées pour garantir un accès complet à /etc/modprobe.d.
- Standardisez le nom du champ personnalisé sur tous les appareils pour des rapports unifiés dans NinjaOne.
- Associez ce script à des outils de remédiation qui imposent le blocage en cas de détection de non-conformité.
- Planifiez-la comme une tâche récurrente dans NinjaOne pour la validation périodique de la conformité.
Conclusion
L’utilisation d’un script shell pour vérifier l’état du stockage USB sous Linux offre une méthode légère, vérifiable et automatisable pour la vérification de la conformité des terminaux. Associé à NinjaOne, ce script devient un outil puissant pour l’application centralisée des politiques et la visibilité. Que vous soyez un MSP gérant des flottes de clients ou une équipe informatique interne sécurisant les actifs de l’entreprise, cette solution offre le parfait équilibre entre simplicité et puissance.