Skip to content

Commit fdcdb87

Browse files
save file
1 parent 9fa908f commit fdcdb87

File tree

1 file changed

+250
-0
lines changed
  • blog/26-02-05/request-url-to-absolute-filename/ex

1 file changed

+250
-0
lines changed
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
2+
3+
resolve.df = false;
4+
5+
function resolve(url,docroot='.'){
6+
resolve.df && console.log('=== resolve v2.0 ===');
7+
resolve.df && console.log('url :',url);
8+
resolve.df && console.log('docroot :',docroot);
9+
var err;
10+
try{
11+
12+
url = decodeURI(url);
13+
14+
}//try
15+
catch(err2){
16+
17+
err = err2;
18+
19+
}//catch
20+
if(err){
21+
resolve.df && console.error(err);
22+
return false;
23+
}
24+
25+
url = url.slice(1);
26+
resolve.df && console.log('url :',url);
27+
var root = path.resolve(docroot);
28+
root += path.sep;
29+
resolve.df && console.log('root :',root);
30+
var abs = path.resolve(docroot,url);
31+
resolve.df && console.log('abs :',abs);
32+
33+
if(!abs.startsWith(root)){
34+
resolve.df && console.log('fail');
35+
return false;
36+
}
37+
38+
if(url.endsWith('/')){
39+
abs += '/';
40+
}
41+
resolve.df && console.log('ok',abs);
42+
return abs;
43+
44+
}//resolve
45+
46+
47+
48+
49+
var path = require('path');
50+
var test = setup();
51+
52+
53+
test.tests.forEach((item,i)=>{
54+
55+
var abs = resolve(item.url,test.docroot);
56+
57+
console.log();
58+
console.log(i,item.note);
59+
console.log('value :',item.url);
60+
console.log('expected :',item.expected);
61+
console.log('result : ',abs);
62+
console.log();
63+
64+
});
65+
66+
67+
68+
function setup(){
69+
70+
return {
71+
72+
"docroot" : "/var/www",
73+
"tests" : [
74+
{
75+
"url": "/index.html",
76+
"expected": "/var/www/index.html",
77+
"note": "Basic file"
78+
},
79+
{
80+
"url": "/css/style.css",
81+
"expected": "/var/www/css/style.css",
82+
"note": "Nested file"
83+
},
84+
{
85+
"url": "/images/",
86+
"expected": "/var/www/images/",
87+
"note": "Directory with trailing slash"
88+
},
89+
{
90+
"url": "/folder/sub/file.txt",
91+
"expected": "/var/www/folder/sub/file.txt",
92+
"note": "Deep nested file"
93+
},
94+
95+
/* Traversal attempts */
96+
{
97+
"url": "/../secret.txt",
98+
"expected": false,
99+
"note": "Simple traversal"
100+
},
101+
{
102+
"url": "/../../etc/passwd",
103+
"expected": false,
104+
"note": "Traversal to root"
105+
},
106+
{
107+
"url": "/foo/../../secret.txt",
108+
"expected": false,
109+
"note": "Traversal inside nested path"
110+
},
111+
{
112+
"url": "/..",
113+
"expected": false,
114+
"note": "Parent directory"
115+
},
116+
{
117+
"url": "/../",
118+
"expected": false,
119+
"note": "Parent directory with slash"
120+
},
121+
122+
/* Encoded traversal */
123+
{
124+
"url": "/%2e%2e/secret.txt",
125+
"expected": false,
126+
"note": "Encoded .."
127+
},
128+
{
129+
"url": "/foo/%2e%2e/%2e%2e/passwd",
130+
"expected": false,
131+
"note": "Double encoded traversal"
132+
},
133+
{
134+
"url": "/%2e%2e/%2e%2e/etc/passwd",
135+
"expected": false,
136+
"note": "Encoded traversal to root"
137+
},
138+
139+
/* Double-encoded traversal */
140+
{
141+
"url": "/%252e%252e/%252e%252e/etc/passwd",
142+
"expected": "/var/www/%2e%2e/%2e%2e/etc/passwd",
143+
"note": "Double-encoded stays inside docroot after single decode"
144+
},
145+
146+
/* Mixed slash styles */
147+
{
148+
"url": "/..\\..\\Windows\\win.ini",
149+
"expected": false,
150+
"note": "Windows backslash traversal"
151+
},
152+
{
153+
"url": "/folder\\sub\\file.txt",
154+
"expected": "/var/www/folder/sub/file.txt",
155+
"note": "Windows slashes inside docroot"
156+
},
157+
158+
/* Absolute path attempts */
159+
{
160+
"url": "/etc/passwd",
161+
"expected": "/var/www/etc/passwd",
162+
"note": "Absolute path becomes relative after slice"
163+
},
164+
{
165+
"url": "C:\\Windows\\win.ini",
166+
"expected": false,
167+
"note": "Windows absolute path attack"
168+
},
169+
{
170+
"url": "/C:/Windows/win.ini",
171+
"expected": false,
172+
"note": "Windows absolute path with leading slash"
173+
},
174+
175+
/* Malformed garbage */
176+
{
177+
"url": "/....//....//etc/passwd",
178+
"expected": false,
179+
"note": "Weird dot spam traversal"
180+
},
181+
{
182+
"url": "/foo/%",
183+
"expected": false,
184+
"note": "Malformed percent encoding"
185+
},
186+
{
187+
"url": "/foo/%0",
188+
"expected": false,
189+
"note": "Malformed percent encoding 2"
190+
},
191+
192+
/* Unicode weirdness */
193+
{
194+
"url": "/föö/bar.txt",
195+
"expected": "/var/www/föö/bar.txt",
196+
"note": "Unicode filename"
197+
},
198+
{
199+
"url": "/%C0%AFetc/passwd",
200+
"expected": false,
201+
"note": "Overlong UTF-8 slash"
202+
},
203+
204+
/* Directory edge cases */
205+
{
206+
"url": "/",
207+
"expected": "/var/www/",
208+
"note": "Root directory"
209+
},
210+
{
211+
"url": "/./",
212+
"expected": "/var/www/",
213+
"note": "Dot directory"
214+
},
215+
{
216+
"url": "/folder/./file.txt",
217+
"expected": "/var/www/folder/file.txt",
218+
"note": "Dot inside path"
219+
},
220+
{
221+
"url": "/folder///sub///file.txt",
222+
"expected": "/var/www/folder/sub/file.txt",
223+
"note": "Multiple slashes"
224+
},
225+
226+
/* Ultra-weird attacker payloads */
227+
{
228+
"url": "/..////..////etc/passwd",
229+
"expected": false,
230+
"note": "Slash spam traversal"
231+
},
232+
{
233+
"url": "/foo/%2e%2e%2f%2e%2e%2fetc/passwd",
234+
"expected": false,
235+
"note": "Encoded slash traversal"
236+
},
237+
{
238+
"url": "/foo/%F0%9F%92%A9/bar.txt",
239+
"expected": "/var/www/foo/💩/bar.txt",
240+
"note": "Emoji in path"
241+
}
242+
]
243+
}
244+
245+
}//setup
246+
247+
248+
249+
250+

0 commit comments

Comments
 (0)