Institut de technologie du Massachusetts. Cours magistral # 6.858. "Sécurité des systèmes informatiques." Nikolai Zeldovich, James Mickens. 2014 année
Computer Systems Security est un cours sur le développement et la mise en œuvre de systèmes informatiques sécurisés. Les conférences couvrent les modèles de menace, les attaques qui compromettent la sécurité et les techniques de sécurité basées sur des travaux scientifiques récents. Les sujets incluent la sécurité du système d'exploitation (OS), les fonctionnalités, la gestion du flux d'informations, la sécurité des langues, les protocoles réseau, la sécurité matérielle et la sécurité des applications Web.
Cours 1: «Introduction: modèles de menace»
Partie 1 /
Partie 2 /
Partie 3Conférence 2: «Contrôle des attaques de pirates»
Partie 1 /
Partie 2 /
Partie 3Conférence 3: «Débordements de tampon: exploits et protection»
Partie 1 /
Partie 2 /
Partie 3Conférence 4: «Séparation des privilèges»
Partie 1 /
Partie 2 /
Partie 3 Alors qu'avions-nous d'autre sur cette liste? Processus. La mémoire est quelque chose qui se produit simultanément avec le processus. Ainsi, si vous n'êtes pas dans ce processus, vous ne pouvez pas accéder à sa mémoire. La mémoire virtuelle améliore parfaitement cet isolement pour nous. De plus, le mécanisme de débogage vous permet de "pop" dans la mémoire d'un autre processus, si vous avez le même ID utilisateur
Ensuite, nous avons le réseau. Les réseaux sous
Unix ne correspondent pas tout à fait au modèle décrit ci-dessus, en partie du fait que le
système d' exploitation
Unix a d'abord été développé, puis un réseau est apparu, qui est rapidement devenu populaire. Il a un ensemble de règles légèrement différent. Par conséquent, les opérations dont nous devons vraiment nous occuper sont de connecter quelqu'un au réseau si vous gérez le réseau ou d'écouter un port si vous agissez en tant que serveur. Vous devrez peut-être lire ou écrire des données sur cette connexion, ou envoyer et recevoir
des paquets
bruts .

Ainsi, les réseaux sous
Unix sont pour la plupart sans rapport avec l'
ID utilisateur . Les règles sont que n'importe qui peut toujours se connecter à n'importe quelle machine ou n'importe quelle adresse IP ou ouvrir une connexion. Si vous voulez écouter sur un port, alors dans ce cas il y a une différence, c'est que la plupart des utilisateurs sont interdits d'écouter des ports avec un nombre inférieur à la «valeur magique» de 1024. En principe, vous pouvez écouter de tels ports, mais dans ce cas, vous devriez Soyez un utilisateur spécial appelé
"super utilisateur" avec
uid = 0 .
En général, sous Unix, il y a le concept d'administrateur, ou de superutilisateur, qui est représenté par l'identifiant uid = 0, qui peut contourner presque toutes ces vérifications, donc si vous travaillez avec des droits root, vous pouvez lire et écrire des fichiers, changer les droits d'accès pour eux. Le système d'exploitation vous permettra de le faire car il pense que vous devriez avoir tous les privilèges. Et vous avez vraiment besoin de tels privilèges pour écouter sur les ports avec un nombre <1024. Que pensez-vous d'une restriction aussi étrange?
Public: il identifie des numéros de port spécifiques pour des connexions spécifiques, par exemple, pour
http sur le port 80.
Professeur: oui, par défaut le
protocole HTTP utilise le port 80. En revanche, d'autres services peuvent utiliser des ports avec un nombre supérieur à 1024, pourquoi cette restriction est-elle nécessaire? Quelle est l'utilité ici?
Public: parce que vous ne voulez pas que quelqu'un écoute accidentellement votre
HTTP .
Professeur: oui. Je pense que la raison en est que vous aviez auparavant de nombreux utilisateurs sur la même machine. Ils se sont connectés avec leurs identifiants de connexion, ont lancé leurs applications, vous vouliez donc vous assurer qu'un utilisateur aléatoire, s'étant connecté à l'ordinateur, ne pourrait pas mettre la main sur le serveur Web en cours d'exécution. Parce que les utilisateurs se connectant de l'extérieur ne savent pas qui travaille sur ce port, et ils se connectent simplement au port 80. Si je veux entrer dans cette machine et démarrer mon propre serveur Web, je transfère simplement tout le trafic du serveur Web vers cette voiture. Ce n'est probablement pas un très bon plan, mais c'est la façon dont le sous-système réseau Unix empêche les utilisateurs aléatoires de contrôler les services connus s'exécutant sur ces numéros de port bas. Telle est la justification d'une telle limitation.

De plus, du point de vue de la lecture et de l'écriture des données de connexion, si vous avez un fichier descripteur pour un socket spécifique,
Unix vous permettra de lire et d'écrire toutes les données de cette
connexion TCP ou
uTP . Lors de l'envoi
de paquets
bruts ,
Unix se comporte comme un paranoïaque, il ne vous permettra donc pas d'envoyer des paquets arbitraires sur le réseau. Cela devrait être dans le contexte de la connexion spéciale, sauf si vous avez
root - le droit et vous pouvez faire ce que vous voulez.
Donc, une question intéressante que vous pourriez poser est d'où viennent tous ces
ID utilisateur ?
Nous parlons de processus ayant
userid ou
groupid . Lorsque vous lancez
PS sur votre ordinateur, vous verrez certainement une série de processus avec différentes valeurs
uid . D'où venaient-ils?
Nous avons besoin d'un mécanisme pour charger toutes ces valeurs d'
ID utilisateur .
Unix a plusieurs appels système conçus pour cela. Par conséquent, pour amorcer ces valeurs d'identificateur, il existe une fonction appelée
setuid (uid) , vous pouvez donc attribuer le numéro
uid d'un processus en cours à cette valeur. C'est en fait une opération dangereuse, comme tout le reste dans la tradition
Unix , car vous ne pouvez le faire que si votre
uid = 0 . En tout cas, il devrait en être ainsi.
Ainsi, si vous êtes un utilisateur avec des droits root et que
uid = 0 , vous pouvez appeler
setuid (uid) et basculer l'utilisateur vers n'importe quel processus. Il existe quelques autres appels système similaires pour initialiser le
gid lié au processus: ce sont
setgid et
setgroups . Par conséquent, ces appels système vous permettent de configurer les privilèges de processus.

Le fait que vos processus obtiennent les droits d'accès corrects lorsque vous vous connectez à la machine
Unix ne se produit pas car vous avez le même
ID que les processus, car le système ne sait pas encore qui vous êtes. Au lieu de cela, sous
Unix, il existe une sorte de procédure de connexion lorsque le
protocole de shell sécurisé
SSH démarre le processus pour quiconque se connecte à l'ordinateur et essaie d'authentifier l'utilisateur.
Ainsi, initialement, ce processus de connexion commence par
uid = 0 comme pour un utilisateur avec des droits root, puis, lorsqu'il reçoit un nom d'utilisateur et un mot de passe spécifiques, il les vérifie dans sa propre base de données de comptes. Généralement, sous
Unix, ces données sont stockées dans deux fichiers:
/ etc / password (pour des raisons historiques, les mots de passe ne sont plus stockés dans ce fichier) et dans le fichier
/ etc / shadow , dans lequel les mots de passe sont stockés. Cependant, il existe une table dans le fichier
/ etc / password qui affiche chaque nom d'utilisateur dans le système sous forme de valeur entière.
Ainsi, votre nom d'utilisateur est mappé à un entier spécifique dans ce fichier
/ etc / password , puis le processus de connexion vérifie si votre mot de passe est correct en fonction de ce fichier. S'il trouve votre
uid entier, il définit les fonctions
setuid sur cette valeur
uid et démarre le shell avec la commande
exec (/ bin / sh) . Vous pouvez maintenant interagir avec le shell, mais cela fonctionne sous votre
UID , vous ne pourrez donc pas endommager accidentellement cette machine.
Public: est- il possible de démarrer un nouveau processus avec
uid = 0 si votre
uid n'est pas vraiment 0?
Professeur: si vous avez des privilèges root, vous pouvez vous limiter à un autre
uid , réduire votre autorité, mais dans tous les cas, vous pouvez créer un processus avec uniquement le même
uid que le vôtre. Mais il arrive que pour diverses raisons vous souhaitiez augmenter vos privilèges. Supposons que vous devez installer un package pour lequel vous avez besoin
des privilèges
root .
Il existe deux façons de définir des privilèges sur
Unix . Celui que nous avons déjà mentionné est un descripteur de fichier. Donc, si vous voulez vraiment augmenter vos privilèges, vous pouvez parler à quelqu'un qui travaille sous les droits root et lui demander d'ouvrir ce fichier pour vous. Ou vous devez installer une nouvelle interface, puis cet assistant ouvre un fichier pour vous et vous renvoie un descripteur de fichier en utilisant le transfert
fd . C'est une façon d'augmenter vos privilèges, mais cela n'est pas pratique car dans certains cas, des processus s'exécutent avec un grand nombre de privilèges. Pour cela,
Unix a un mécanisme intelligent mais en même temps problématique appelé
"binaires setuid" . Ce mécanisme est un exécutable standard sur un
système de fichiers
Unix , sauf lorsque vous exécutez
exec sur le binaire
setuid , par exemple,
/ bin / su sur la plupart des machines, ou
sudo , au démarrage.
Un système
Unix typique a un tas de binaires
setuid . La différence est que lorsque vous exécutez l'un de ces binaires, il bascule réellement l'
ID utilisateur du processus vers le propriétaire de ce binaire. Ce mécanisme semble étrange lorsque vous le voyez pour la première fois. En règle générale, les façons de l'utiliser sont que ce «binaire» a très probablement un
UID de propriétaire
de 0, car vous voulez vraiment restaurer de nombreux privilèges.

Vous voulez restaurer les droits de superutilisateur afin que vous puissiez exécuter cette commande
su , et le noyau, lorsque vous exécutez ce binaire, basculera l'
uid du processus sur 0, de sorte que ce programme effectuera maintenant certaines choses privilégiées.
Public: si vous avez
uid = 0 et que vous changez l'
uid de tous ces binaires
setuid en autre chose que 0, pouvez-vous restaurer vos privilèges?
Professeur: non, de nombreux processus ne pourront pas restaurer les privilèges lors de la baisse du niveau d'accès, vous pouvez donc être bloqué à cet endroit. Ce mécanisme n'est pas lié à
uid = 0 . Comme tout utilisateur d'un système
Unix , vous pouvez créer n'importe quel fichier binaire, créer un programme, le compiler et définir ce bit
setuid sur le programme lui-même. Il vous appartient, l'utilisateur, votre ID utilisateur. Et cela signifie que toute personne qui exécute votre programme exécutera ce code avec votre ID utilisateur. Y a-t-il un problème avec cela? Que faut-il faire?
Public: c'est-à-dire, s'il y a eu une erreur dans votre candidature, quelqu'un pourrait-il en faire quoi que ce soit, en agissant avec vos privilèges?
Professeur: c'est vrai, cela arrive si mon application est "buggy", ou si elle vous permet d'exécuter tout ce que vous voulez. Supposons que je puisse copier le shell du système et le configurer pour moi, mais n'importe qui peut exécuter ce shell sous mon compte. Ce n'est probablement pas le meilleur plan d'action. Mais un tel mécanisme ne crée pas de problème, car la seule personne qui peut définir le bit
setuid sur un fichier binaire est le propriétaire de ce fichier. En tant que propriétaire du fichier, vous disposez du privilège
uid , vous pouvez donc transférer votre compte à une autre personne, mais cette autre personne ne pourra pas créer le binaire
setuid avec votre
ID utilisateur .
Ce bit setuid est stocké à côté de ces bits d'autorisation, c'est-à-dire que dans chaque
inode il y a aussi un bit
setuid qui indique si ce fichier exécutable devrait ou si le programme est passé à l'
uid du propriétaire pendant l'exécution.

Il s'avère que c'est un mécanisme très délicat lorsqu'il est utilisé correctement, et grâce à lui, le noyau implémente le programme correctement. En fait, c'est assez facile à faire, car une seule vérification est effectuée: si ce bit
setuid existe, le processus passe à
uid . C'est assez simple.
Mais l'utiliser en toute sécurité est assez difficile, car, comme cela vient d'être indiqué, si ce programme contient des erreurs ou fait quelque chose d'inattendu, vous avez la possibilité de faire des choses arbitraires sous
uid = 0 ou sous tout autre
uid . Sous
Unix, lorsque vous exécutez un programme, vous héritez de beaucoup de choses de votre processus parent.
Par exemple, vous pouvez transmettre des variables d'environnement aux binaires
setuid . Le fait est que sous
Unix, vous pouvez spécifier la bibliothèque partagée à utiliser pour le processus en définissant la variable d'environnement, et les binaires
setuid ne se soucient pas de filtrer ces variables d'environnement.
Par exemple, vous pouvez exécuter
bin / su , mais utiliser des bibliothèques partagées pour la fonction
printf , afin que votre
printf démarre lorsque
bin / su imprime quelque chose, et vous pouvez exécuter le shell au lieu de printingf.
Il y a beaucoup de subtilités que vous devez comprendre correctement concernant la méfiance du programme envers les données que l'utilisateur entre. Parce que vous faites généralement confiance aux entrées utilisateur,
setuid n'a jamais été la partie la plus sûre d'un système
Unix complet. Vous avez des questions à ce sujet?
Public: setuid s'applique-t-il également aux groupes ou uniquement à l'utilisateur?
Professeur: il y a un bit
setgid symétrique au bit
setuid , que vous pouvez également régler. Si le fichier a un
gid spécifique et que ce bit
setgid est défini au démarrage du programme, vous l'obtiendrez.
Setgid n'est pas particulièrement utilisé, mais peut être utile dans les cas où vous souhaitez fournir des privilèges très spécifiques. Par exemple,
bin / su a probablement besoin de beaucoup de privilèges, mais il y a peut-être un programme qui a besoin de quelques privilèges supplémentaires, par exemple, pour écrire quelque chose dans un fichier journal spécial. Par conséquent, vous souhaiterez probablement lui fournir un certain groupe et créer un fichier journal pour elle qui sera accessible en écriture par ce groupe. Donc, même si le programme est «buggé», vous ne perdrez rien d'autre que ce groupe. Ceci est utile comme mécanisme qui, pour une raison quelconque, n'est pas utilisé trop souvent, car après tout, les gens devraient utiliser davantage les droits root.
Public: Existe-t-il des restrictions quant à qui peut modifier l'accès?
Professeur: oui. Différentes implémentations
Unix ont des vérifications différentes pour cela. La règle générale est que seul root peut changer le propriétaire du fichier, car vous ne voulez pas créer de fichiers qui appartiendront à quelqu'un d'autre et bien sûr vous ne voulez pas vous approprier les fichiers d'autres personnes. Donc, si votre
UID n'est pas 0, alors vous êtes coincé. Vous ne pouvez pas modifier la propriété d'un fichier. Si votre
uid = 0 , vous avez des privilèges root et vous pouvez changer le propriétaire en n'importe qui. Il y a quelques complications si vous avez un
setuid binaire et que vous passez d'un
uid à un autre, c'est assez délicat, mais en gros vous ne pouvez pas changer le propriétaire du fichier si vous n'avez pas les privilèges root.
Par tous les comptes, c'est un système légèrement dépassé. Vous pourriez probablement imaginer de nombreuses façons de simplifier les processus décrits ci-dessus, mais en fait, la plupart des systèmes avancés ressemblent à ceci car ils évoluent avec le temps. Mais vous pouvez parfaitement utiliser ces mécanismes comme un "bac à sable".
Ce ne sont que des principes de base d'
Unix , qui apparaissent dans presque tous les systèmes d'exploitation de type Unix:
Mac OS X ,
Linux ,
FreeBSD ,
Solaris , si quelqu'un d'autre l'utilise, etc. Mais chacun de ces systèmes possède des mécanismes plus sophistiqués que vous pourriez utiliser. Par exemple, sous
Linux, il existe un ensemble «bac à sable»
COMP ,
Mac OS X utilise la
ceinture de sécurité «bac à sable». La semaine prochaine, je vous donnerai des exemples de bacs à sable disponibles sur chaque système basé sur
Unix .
Ainsi, l'un des derniers mécanismes, que nous examinerons avant de plonger dans
OKWS , explique comment vous devez gérer les binaires
setuid et montre comment vous protéger contre les failles de sécurité existantes. Le problème est que vous aurez inévitablement des binaires
setuid sur votre système, comme
/ bin / su , ou
sudo , ou autre chose, et il est probable que vos programmes auront des erreurs. Pour cette raison, quelqu'un pourra exécuter le binaire
setuid et le processus pourra accéder à la
racine , ce que vous ne voulez pas autoriser.

Le mécanisme
Unix , qui est souvent utilisé pour empêcher l'exécution d'un processus potentiellement malveillant à l'aide de binaires
setuid , consiste à utiliser l'espace de noms du système de fichiers pour le modifier à l'aide de l'appel système
chroot , l'opération de modification du répertoire racine.
OKWS , en tant que serveur Web spécialisé dans la création de services Web rapides et sécurisés, l'utilise assez largement.

Donc, sous
Unix, vous pouvez exécuter
chroot dans un répertoire spécifique, vous pouvez donc peut-être aussi exécuter
chroot ("/ foo") .
Il y a 2 explications pour ce que fait
chroot . Le premier est simplement intuitif, cela signifie qu'après avoir exécuté
chroot , le répertoire racine ou le répertoire situé derrière la barre oblique est fondamentalement équivalent à ce que
/ foo a utilisé avant d'appeler
chroot . Cela ressemble à limiter l'espace de noms sous votre
/ foo . Par conséquent, si vous avez un fichier qui s'appelait auparavant
/ foo / x , après avoir appelé
chroot, vous pouvez obtenir ce fichier simplement en ouvrant
/ x . Limitez donc votre espace de noms à un sous-répertoire. Voici ce qu'est la version intuitive.

Bien sûr, en matière de sécurité, ce n'est pas la version intuitive qui compte, mais que fait exactement le noyau avec cet appel système? Et cela fait essentiellement deux choses. Tout d'abord, il change la valeur de cette barre oblique, donc chaque fois que vous accédez ou lorsque vous démarrez le nom du répertoire avec une barre oblique, le noyau inclut tout fichier que vous avez fourni avec des opérations
chroot . Dans notre exemple, il s'agit du fichier
/ foo avant d'appeler
chroot , c'est-à-dire que nous obtenons ce
/ = / foo .

La prochaine chose que le noyau essaiera de faire est de vous empêcher de "vous échapper" de votre
/ si vous le faites
/../ . Parce que sur
Unix, je pourrais vous demander de me donner, par exemple,
/../etc/password . Donc, si je venais de compléter cette ligne comme ceci:
/foo/../etc/password , ce ne serait pas bien, car je pourrais simplement quitter
/ foo et continuer pour obtenir
/ etc / password .
La deuxième chose que le noyau fait avec un appel système
Unix est que lorsque vous appelez
chroot pour ce processus particulier, il change la façon dont
/../ est évalué dans ce répertoire. Par conséquent, il modifie
/../ afin que
/ foo pointe vers lui-même. Ainsi, cela ne vous permet pas de «vous échapper», et ce changement ne s'applique qu'à ce processus et n'affecte pas le reste. Quelles idées avez-vous sur la façon de «s'échapper» de l'environnement
chroot en utilisant la façon dont il est mis en œuvre?
Fait intéressant, le noyau ne surveille qu'un seul répertoire
chroot , vous pouvez donc probablement effectuer l'opération
chroot = (/ foo) , mais vous seriez coincé à cet endroit. Vous voulez donc obtenir
/ etc / password , mais comment faire? Vous pouvez maintenant ouvrir le répertoire racine en tapant
open (* / *) . Cela vous donnera un descripteur de fichier décrivant ce qu'est
/ foo . Ensuite, vous pouvez à nouveau appeler
chroot et exécuter
chroot (`/ bar) .

, :
root /foo ,
/foo/bar /../ /foo / bar/..
,
/foo .
fchdir (fd) (*/*) ,
chdir (..) .

/foo ,
/../ .
/foo ,
root , .
, , . .
Unix root-
chroot ,
chroot . ,
Unix uid = 0 ,
chroot . . , ,
chroot ,
userid . ,
Unix , ,
root , .
, , , .
chroot — . .
: ,
inod , ?
: ! , , , : «
inode 23», -
hroot . ,
Unix inode inode , , , root-.
, , ,
OKWS . ,
OKWS .
, -, , - , . , ,
httpd , ,
Apache .
userid www /etc/password . , ,
SSL ,
PHP , . , , ,
MySQL , .
MySQL .
MySQL , , , .

, , ,
MySQL , , .
, , , , . , , ,
Apache , ou en SSL , ou peut-être dans le code d'application ou dans l'interpréteur PHP . Et comme il y a des erreurs, vous pouvez les utiliser pour obtenir l'intégralité du contenu de l'application.52:30 minSuite:Cours MIT "Sécurité des systèmes informatiques". Conférence 4: «Partager les privilèges», partie 2La version complète du cours est disponible ici .Merci de rester avec nous. Aimez-vous nos articles? Vous voulez voir des matériaux plus intéressants? Soutenez-nous en passant une commande ou en le recommandant à vos amis, une
réduction de 30% pour les utilisateurs Habr sur un analogue unique de serveurs d'entrée de gamme que nous avons inventés pour vous: Toute la vérité sur VPS (KVM) E5-2650 v4 (6 cœurs) 10 Go DDR4 240 Go SSD 1 Gbps à partir de 20 $ ou comment diviser le serveur? (les options sont disponibles avec RAID1 et RAID10, jusqu'à 24 cœurs et jusqu'à 40 Go de DDR4).
Dell R730xd 2 fois moins cher? Nous avons seulement
2 x Intel Dodeca-Core Xeon E5-2650v4 128 Go DDR4 6x480 Go SSD 1 Gbps 100 TV à partir de 249 $ aux Pays-Bas et aux États-Unis! Pour en savoir plus sur la
création d'un bâtiment d'infrastructure. classe utilisant des serveurs Dell R730xd E5-2650 v4 coûtant 9 000 euros pour un sou?