View difference between Paste ID: kjCqFnv1 and
SHOW: | | - or go back to the newest paste.
1-
1+
11/09/2005 14:56
2
Message #1
3
4
5
Fana
6
7
8
Groupe : Members
9
Messages : 71
10
Inscrit : 8-September 05
11
Lieu : Bruxelles & poivres
12
Membre no 14
13
FAI: Skynet
14
Vitesse: ADSL MAX (jusqu'à 8 Mb)
15
WI-FI: Oui
16
17
18
19
Bonjour à tous amis lecteurs & administrateurs nioBees !!!
20
21
L'appel système chroot() (abréviation pour change root directory), est devenu particulièrement populaire dernièrement, entre autre grâce à l'équipe d'OpenBSD. De nombreux articles ont vanté les mérites de la restriction d'une processus dans un chroot. L'idée est de prendre un processus et de l'enfermer dans un chroot pour le confiner à l'intérieur d'un répertoire donné dans le système de fichiers. L'objectif est de protéger, prétendument, le reste du système contre une compromission complète si le processus à l'intérieur du chroot est pris pour cible. 
22
23
L'objectif de cet article est de démystifier certaines croyances, en montrant plusieurs attaques contre cet appel système, et la manière de les contrer, comme cela est réalisé dans grsecurity *http://www.grsecurity.net* pour une documentation complète mais grsecurity propose entre autre des ACLs, de nombreux durcissements, des protections renforcées des zones mémoires, etc., ). Il est en effet essentiel de comprendre que des "fonctionnalités", comme chroot, ne font pas tout en sécurité, mais que la manière dont elles sont réalisées et configurées est au moins aussi essentielle. 
24
25
Quand on discute des inconvénients de chroot(), la plupart des gens mettent en avant un article écrit il y a plus d'un an qui décrit une attaque simple *http://www.bpfh.net/simes/computing/chroot-break.html*, mais qui ne fonctionne plus avec les versions récentes de Linux ou FreeBSD. Certaines personnes sont conscientes que si un attaquant parvient à devenir root dans un chroot, il n'y a plus rien qui l'empêche alors de s'attaquer au reste du système. Certes, cela est tout à fait exact, mais ces mêmes personnes sont en général inconscientes des moyens à mettre enœuvre. 
26
27
Dans la suite de cet article, je décris en détails plusieurs attaques qui permettent de s'évader d'un chroot et de compromettre le système hôte. Certaines de ces attaques ne nécessitent pas d'être root, ce que beaucoup de personnes pensent, à tort, être impossible. 
28
29
Évasion d'un chroot via mount
30
31
L'appel système mount(), réservé à l'utilisateur root, est utilisé pour monter un système de fichiers à un endroit précis. Il prend en argument le chemin vers le device, et le chemin vers l'endroit où monter le device. Évidemment, si un attaquant est autorisé à créer des devices appartenant aux disques durs présents sur le système, il peut sortir du chroot en montant des files systems et en y ajoutant des shells root par exemple. 
32
33
Il existe de nombreuses options à considérer lors de la mise en place d'un chroot (voir les pages man mount et man 2 mount) dont les 3 plus intéressantes sont : 
34
35
- MS_NOSUID : ignore les bits SUID et SGID ; 
36
- MS_NODEV : empêche la création de devices ; 
37
- MS_NOEXEC : interdiction d'exécuter des programmes.
38
39
Toutefois, il reste quand même des choses à faire. En fait, pour monter certains systèmes de fichiers, il n'est pas nécessaire d'avoir un device. Les plus connus de ces systèmes de fichiers sont devpts et procfs. La possibilité de monter procfs constitue une fuite d'information à propos du système et des processus s'exécutant en dehors du chroot. 
40
41
Certains pensaient qu'il était possible de sortir du chroot si procfs était monté, simplement en changeant la racine pour /proc/1/root. Cependant, cela n'est plus le cas, au moins sur les noyaux Linux récents. Il reste toutefois une autre fonctionnalité offerte par procfs qui permet également de sortir du chroot qui sera présentée ci-après (cf. « évasion via sysctl »). 
42
43
Monter devpts donne à l'attaquant un accès à toutes les pseudo-consoles ouvertes sur le système (par exemple, celles de ssh). L'attaquant peut alors injecter des caractères via ioctl() dans les terminaux, en particulier ceux des administrateurs. 
44
45
Considérons le code suivant : 
46
47
CODE
48
int fd;
49
char *buf = "chmod 777 /etc/shadow\n";
50
char *p;
51
52
fd = open("/dev/pts/0", O_RDWR);
53
54
if (fd < 0)
55
return 1;
56
57
for (p = buf; *p; p++)
58
ioctl(fd, TIOCSTI, p);
59
60
Sur une installation par défaut de Linux, cela exécute chmod 777 /etc/shadow dans le terminal d'un administrateur. Grsecurity arrête les attaques de ce type en interdisant tout montage au sein d'un chroot. 
61
62
Évasion d'un chroot via Ptrace
63
64
ptrace() a attiré l'attention dernièrement, en particulier depuis que certaines race conditions ont permis une compromission root locale. Cet appel système permet d'observer et/ou de modifier le flux d'exécution d'un autre processus. En tant que root dans un chroot, un attaquant peut modifier le flux d'exécution de n'importe quel processus du système (sauf init, le premier processus). 
65
66
En tant que non root dans un chroot, l'attaquant peut modifier un processus possédant le même UID. L'attaquant utilise une requête PTRACE_ATTACH pour s'accrocher au processus cible, puis emploie PTRACE_POKEUSR, PTRACE_SETREGS, et PTRACE_POKETEXT pour modifier ce qu'il veut dans l'espace d'adressage du processus (et même les zones en lecture seule). 
67
68
A cause d'une faible protection des pages sur la plupart des UNIXes, si l'attaquant veut compromettre un processus, il trouvera très probablement une partie de l'espace mémoire qui soit accessible à la fois en écriture et en exécution, même si la pile n'est pas exécutable. L'attaquant peut alors modifier cette région et rediriger l'exécution vers le code malicieux qu'il aura introduit (n'importe quel shellcode par exemple) afin de sortir du chroot. L'exploitation est très simple, d'autant qu'aucune force brute n'est nécessaire puisque l'attaquant à une vue complète de la mémoire du processus cible. 
69
70
Il est clair que les attaques à base de ptrace() sont très puissantes et offrent une grande diversité de solution à un attaquant. Grsecurity interdit ces attaques en empêchant l'utilisation de ptrace() si le processus appelant tourne dans un chroot. De plus, comme Grsecurity garantit également qu'aucun segment ne soit accessible à la fois en écriture et en exécution, cela rend les exploitations à base de ptrace() bien plus complexe. 
71
72
73
Évasion d'un chroot via Fchdir
74
75
Sortir d'un chroot avec fchdir() dépend fortement de l'application, au contraire des autres attaques, mais je ne connais aucun autre OS qui bloque cette attaque, en dehors de grsecurity. Cet appel système permet de changer de répertoire courant pour un file descriptor ouvert référençant un autre répertoire. 
76
77
Une exploitation est possible si le processus change de répertoire racine tout en conservant un file descriptor ouvert vers un répertoire situé en dehors du chroot (et donc sur le système de fichiers principal). L'attaquant peut exploiter une faille dans le chroot et changer de répertoire pour cet autre répertoire, ou bien utiliser cela en combinaison avec l'attaque ptrace décrite ci-dessus. 
78
79
Grsecurity empêche cela en descendant dans l'arborescence du système de fichiers en partant du répertoire vers lequel le processus "chrooté" tente le fchdir(). Si l'algorithme termine dans le système de fichiers chrooté, l'opération est autorisée, dans le cas contraire, elle est rejetée. 
80
81
82
Évasion d'un chroot via Chmod
83
84
Cette attaque nécessite une condition très particulière, mais, avec cette réserve, donne un accès root sur le système. Les appels système chmod() et fchmod() sont utilisés pour modifier les permissions sur un fichier. L'intérêt réside ici dans les droits S_ISUID et S_ISGID. Supposons qu'un attaquant devienne root dans le chroot (et que cela ne suffise plus pour sortir du chroot), il peut télécharger une application quelconque, et activer le bit SUID ou SGID. Maintenant, il est possible à un attaquant (le même ou un autre) situé en dehors du chroot, mais sans être root, de passer root grâce à l'application SUID/SGID. 
85
86
En guise de protection, grsecurity interdit l'ajout du bit SUID ou SGID lorsque le processus est dans un chroot. 
87
88
Évasion d'un chroot via sysctl
89
90
Une attaque dont je n'ai entendu parler nulle part se focalise sur la fonction sysctl()> pour sortir du chroot. C'est une des plus élégante à exécuter et ne demande aucune des capabilities (voir /usr/src/linux/include/capability.h) particulière pour réussir. Cet appel système renseigne sur l'état du noyau, et, pour un processus avec les privilèges adéquats, de le modifier. Ces paramètres sont accessibles soit via le fichier de configuration /etc/sysctl.conf, soit au travers de procfs, soit directement par l'appel système sysctl(), et stockés sous formes d'une base type MIB (Management Information Base). 
91
92
De là, un attaquant dispose de plusieurs choix, selon ce qui est compilé dans le noyau. Par exemple, la plupart des noyaux supportent les modules, et donc CONFIG_KMOD qui autorise le chargement automatique d'un module noyau par un chargeur situé en espace utilisateur. Le chargeur habituel est /sbin/modprobe. Toutefois, il est possible d'en contrôler l'emplacement par une entrée dans la base avec sysctl(). Le programme suivant illustre cela : 
93
94
CODE
95
#include <stdio.h>
96
#include <string.h>
97
#include <unistd.h>
98
#include <linux/unistd.h>
99
#include <linux/sysctl.h>
100
#include <sys/socket.h>
101
102
_syscall1(int, _sysctl, struct __sysctl_args *, args);
103
int sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
104
void *newval, size_t newlen)
105
{
106
struct __sysctl_args args={name,nlen,oldval,oldlenp,newval,newlen};
107
return _sysctl(&args);
108
}
109
110
#define SIZE(x) sizeof(x)/sizeof(x[0])
111
#define MODPROBEPATHLEN 256
112
113
char modprobepath[MODPROBEPATHLEN];
114
int pathlen;
115
int name[] = { CTL_KERN, KERN_MODPROBE };
116
117
int main(void){
118
strcpy(modprobepath, "/bin/sh");
119
pathlen = SIZE(modprobepath);
120
if (sysctl(name, SIZE(name), 0, NULL, modprobepath, pathlen))
121
perror("sysctl");
122
else {
123
printf("successfully modified the modprobe path.\n");
124
socket(AF_SECURITY, SOCK_STREAM, 1);
125
printf("executing shell with full privileges, outside of chroot\n");
126
}
127
return 0;
128
}
129
130
Cette attaque fonctionne car le noyau peut exécuter des programmes dans un contexte utilisateur. Quand le noyau force l'exécution d'un binaire, celui-ci est exécuté avec le vrai système de fichiers racine en tant que racine du nouveau processus. 
131
132
Pour stopper cela, grsecurity empêche les écritures via sysctl(), mais aussi via le procfs. 
133
134
Évasion d'un chroot via la mémoire partagée
135
136
Une autre attaque intéressante pour sortir d'un chroot s'appuie sur l'utilisation de mémoire partagée. L'attaque en elle-même dépend des processus employant de la mémoire partagée en dehors du chroot. Si de tels processus existent, il est alors très probable que l'attaque réussisse, indépendant de ce que la mémoire partagée de ces processus soit déclarée privée ou non au moment de sa création. 
137
138
Pour s'attacher à de la mémoire partagée, l'attaquant doit commencer par trouver sa cible. S'attacher à de la mémoire partagée non privée est facile : il suffit de connaître (ou de "bruteforcer") la clé de la mémoire virtuelle. Si la mémoire virtuelle est déclarée privée, un test supplémentaire impose que l'UID effectif de l'attaquant soit égal à l'UID du processus ou du créateur de la mémoire partagée. 
139
140
L'utilisateur root peut outrepasser ce test s'il dispose de la capability CAP_IPC_OWNER, même s'il existe d'autres solutions pour root sans cette capability. S'il dispose de CAP_SYS_ADMIN, il peut alors modifier les credentials de la mémoire partagée pour qu'ils soient identiques aux siens, et ainsi s'attacher au processus. Si l'attaquant dispose de CAP_SETUID, il peut modifier son UID pour la faire correspondre à celle de la mémoire partagée. 
141
142
Finalement, si le processus compromis dans le chroot possède un UID effectif égal à celui de la cible utilisant de la mémoire partagée, l'attaquant peut sortir du chroot sans avoir besoin des droits de root. Faire tourner des démons sous l'identité nobody est assez classique sur nos systèmes, et cette attaque devient alors particulièrement intéressante. Après avoir obtenu les credentials sur la mémoire partagée, l'attaquant peut récupérer l'identification de la mémoire avec la fonction shmget(), puis s'attacher à cette mémoire avec shmat(). L'attaquant peut alors profiter de cet accès pour modifier des entiers, des chaînes de caractères, ..., pour exploiter le processus 
143
144
Le programme suivant permet de déterminer si votre système est vulnérable ou non, que ce soit un Linux, un FreeBSD, un NetBSD, un OpenBSD ou un Solaris : 
145
146
CODE
147
#include <stdio.h>
148
#include <sys/ipc.h>
149
#include <sys/types.h>
150
#include <sys/shm.h>
151
152
int main(void)
153
{
154
pid_t pid;
155
int ipckey, ret;
156
157
printf("Testing denied shared memory attach out of chroot... : ");
158
fflush(stdout);
159
160
ipckey = shmget(0, 10, IPC_CREAT | IPC_EXCL | 0700);
161
162
if (ipckey < 0) {
163
printf("Unable to create shared memory.\n");
164
return 1;
165
}
166
167
pid = fork();
168
if (pid == 0) {
169
void *shm = NULL;
170
struct shmid_ds buf;
171
172
ret = chroot("/tmp");
173
174
if (ret) {
175
printf("Unable to chroot.\n");
176
return 1;
177
}
178
179
shm = shmat(ipckey, NULL, 0);
180
181
if (shm == (void *)-1)
182
printf("PASSED\n");
183
else {
184
shmdt(shm);
185
printf("FAILED\n");
186
}
187
188
shmctl(ipckey, IPC_RMID, &buf);
189
} else if (pid > 0) {
190
int status;
191
192
wait(&status);
193
} else if (pid < 0) {
194
printf("Fork failed.\n");
195
return 1;
196
}
197
198
return 0;
199
}
200
201
Grsecurity enregistre l'id du processus du créateur et du dernier "attaché" à la mémoire partagée. Quand un attaquant tente de s'attacher à son tour à la mémoire partagée en dehors du chroot, grsecurity vérifie si le processus qui a créé cette mémoire virtuelle existe encore (si ce n'est pas le cas, c'est le processus qui s'est attaché en dernier à la mémoire partagée qui est utilisé) et compare la racine de ce processus avec celle du processus qui tente de s'attacher (celui d'un potentiel attaquant) : si les racines diffèrent, l'opération est refusée. 
202
203
204
205
Conclusion
206
207
Les différentes méthodes décrites ici pour s'échapper d'un chroot ne sont pas les seules, sans parler des moyens d'affecter le système en dehors du chroot depuis l'intérieur de celui-ci (tuer des processus, épuiser des ressources, ...). J'espère que cet article vous aura convaincu de la nécessité de faire tourner des processus dans des chroot en tant que processus non root, UID dédié au processus, puisque dès que d'autres processus existent sur le système, ils aident indéniablement un attaquant à s'échapper. 
208
209
Grsecurity, patch de sécurité pour le noyau Linux, propose un ensemble de tests illustrant les attaques décrites ici, ainsi qu'un comparatif des résultats obtenus sur différentes plateformes (OpenBSD, FreeBSD et Solaris).
210
211
Toutes les attaques contre chroot présentées ici, et quelques autres encore, pas uniquement à l'encontre de chroot, échouent lorsqu'elles sont tentées sur un Linux patché avec grsecurity. 
212
213
Pour conclure, il est possible de mettre en place des moyens pour se protéger de classes entières de vulnérabilités. Les solutions doivent être ouvertes afin que tout un chacun puisse les vérifier et contrôler. De plus, de telles solutions doivent également être simples afin que même des administrateurs inexpérimentés puissent les déployer.
214
215
216
217
Sécuritassement vÔtre 
218
- His Imperial Majesty -
219
220
221
222
223
224
225
11/09/2005 14:56</span> 
226
			</div> 
227
			<!-- REPORT / DELETE / EDIT / QUOTE DIV --> 
228
			<div align="right"> 
229
				<span class="postdetails"> Message
230
					<a title="Afficher le lien vers ce message" href="http://www.touslesreseaux.com/forum/index.php?showtopic=40&amp;view=findpost&amp;p=96" onclick="link_to_post(96); return false;">#1</a> 
231
					
232
				</span> 
233
			</div> 
234
		</td> 
235
	</tr> 
236
	<tr> 
237
		<td valign="top" class="post2"> 
238
        	<span class="postdetails"> 
239
				
240
        			<br /><br /> 
241
				
242
        		Fana<br /> 
243
        		<img src="http://www.touslesreseaux.com/images/membre.gif" alt="Ic&ocirc;ne de groupe" /><br /><br /> 
244
        		Groupe&nbsp;: Members<br /> 
245
        		Messages&nbsp;: 71<br /> 
246
        		Inscrit&nbsp;: 8-September 05<br /> 
247
        		Lieu&nbsp;: Bruxelles &amp; poivres<br /> 
248
        		Membre n<sup>o</sup>  14<br /> 
249
				
250
					
251
FAI: Skynet<br /> 
252
Vitesse: ADSL MAX (jusqu'à 8 Mb)<br /> 
253
WI-FI: Oui<br /> 
254
				
255
				<br /> 
256
        		 
257
        	</span><br /> 
258
        	<img src="style_images/touslesres1204749096/spacer.gif" alt="" width="160" height="1" /><br /> 
259
       </td> 
260
       <td width="100%" valign="top" class="post2" id='post-main-96'> 
261
			<!-- THE POST 96 --> 
262
			<div class="postcolor" id='post-96'> 
263
				Bonjour à tous amis lecteurs &amp; administrateurs nioBees &#33;&#33;&#33;<br /><br />L&#39;appel système chroot() (abréviation pour change root directory), est devenu particulièrement populaire dernièrement, entre autre grâce à l&#39;équipe d&#39;OpenBSD. De nombreux articles ont vanté les mérites de la restriction d&#39;une processus dans un chroot. L&#39;idée est de prendre un processus et de l&#39;enfermer dans un chroot pour le confiner à l&#39;intérieur d&#39;un répertoire donné dans le système de fichiers. L&#39;objectif est de protéger, prétendument, le reste du système contre une compromission complète si le processus à l&#39;intérieur du chroot est pris pour cible. <br /><br />L&#39;objectif de cet article est de démystifier certaines croyances, en montrant plusieurs attaques contre cet appel système, et la manière de les contrer, comme cela est réalisé dans grsecurity *http://www.grsecurity.net*  pour une documentation complète mais grsecurity propose entre autre des ACLs, de nombreux durcissements, des protections renforcées des zones mémoires, etc., ). Il est en effet essentiel de comprendre que des &quot;fonctionnalités&quot;, comme chroot, ne font pas tout en sécurité, mais que la manière dont elles sont réalisées et configurées est au moins aussi essentielle. <br /><br />Quand on discute des inconvénients de chroot(), la plupart des gens mettent en avant un article écrit il y a plus d&#39;un an qui décrit une attaque simple *http://www.bpfh.net/simes/computing/chroot-break.html*, mais qui ne fonctionne plus avec les versions récentes de Linux ou FreeBSD. Certaines personnes sont conscientes que si un attaquant parvient à devenir root dans un chroot, il n&#39;y a plus rien qui l&#39;empêche alors de s&#39;attaquer au reste du système. Certes, cela est tout à fait exact, mais ces mêmes personnes sont en général inconscientes des moyens à mettre enœuvre. <br /><br />Dans la suite de cet article, je décris en détails plusieurs attaques qui permettent de s&#39;évader d&#39;un chroot et de compromettre le système hôte. Certaines de ces attaques ne nécessitent pas d&#39;être root, ce que beaucoup de personnes pensent, à tort, être impossible. <br /><br /><b><span style='color:red'>Évasion d&#39;un chroot via mount</span></b><br /><br />L&#39;appel système mount(), réservé à l&#39;utilisateur root, est utilisé pour monter un système de fichiers à un endroit précis. Il prend en argument le chemin vers le device, et le chemin vers l&#39;endroit où monter le device. Évidemment, si un attaquant est autorisé à créer des devices appartenant aux disques durs présents sur le système, il peut sortir du chroot en montant des files systems et en y ajoutant des shells root par exemple. <br /><br />Il existe de nombreuses options à considérer lors de la mise en place d&#39;un chroot (voir les pages man mount et man 2 mount) dont les 3 plus intéressantes sont : <br /><br /><b>- MS_NOSUID : ignore les bits SUID et SGID ; <br />- MS_NODEV : empêche la création de devices  ; <br />- MS_NOEXEC : interdiction d&#39;exécuter des programmes.</b><br /><br />Toutefois, il reste quand même des choses à faire. En fait, pour monter certains systèmes de fichiers, il n&#39;est pas nécessaire d&#39;avoir un device. Les plus connus de ces systèmes de fichiers sont devpts et procfs. La possibilité de monter procfs constitue une fuite d&#39;information à propos du système et des processus s&#39;exécutant en dehors du chroot. <br /><br />Certains pensaient qu&#39;il était possible de sortir du chroot si procfs était monté, simplement en changeant la racine pour /proc/1/root. Cependant, cela n&#39;est plus le cas, au moins sur les noyaux Linux récents. Il reste toutefois une autre fonctionnalité offerte par procfs qui permet également de sortir du chroot qui sera présentée ci-après (cf. « évasion via sysctl »). <br /><br />Monter devpts donne à l&#39;attaquant un accès à toutes les pseudo-consoles ouvertes sur le système (par exemple, celles de ssh). L&#39;attaquant peut alors injecter des caractères via ioctl() dans les terminaux, en particulier ceux des administrateurs. <br /><br />Considérons le code suivant : <br /><br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->int fd;<br />char *buf = &#34;chmod 777 /etc/shadow&#092;n&#34;;<br />char *p;<br /><br />fd = open&#40;&#34;/dev/pts/0&#34;, O_RDWR&#41;;<br /><br />if &#40;fd &#60; 0&#41;<br />	return 1;<br /><br />for &#40;p = buf; *p; p++&#41;<br />	ioctl&#40;fd, TIOCSTI, p&#41;;<!--c2--></div><!--ec2--><br /><br />Sur une installation par défaut de Linux, cela exécute chmod 777 /etc/shadow dans le terminal d&#39;un administrateur. Grsecurity arrête les attaques de ce type en interdisant tout montage au sein d&#39;un chroot. <br /><br /><b><span style='color:red'>Évasion d&#39;un chroot via Ptrace</span></b><br /><br />ptrace() a attiré l&#39;attention dernièrement, en particulier depuis que certaines race conditions ont permis une compromission root locale. Cet appel système permet d&#39;observer et/ou de modifier le flux d&#39;exécution d&#39;un autre processus. En tant que root dans un chroot, un attaquant peut modifier le flux d&#39;exécution de n&#39;importe quel processus du système (sauf init, le premier processus). <br /><br />En tant que non root dans un chroot, l&#39;attaquant peut modifier un processus possédant le même UID. L&#39;attaquant utilise une requête PTRACE_ATTACH pour s&#39;accrocher au processus cible, puis emploie PTRACE_POKEUSR, PTRACE_SETREGS, et PTRACE_POKETEXT pour modifier ce qu&#39;il veut dans l&#39;espace d&#39;adressage du processus (et même les zones en lecture seule). <br /><br />A cause d&#39;une faible protection des pages sur la plupart des UNIXes, si l&#39;attaquant veut compromettre un processus, il trouvera très probablement une partie de l&#39;espace mémoire qui soit accessible à la fois en écriture et en exécution, même si la pile n&#39;est pas exécutable. L&#39;attaquant peut alors modifier cette région et rediriger l&#39;exécution vers le code malicieux qu&#39;il aura introduit (n&#39;importe quel shellcode par exemple) afin de sortir du chroot. L&#39;exploitation est très simple, d&#39;autant qu&#39;aucune force brute n&#39;est nécessaire puisque l&#39;attaquant à une vue complète de la mémoire du processus cible. <br /><br />Il est clair que les attaques à base de ptrace() sont très puissantes et offrent une grande diversité de solution à un attaquant. Grsecurity interdit ces attaques en empêchant l&#39;utilisation de ptrace() si le processus appelant tourne dans un chroot. De plus, comme Grsecurity garantit également qu&#39;aucun segment ne soit accessible à la fois en écriture et en exécution, cela rend les exploitations à base de ptrace() bien plus complexe. <br /><br /><br /><b><span style='color:red'>Évasion d&#39;un chroot via Fchdir</span></b><br /><br />Sortir d&#39;un chroot avec fchdir() dépend fortement de l&#39;application, au contraire des autres attaques, mais je ne connais aucun autre OS qui bloque cette attaque, en dehors de grsecurity. Cet appel système permet de changer de répertoire courant pour un file descriptor ouvert référençant un autre répertoire. <br /><br />Une exploitation est possible si le processus change de répertoire racine tout en conservant un file descriptor ouvert vers un répertoire situé en dehors du chroot (et donc sur le système de fichiers principal). L&#39;attaquant peut exploiter une faille dans le chroot et changer de répertoire pour cet autre répertoire, ou bien utiliser cela en combinaison avec l&#39;attaque ptrace décrite ci-dessus. <br /><br />Grsecurity empêche cela en descendant dans l&#39;arborescence du système de fichiers en partant du répertoire vers lequel le processus &quot;chrooté&quot; tente le fchdir(). Si l&#39;algorithme termine dans le système de fichiers chrooté, l&#39;opération est autorisée, dans le cas contraire, elle est rejetée. <br /><br /><br /><b><span style='color:red'>Évasion d&#39;un chroot via Chmod</span></b><br /><br />Cette attaque nécessite une condition très particulière, mais, avec cette réserve, donne un accès root sur le système. Les appels système chmod() et fchmod() sont utilisés pour modifier les permissions sur un fichier. L&#39;intérêt réside ici dans les droits S_ISUID et S_ISGID. Supposons qu&#39;un attaquant devienne root dans le chroot (et que cela ne suffise plus pour sortir du chroot), il peut télécharger une application quelconque, et activer le bit SUID ou SGID. Maintenant, il est possible à un attaquant (le même ou un autre) situé en dehors du chroot, mais sans être root, de passer root grâce à l&#39;application SUID/SGID. <br /><br />En guise de protection, grsecurity interdit l&#39;ajout du bit SUID ou SGID lorsque le processus est dans un chroot. <br /><br /><b><span style='color:red'>Évasion d&#39;un chroot via sysctl</span></b><br /><br />Une attaque dont je n&#39;ai entendu parler nulle part se focalise sur la fonction sysctl()&gt; pour sortir du chroot. C&#39;est une des plus élégante à exécuter et ne demande aucune des capabilities (voir /usr/src/linux/include/capability.h) particulière pour réussir. Cet appel système renseigne sur l&#39;état du noyau, et, pour un processus avec les privilèges adéquats, de le modifier. Ces paramètres sont accessibles soit via le fichier de configuration /etc/sysctl.conf, soit au travers de procfs, soit directement par l&#39;appel système sysctl(), et stockés sous formes d&#39;une base type MIB (Management Information Base). <br /><br />De là, un attaquant dispose de plusieurs choix, selon ce qui est compilé dans le noyau. Par exemple, la plupart des noyaux supportent les modules, et donc CONFIG_KMOD qui autorise le chargement automatique d&#39;un module noyau par un chargeur situé en espace utilisateur. Le chargeur habituel est /sbin/modprobe. Toutefois, il est possible d&#39;en contrôler l&#39;emplacement par une entrée dans la base avec sysctl(). Le programme suivant illustre cela : <br /><br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->#include &#60;stdio.h&#62;<br />#include &#60;string.h&#62;<br />#include &#60;unistd.h&#62;<br />#include &#60;linux/unistd.h&#62;<br />#include &#60;linux/sysctl.h&#62;<br />#include &#60;sys/socket.h&#62;<br /><br />_syscall1&#40;int, _sysctl, struct __sysctl_args *, args&#41;;<br />int sysctl&#40;int *name, int nlen, void *oldval, size_t *oldlenp,<br />           void *newval, size_t newlen&#41;<br />{<br />        struct __sysctl_args args={name,nlen,oldval,oldlenp,newval,newlen};<br />        return _sysctl&#40;&amp;args&#41;;<br />}<br /><br />#define SIZE&#40;x&#41; sizeof&#40;x&#41;/sizeof&#40;x&#91;0&#93;&#41;<br />#define MODPROBEPATHLEN 256<br /><br />char modprobepath&#91;MODPROBEPATHLEN&#93;;<br />int pathlen;<br />int name&#91;&#93; = { CTL_KERN, KERN_MODPROBE };<br /><br />int main&#40;void&#41;{<br />        strcpy&#40;modprobepath, &#34;/bin/sh&#34;&#41;;<br />        pathlen = SIZE&#40;modprobepath&#41;;<br />        if &#40;sysctl&#40;name, SIZE&#40;name&#41;, 0, NULL, modprobepath, pathlen&#41;&#41;<br />                perror&#40;&#34;sysctl&#34;&#41;;<br />        else {<br />                printf&#40;&#34;successfully modified the modprobe path.&#092;n&#34;&#41;;<br />                socket&#40;AF_SECURITY, SOCK_STREAM, 1&#41;;<br />                printf&#40;&#34;executing shell with full privileges, outside of chroot&#092;n&#34;&#41;;<br />        }<br />        return 0;<br />}<!--c2--></div><!--ec2--><br /><br />Cette attaque fonctionne car le noyau peut exécuter des programmes dans un contexte utilisateur. Quand le noyau force l&#39;exécution d&#39;un binaire, celui-ci est exécuté avec le vrai système de fichiers racine en tant que racine du nouveau processus. <br /><br />Pour stopper cela, grsecurity empêche les écritures via sysctl(), mais aussi via le procfs. <br /><br /><b><span style='color:red'>Évasion d&#39;un chroot via la mémoire partagée</span></b><br /><br />Une autre attaque intéressante pour sortir d&#39;un chroot s&#39;appuie sur l&#39;utilisation de mémoire partagée. L&#39;attaque en elle-même dépend des processus employant de la mémoire partagée en dehors du chroot. Si de tels processus existent, il est alors très probable que l&#39;attaque réussisse, indépendant de ce que la mémoire partagée de ces processus soit déclarée privée ou non au moment de sa création. <br /><br />Pour s&#39;attacher à de la mémoire partagée, l&#39;attaquant doit commencer par trouver sa cible. S&#39;attacher à de la mémoire partagée non privée est facile : il suffit de connaître (ou de &quot;bruteforcer&quot;) la clé de la mémoire virtuelle. Si la mémoire virtuelle est déclarée privée, un test supplémentaire impose que l&#39;UID effectif de l&#39;attaquant soit égal à l&#39;UID du processus ou du créateur de la mémoire partagée. <br /><br />L&#39;utilisateur root peut outrepasser ce test s&#39;il dispose de la capability CAP_IPC_OWNER, même s&#39;il existe d&#39;autres solutions pour root sans cette capability. S&#39;il dispose de CAP_SYS_ADMIN, il peut alors modifier les credentials de la mémoire partagée pour qu&#39;ils soient identiques aux siens, et ainsi s&#39;attacher au processus. Si l&#39;attaquant dispose de CAP_SETUID, il peut modifier son UID pour la faire correspondre à celle de la mémoire partagée. <br /><br />Finalement, si le processus compromis dans le chroot possède un UID effectif égal à celui de la cible utilisant de la mémoire partagée, l&#39;attaquant peut sortir du chroot sans avoir besoin des droits de root. Faire tourner des démons sous l&#39;identité nobody est assez classique sur nos systèmes, et cette attaque devient alors particulièrement intéressante. Après avoir obtenu les credentials sur la mémoire partagée, l&#39;attaquant peut récupérer l&#39;identification de la mémoire avec la fonction shmget(), puis s&#39;attacher à cette mémoire avec shmat(). L&#39;attaquant peut alors profiter de cet accès pour modifier des entiers, des chaînes de caractères, ..., pour exploiter le processus <br /><br />Le programme suivant permet de déterminer si votre système est vulnérable ou non, que ce soit un Linux, un FreeBSD, un NetBSD, un OpenBSD ou un Solaris : <br /><br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->#include &#60;stdio.h&#62;<br />#include &#60;sys/ipc.h&#62;<br />#include &#60;sys/types.h&#62;<br />#include &#60;sys/shm.h&#62;<br /><br />int main&#40;void&#41;<br />{<br />        pid_t pid;<br />        int ipckey, ret;<br /><br />        printf&#40;&#34;Testing denied shared memory attach out of chroot... &#58; &#34;&#41;;<br />        fflush&#40;stdout&#41;;<br /><br />        ipckey = shmget&#40;0, 10, IPC_CREAT | IPC_EXCL | 0700&#41;;<br /><br />        if &#40;ipckey &#60; 0&#41; {<br />                printf&#40;&#34;Unable to create shared memory.&#092;n&#34;&#41;;<br />                return 1;<br />        }<br /><br />        pid = fork&#40;&#41;;<br />        if &#40;pid == 0&#41; {<br />                void *shm = NULL;<br />                struct shmid_ds buf;<br /><br />                ret = chroot&#40;&#34;/tmp&#34;&#41;;<br /><br />                if &#40;ret&#41; {<br />                        printf&#40;&#34;Unable to chroot.&#092;n&#34;&#41;;<br />                        return 1;<br />                }<br /><br />                shm = shmat&#40;ipckey, NULL, 0&#41;;<br /><br />                if &#40;shm == &#40;void *&#41;-1&#41;<br />                        printf&#40;&#34;PASSED&#092;n&#34;&#41;;<br />                else {<br />                        shmdt&#40;shm&#41;;<br />                        printf&#40;&#34;FAILED&#092;n&#34;&#41;;<br />                }<br /><br />                shmctl&#40;ipckey, IPC_RMID, &amp;buf&#41;;<br />        } else if &#40;pid &#62; 0&#41; {<br />                int status;<br /><br />                wait&#40;&amp;status&#41;;<br />        } else if &#40;pid &#60; 0&#41; {<br />                printf&#40;&#34;Fork failed.&#092;n&#34;&#41;;<br />                return 1;<br />        }<br /><br />        return 0;<br />}<!--c2--></div><!--ec2--><br /><br />Grsecurity enregistre l&#39;id du processus du créateur et du dernier &quot;attaché&quot; à la mémoire partagée. Quand un attaquant tente de s&#39;attacher à son tour à la mémoire partagée en dehors du chroot, grsecurity vérifie si le processus qui a créé cette mémoire virtuelle existe encore (si ce n&#39;est pas le cas, c&#39;est le processus qui s&#39;est attaché en dernier à la mémoire partagée qui est utilisé) et compare la racine de ce processus avec celle du processus qui tente de s&#39;attacher (celui d&#39;un potentiel attaquant) : si les racines diffèrent, l&#39;opération est refusée. <br /><br /><br /><br /><b><span style='color:red'>Conclusion</span></b><br /><br />Les différentes méthodes décrites ici pour s&#39;échapper d&#39;un chroot ne sont pas les seules, sans parler des moyens d&#39;affecter le système en dehors du chroot depuis l&#39;intérieur de celui-ci (tuer des processus, épuiser des ressources, ...). J&#39;espère que cet article vous aura convaincu de la nécessité de faire tourner des processus dans des chroot en tant que processus non root, UID dédié au processus, puisque dès que d&#39;autres processus existent sur le système, ils aident indéniablement un attaquant à s&#39;échapper. <br /><br /><a href='http://cvsweb.grsecurity.net/index.cgi/regression' target='_blank'>Grsecurity, patch de sécurité pour le noyau Linux, propose un ensemble de tests illustrant les attaques décrites ici, ainsi qu&#39;un comparatif des résultats obtenus sur différentes plateformes (OpenBSD, FreeBSD et Solaris).</a><br /><br />Toutes les attaques contre chroot présentées ici, et quelques autres encore, pas uniquement à l&#39;encontre de chroot, échouent lorsqu&#39;elles sont tentées sur un Linux patché avec grsecurity. <br /><br />Pour conclure, il est possible de mettre en place des moyens pour se protéger de classes entières de vulnérabilités. Les solutions doivent être ouvertes afin que tout un chacun puisse les vérifier et contrôler. De plus, de telles solutions doivent également être simples afin que même des administrateurs inexpérimentés puissent les déployer.<br /><br /><br /><br />Sécuritassement vÔtre <br />- His Imperial Majesty -