Une faille de sécurité

Publié le 24 août 2007 par Peck
Cet article est maintenant sur http://linux-attitude.fr/post/Une-faille-de-securite

Niveau :
Résumé : bugs, failles, buffer overflow, fuite d'information, format string, race condition

En tant qu'admin, vous vous devez de connaître les différents types de faille pour savoir quel est le potentiel de risque associé à chacune de vos actions. Qu'est-ce donc qu'une faille de sécurité ?

C'est une erreur dans un système qui permet d'en obtenir des informations confidentielles, un accès non autorisé ou éventuellement d'arrêter un système. Elles peuvent être dûes à des erreurs de programmation, ou à des erreurs d'administration.


Droits
Dans un système unix, les failles causées par un sysadmin sont la plupart du temps des problèmes de droit d'accès permettant une fuite d'information. Par exemple des fichiers sensibles non protégés et accessibles par apache, un fichier de mot de passe lisible ou des propriétaires/groupe/droits mal prévus sur une machine avec de nombreux utilisateurs.

Il s'agit ici surtout de faire attention à chacune de vos actions impliquant un droit, c'est à dire tout ce qui est lié à de nouveaux utilisateurs ou à des changement dans des droits d'accès.


Flood
Certains problèmes de conception permettent de faire tomber un service ou un système facilement. La faille la plus connue à ce sujet est la fork bomb qui qui ne fait que duppliquer son processus jusqu'à ce que le système tombe à court de processus.
En shell (à vous de chercher comment elle se lit) :
$ :(){ :|:& };:


Certaines requêtes distantes peuvent aussi mener à des calculs extrêmements longs et mis à disposition de tout un chacun. Un personne interrogeant ce service plusieurs fois peut l'écrouler facilement. Attention donc à bien protéger votre code s'il autorise l'utilisateur à spécifier une recherche puissante par exemple, évitez qu'il puisse rentrer des expressions trop complexes.


Bugs
Il peut aussi s'agir d'une erreur de programmation. Il existe deux façons de les exploiter. Soit distante, sur une machine à laquelle vous n'avez pas accès, soit locale en cherchant à s'octroyer des droits supplémentaires.

À distance il s'agit d'obtenir un accès à la machine. Les failles potentielles sont dans tous les services ouverts sur le réseau. La protection s'appelle donc iptables (netstat pour les découvrir). Il existe de rares failles dans le noyau, mais elles sont suffisament exceptionnelle pour pouvoir être raisonnablement ignorées dans la vie de tous les jours (mettez à jour votre noyau au cas où :-).
# on regarde les failles réseau potentielles
$ netstat -lnptu
# on coupe le tout
$ iptables -P INPUT DROP # Attention, vraiment tout !!


En local, il s'agit d'augmenter ses droits d'accès (car on a dèjà un accès). Les failles potentielles sont dans les programmes s'exécutant sous un autre utilisateur. Il existe de rares failles dans le noyau mais elles sont suffisament fréquentes pour que l'on vous conseille d'avoir un noyau à jour de moins de 2 versions mineures sur un système avec beaucoup d'utilisateurs.

Les failles locales sont dans tout programme s'exécutant en tant qu'un utilisateur et ayant des interactions avec un autre utilisateur. Cela nous laisse donc avec les démons et les commandes suid.
# les démons
$ netstat -lnp
# les commandes suid
$ find / -perm -u=s

Attention, ce n'est pas parce qu'un démon tourne ou qu'un programme est suid qu'il peut être attaqué, il faut aussi qu'il ait un bug exploitable.


Un bug pour la route

Il n'y a pas besoin d'écrire des programmes extrêment complexes pour créer des bugs exploitables, les buffer overflow sont courants. Un exemple de faille tout en un :
int main(int argc, char**argv)
{
  char str[16];
  /*
   * Pas de vérification de l'existence de argv[1]
   * Utilisation d'une chaîne utilisateur en tant que format string (si argv[1] = "%s" ...)
   * Non vérification de la taille du buffer (si argv[1] fait plus de 15 caractères ...)
   */
  sprintf(str, argv[1]);
  return 0;
}
Vous trouverez des dizaines de façons d'exploiter ces bugs sur le net.


Ou deux

Un autre type de bug que vous pourrez rencontrer souvent si vous écrivez des scripts et y créez des fichiers, il s'agit de la race condition et c'est en général invisible. Exemple qui parraît innocent :
# on vérifie que /tmp/toto n'existe pas pour ne pas se faire piquer le mot de passe
if [ ! -e  /tmp/toto ]
then
  umask 077 # on tente de rendre illisible /tmp/toto
  echo "login:pass" > /tmp/toto
  # blah
  rm /tmp/toto
fi
Hé bien il est parfaitement possible de créer un fichier /tmp/toto avec les droits qui nous plaisent entre le moment du test et le echo, et donc de récupérer le mot de passe. Ce temps est très court, c'est pourquoi le développeur ne se doute pas de la faille (d'ou le terme race condition), mais une rapide recherche sur le net vous convaincra de la facilité qu'il y a à l'exploiter.