1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
From: Christian.Schroeder@Inf-Technik.TU-Ilmenau.DE (Ch. Schroeder)
Message-Id: <9510171319.AA19401@pegasus>
Subject: yale tftpd
To: pst@cisco.com
Date: Tue, 17 Oct 1995 14:19:32 +0100 (MET)
Hello Paul,
Some days ago I foung the yale tftp daemon (3.0) on the INTERNET and I want to
use it because I have to follow symbolic links from the tftp root directory
to some bootfiles in other directories in the local filesystem.
But I found, that there are some security holes (?) in the code, specially
if the daemon checks the pathname of the requested file. That is dangereous
if no default access rules are specified.
i.e:
config file:
------------
defaultDirectory /tftpboot
rootDirectory /tftpboot
accessList 1 readonly 141.24.20.0 0.0.3.255
defaultAccessList 1
The following reqeusts were successfully and I think, that shouldn't be so.
tftp> get /etc/passwd ./foo
Error code 1: File not found
tftp> get /tftpboot/../../etc/passwd ./foo
Received 474 bytes in 0.3 seconds
tftp> get ../../etc/passwd ./foo
Received 474 bytes in 0.1 seconds
tftp>
I found also some Problems when I dont secify a rootDirectory.
Specially the "../.." parts are only removed, if a root directory
is specified AND the path starts with "/" AND the path doesn't start
with the virtual root directory (e.g. /tftpboot). restrict rules can
be skipped with leading ../.. etc.
Therefore I made some changes in tftpd.c an got better results.
tftp> get /etc/passwd ./foo
Error code 1: File not found
tftp> get /tftpboot/../../etc/passwd ./foo
Error code 2: Access violation
tftp> get ../../etc/passwd ./foo
Error code 1: File not found
tftp>
It would be very nice, if you could check my modifications and
mail me your meaning back. (Excuse please my ugly english)
Christian
Here's the diff File ( diff -bw -c tftpd.c tftpd.c.patched ):
*** tftpd.c Tue Oct 17 14:09:01 1995
--- tftpd.c.patched Tue Oct 17 11:57:30 1995
***************
*** 459,475 ****
/* Rule 2:
*/
! if (tftpRootDirectory != 0 && IS_ROOTED(filename)) {
char _tmp[1024];
int maxPath;
int rootLen;
! rootLen = strlen (tftpRootDirectory);
/* make sure the pathname doesn't already contain
* the virtual root.
*/
- if (strncmp(filename,tftpRootDirectory,rootLen) != 0) {
/* Insure our temporary space is big enough */
maxPath = ((sizeof _tmp) - 1) - rootLen;
--- 459,483 ----
/* Rule 2:
*/
! if ((tftpRootDirectory != 0 && IS_ROOTED(filename)) ||
! (tftpDefaultDirectory != 0 && IS_ROOTED(filename))) {
char _tmp[1024];
+ char* realRootDir;
int maxPath;
int rootLen;
! if (tftpRootDirectory != 0 ) {
! realRootDir = tftpRootDirectory;
! }
! else {
! realRootDir = tftpDefaultDirectory;
! }
+ rootLen = strlen (realRootDir);
+
/* make sure the pathname doesn't already contain
* the virtual root.
*/
/* Insure our temporary space is big enough */
maxPath = ((sizeof _tmp) - 1) - rootLen;
***************
*** 481,486 ****
--- 489,496 ----
return EACCESS;
}
+ if (strncmp(filename,realRootDir,rootLen) != 0) {
+
/* Squeeze out any '.' or '..' components */
strcpy (tmpPath, filename);
if (realPath (tmpPath, _tmp) < 0) {
***************
*** 492,511 ****
/* Create the full pathname, prefixed by the
* virtual root.
*/
! strcpy (tmpPath, tftpRootDirectory);
strcat (tmpPath, _tmp);
filename = tmpPath;
}
}
/* Rule 3:
*/
! if (!IS_ROOTED(filename) && tftpDefaultDirectory == 0) {
! strcpy (tmpPath, tftpRootDirectory);
! strcat (tmpPath, "/");
strcat (tmpPath, filename);
filename = tmpPath;
}
/* Check access lists */
/* Rules 4&5:
--- 502,554 ----
/* Create the full pathname, prefixed by the
* virtual root.
*/
! strcpy (tmpPath, realRootDir);
strcat (tmpPath, _tmp);
filename = tmpPath;
}
+ else {
+ /* Squeeze out any '.' or '..' components */
+ strcpy (tmpPath, filename);
+ if (realPath (tmpPath, _tmp) < 0) {
+ if (tftpDebugLevel > 1)
+ syslog (LOG_DEBUG, "realPath fails");
+ return EACCESS;
}
+ /* Create the full pathname */
+ strcpy (tmpPath,_tmp);
+ filename = tmpPath;
+ if (strncmp(filename,realRootDir,rootLen) != 0) {
+ if (tftpDebugLevel > 1) {
+ syslog(LOG_DEBUG, "file=%s; invalid access denied", filename);
+ return EACCESS;
+ }
+ }
+ }
+ }
/* Rule 3:
*/
! if ((!IS_ROOTED(filename) && tftpRootDirectory != 0) ||
! (!IS_ROOTED(filename) && tftpDefaultDirectory != 0)) {
! char _tmp[1024];
strcat (tmpPath, filename);
+ /* Squeeze out any '.' or '..' components */
+ strcpy (tmpPath, filename);
+ if (realPath (tmpPath, _tmp) < 0) {
+ if (tftpDebugLevel > 1)
+ syslog (LOG_DEBUG, "realPath fails");
+ return EACCESS;
+ }
+ if ( tftpDefaultDirectory == 0 ) {
+ strcpy (tmpPath, tftpRootDirectory);
+ }
+ else {
+ strcpy (tmpPath, tftpDefaultDirectory);
+ }
+ strcat (tmpPath, _tmp);
filename = tmpPath;
}
+
/* Check access lists */
/* Rules 4&5:
--
***
(o o)
---------------------------------------ooO--(_)--Ooo----------------------
| | |
| | Christian Schroeder (Dr.-Ing.) |
| | |
| _/_/_/ _/_/_/ | Technische Universitaet Ilmenau |
| _/ _/ _/ _/ | Fakultaet Elektrotechnik/Informationstechnik |
| _/ _/ | Mikroelektronische Schaltungen u. Systeme |
| _/ _/_/_/ | Postfach 0565 |
| _/ _/ | 98684 ILMENAU |
| _/ _/ _/ _/ | |
| _/_/_/ _/_/_/ | Phone : +49 (0) 3677/69-1165/1168/1169 |
| | FAX : +49 (0) 3677/69-1163 |
| | E-Mail : schroeder@Inf-Technik.TU-Ilmenau.DE |
--------------------------------------------------------------------------
|