Recherche de site Web

Comment surveiller l’intégrité des fichiers sous Linux à l’aide d’Osquery


Le concept de base impliqué dans l’utilisation de l’application osquery est l'"abstraction tabulaire » de nombreux aspects du système d’exploitation, tels que les processus, les utilisateurs, etc. Les données sont stockées dans des tables qui peuvent être interrogées à l’aide de la syntaxe SQL, directement via le shell osqueryi ou via le démon osqueryd.

Dans ce tutoriel, nous allons voir comment installer l’application, comment exécuter des requêtes de base et comment utiliser FIM (File Integrity Monitoring) dans le cadre de votre travail d’administration système Linux.

Dans ce tutoriel, vous allez apprendre :

  • Comment installer osquery
  • Comment lister les tables disponibles
  • Comment effectuer des requêtes à partir du shell osqueryi
  • Comment utiliser le démon osqueryd pour surveiller l’intégrité des fichiers

Comment surveiller l’intégrité des fichiers sous Linux à l’aide d’Osquery

Configuration logicielle requise et conventions utilisées

  • Connaissance de base des concepts SQL
  • Autorisations root pour effectuer des tâches administratives

Installation

Nous avons essentiellement deux options pour installer osquery : la première consiste à télécharger le paquet approprié pour notre système depuis le site officiel ; La seconde, généralement préférée, est d’ajouter le dépôt Osquery à nos sources de logiciels de distribution. Ici, nous allons brièvement explorer les deux options.

Le conseil est de sélectionner la dernière version disponible (4.1.2 au moment de la rédaction). Une fois le paquet téléchargé, nous pouvons l’installer à l’aide de notre gestionnaire de paquets de distribution. Par exemple, pour installer le logiciel sur un système Fedora (en supposant que le paquet se trouve dans notre répertoire de travail actuel), nous exécuterions :

sudo dnf install ./osquery-4.1.2-1.linux.x86_64.rpm

Utilisation d’un référentiel

Comme alternative, nous pouvons ajouter le dépôt rpm ou deb à notre distribution. Si nous utilisons une distribution basée sur rpm, nous pouvons exécuter les commandes suivantes pour accomplir la tâche :

curl -L https://pkg.osquery.io/rpm/GPG | sudo tee
/etc/pki/rpm-gpg/RPM-GPG-KEY-osquery
sudo yum-config-manager --add-repo https://pkg.osquery.io/rpm/osquery-s3-rpm.repo
sudo yum-config-manager --enable osquery-s3-rpm-repo
sudo yum install osquery

Avec les commandes linux ci-dessus, nous ajoutons la clé pulic gpg utilisée pour signer les paquets à notre système, puis nous ajoutons le dépôt. Enfin, nous installons le paquet osquery. Notez que yum, dans les versions récentes de Fedora et CentOS/RHEL, n’est qu’un lien symbolique vers dnf, donc lorsque nous invoquons le premier, le second est utilisé à la place.

Si nous utilisons une distribution basée sur Debian, à la place, nous pouvons ajouter le dépôt deb à nos sources logicielles en exécutant :

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys
1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B
sudo add-apt-repository 'deb [arch=amd64] https://pkg.osquery.io/deb deb main'
sudo apt-get update
sudo apt-get install osquery

Une fois le paquet installé, nous pouvons jeter un coup d’œil à l’utilisation de base du logiciel.

Utilisation de base

Osquery nous permet de surveiller divers aspects d’un système d’exploitation en adoptant une « abstraction tabulaire », en utilisant une syntaxe SQL similaire à celle utilisée sur les bases de données sqlite. Les requêtes sont exécutées sur des tables qui font abstraction de divers aspects du système d’exploitation, tels que les processus et les services.

Nous pouvons exécuter les requêtes directement à l’aide du shell interactif osqueryi, ou nous pouvons les planifier via le démon osqueryd. Voici un exemple de requête pour lister toutes les tables disponibles (la liste complète avec la description des tables peut également être trouvée
en ligne) :

osqueryi
osquery> .tables
  => acpi_tables
  => apt_sources
  => arp_cache
  => atom_packages
  => augeas
  => authorized_keys
  => block_devices
  => carbon_black_info
  => carves
  => chrome_extensions
  => cpu_time
  => cpuid
  => crontab
  => curl
  => curl_certificate
  => deb_packages
  => device_file
  => device_hash
  => device_partitions
  => disk_encryption
  => dns_resolvers
  => docker_container_labels
  => docker_container_mounts
  => docker_container_networks
  => docker_container_ports
  => docker_container_processes
  => docker_container_stats
  => docker_containers
  => docker_image_labels
  => docker_images
  => docker_info
  => docker_network_labels
  => docker_networks
  => docker_version
  => docker_volume_labels
  => docker_volumes
  => ec2_instance_metadata
  => ec2_instance_tags
  => elf_dynamic
  => elf_info
  => elf_sections
  => elf_segments
  => elf_symbols
  => etc_hosts
  => etc_protocols
  => etc_services
  => file
  => file_events
  => firefox_addons
  => groups
  => hardware_events
  => hash
  => intel_me_info
  => interface_addresses
  => interface_details
  => interface_ipv6
  => iptables
  => kernel_info
  => kernel_integrity
  => kernel_modules
  => known_hosts
  => last
  => listening_ports
  => lldp_neighbors
  => load_average
  => logged_in_users
  => magic
  => md_devices
  => md_drives
  => md_personalities
  => memory_array_mapped_addresses
  => memory_arrays
  => memory_device_mapped_addresses
  => memory_devices
  => memory_error_info
  => memory_info
  => memory_map
  => mounts
  => msr
  => npm_packages
  => oem_strings
  => opera_extensions
  => os_version
  => osquery_events
  => osquery_extensions
  => osquery_flags
  => osquery_info
  => osquery_packs
  => osquery_registry
  => osquery_schedule
  => pci_devices
  => platform_info
  => portage_keywords
  => portage_packages
  => portage_use
  => process_envs
  => process_events
  => process_file_events
  => process_memory_map
  => process_namespaces
  => process_open_files
  => process_open_sockets
  => processes
  => prometheus_metrics
  => python_packages
  => routes
  => rpm_package_files
  => rpm_packages
  => selinux_events
  => shadow
  => shared_memory
  => shell_history
  => smart_drive_info
  => smbios_tables
  => socket_events
  => ssh_configs
  => sudoers
  => suid_bin
  => syslog_events
  => system_controls
  => system_info
  => time
  => ulimit_info
  => uptime
  => usb_devices
  => user_events
  => user_groups
  => user_ssh_keys
  => users
  => yara
  => yara_events
  => yum_sources

En exécutant la commande osqueryi, nous entrons le shell interactif ; À partir de là, nous pouvons émettre nos requêtes et instructions. Voici un autre exemple de requête, cette fois pour lister tous les processus en cours d’exécution pid et name. La requête est exécutée sur la table de processus (la sortie de la requête a été tronquée pour plus de commodité) :

osquery> SELECT pid, name FROM processes;
+-------+------------------------------------+
| pid   | name                               |
+-------+------------------------------------+
| 1     | systemd                            |
| 10    | rcu_sched                          |
| 10333 | kworker/u16:5-events_unbound       |
| 10336 | kworker/2:0-events                 |
| 11    | migration/0                        |
| 11002 | kworker/u16:1-kcryptd/253:0        |
| 11165 | kworker/1:1-events                 |
| 11200 | kworker/1:3-events                 |
| 11227 | bash                               |
| 11368 | osqueryi                           |
| 11381 | kworker/0:0-events                 |
| 11395 | Web Content                        |
| 11437 | kworker/0:2-events                 |
| 11461 | kworker/3:2-events_power_efficient |
| 11508 | kworker/2:2                        |
| 11509 | kworker/0:1-events                 |
| 11510 | kworker/u16:2-kcryptd/253:0        |
| 11530 | bash                               |
[...]                                        |
+-------+------------------------------------+

Il est même possible d’effectuer des requêtes sur des tables jointes à l’aide de l’instruction JOIN, tout comme nous le faisons dans les bases de données relationnelles. Dans l’exemple ci-dessous, nous effectuons une requête sur la table des processus, jointe à celle des utilisateurs via la colonne uid :

osquery> SELECT processes.pid, processes.name, users.username FROM processes JOIN
users ON processes.uid = users.uid;
+-------+-------------------------------+------------------+
| pid   | name                          | username         |
+-------+-------------------------------+------------------+
| 1     | systemd                       | root             |
| 10    | rcu_sched                     | root             |
| 11    | migration/0                   | root             |
| 11227 | bash                          | egdoc            |
| 11368 | osqueryi                      | egdoc            |
| 13    | cpuhp/0                       | root             |
| 14    | cpuhp/1                       | root             |
| 143   | kintegrityd                   | root             |
| 144   | kblockd                       | root             |
| 145   | blkcg_punt_bio                | root             |
| 146   | tpm_dev_wq                    | root             |
| 147   | ata_sff                       | root             |
[...]
| 9130  | Web Content                   | egdoc            |
| 9298  | Web Content                   | egdoc            |
| 9463  | gvfsd-metadata                | egdoc            |
| 9497  | gvfsd-network                 | egdoc            |
| 9518  | gvfsd-dnssd                   | egdoc            |
+-------+-------------------------------+------------------+

Surveillance de l’intégrité des fichiers (FIM)

Jusqu’à présent, nous utilisions osquery via le shell interactif : osqueryi. Pour utiliser FIM (File Integrity Monitoring), nous voulons utiliser le démon osqueryd à la place. Via le fichier de configuration, nous fournissons une liste des fichiers que nous voulons surveiller. Les événements tels que les modifications d’attributs impliquant les fichiers et répertoires spécifiés sont enregistrés dans la table file_events. Le démon exécute une requête sur cette table après un intervalle de temps spécifié et notifie dans les journaux lorsque de nouveaux enregistrements sont trouvés. Voyons un exemple de configuration.

Configuration de la configuration

Le fichier de configuration principal d’osquery est /etc/osquery/osquery.conf. Le fichier n’existe pas par défaut, nous devons donc le créer. La configuration est fournie au format Json. Supposons que nous voulions surveiller tous les fichiers et répertoires sous /etc ; Voici comment nous configurerions l’application :

{
  "options": {
    "disable_events": "false"
  },
  "schedule": {
    "file_events": {
      "query": "SELECT * FROM file_events;",
      "interval": 300
    }
  },
  "file_paths": {
    "etc": [
      "/etc/%%"
    ],
  },
}

Analysons la configuration ci-dessus. Tout d’abord, dans la section des options, nous disable_events définissons à « false », afin d’activer les événements de fichier.

Après cela, nous avons créé la section schedule : à l’intérieur de cette section, nous pouvons décrire et créer diverses requêtes planifiées nommées. Dans notre cas, nous avons créé une requête qui sélectionne toutes les colonnes de la table file_events, qui est censée être exécutée toutes les 300 secondes (5 minutes).

Après avoir planifié la requête, nous avons créé la section file_paths, où nous avons spécifié les fichiers à surveiller. Dans cette section, chaque clé représente le nom d’un ensemble de fichiers à surveiller (une catégorie dans le jargon osquery). Dans ce cas, la touche « etc » fait référence à une liste avec une seule entrée, /etc/ %%.

Que signifie le symbole % ? Lors de la spécification des chemins d’accès aux fichiers, nous pouvons utiliser des caractères génériques standard (*) ou SQL ( %). Si un seul caractère générique est fourni, il sélectionne tous les fichiers et répertoires existants au niveau spécifié. Si un caractère générique double est fourni, il sélectionne tous les fichiers et dossiers de manière récursive. Par exemple, l’expression /etc/ % correspond à tous les fichiers et dossiers d’un niveau sous /etc, tandis que /etc/ %% correspond à tous les fichiers et dossiers sous /etc de manière récursive.

Si nécessaire, nous pouvons également exclure des fichiers spécifiques du chemin que nous avons fourni, en utilisant la section exclude_paths dans le fichier de configuration. Dans la section, nous ne pouvons référencer que les catégories définies dans la section file_paths, (« etc » dans ce cas). Nous fournissons la liste des fichiers à exclure :

 "exclude_paths": {
     "etc": [
        "/etc/aliases"
     ]
  }

À titre d’exemple, nous avons exclu le fichier /etc/aliases de la liste. Voici à quoi ressemble notre configuration finale :

{
  "options": {
    "disable_events": "false"
  },
  "schedule": {
    "file_events": {
      "query": "SELECT * FROM file_events;",
      "interval": 20
    }
  },
  "file_paths": {
    "etc": [
      "/etc/%%"
    ]
  },
 "exclude_paths": {
     "etc": [
        "/etc/aliases"
     ]
  }
}

Démarrage du démon

Avec notre configuration en place, nous pouvons démarrer le démon osqueryd :

sudo systemctl start osqueryd

Pour que le démon démarre automatiquement au démarrage, nous devons exécuter :

sudo systemctl enable osqueyd

Une fois que le démon est en cours d’exécution, nous pouvons vérifier que notre configuration fonctionne. À titre d’exemple, nous allons modifier les permissions du fichier /etc/fstab, en les faisant passer de 644 à 600 :

sudo chmod 600 /etc/fstab

Nous pouvons maintenant vérifier que la modification du fichier a été enregistrée en lisant le fichier /var/log/osquery/osqueryd.results.log. Voici la dernière ligne du dossier (embellie) :

{
  "name":"file_events",
  "hostIdentifier":"fingolfin",
  "calendarTime":"Mon Dec 30 19:57:31 2019 UTC",
  "unixTime":1577735851,
  "epoch":0,
  "counter":0,
  "logNumericsAsNumbers":false,
  "columns": {
    "action":"ATTRIBUTES_MODIFIED",
    "atime":"1577735683",
    "category":"etc",
    "ctime":"1577735841",
    "gid":"0",
    "hashed":"0",
    "inode":"262147",
    "md5":"",
    "mode":"0600",
    "mtime":"1577371335",
    "sha1":"",
    "sha256":"",
    "size":"742",
    "target_path":"/etc/fstab",
    "time":"1577735841",
    "transaction_id":"0",
    "uid":"0"
  },
  "action":"added"
}

Dans le journal ci-dessus, nous pouvons clairement voir qu’une action ATTRIBUTES_MODIFIED (Ligne 10) s’est produite sur le target_path « /etc/fstab » (Line 23), qui fait partie de la catégorie « etc » (Line 12). Il est important de noter que si nous interrogeons la table file_events à partir du shell osqueryi, nous ne verrons aucune ligne, car le démon osqueryd et osqueryi ne communiquent pas.

Conclusions

Dans ce tutoriel, nous avons vu les concepts de base impliqués dans l’utilisation de l’application osquery, qui abstrait divers concepts du système d’exploitation à l’aide de données tabulaires que nous pouvons interroger à l’aide de la syntaxe SQL. Nous avons vu comment installer l’application, comment effectuer des requêtes de base à l’aide du shell osqueryi, et enfin comment configurer la surveillance des fichiers à l’aide du démon osqueryd. Nous n’avons fait qu’effleurer la surface de ce que l’application peut faire ; Comme toujours, le conseil est de jeter un coup d’œil à la documentation du projet pour une connaissance plus approfondie.

Articles connexes: