Skip to content

Commit 70f3006

Browse files
save file
1 parent 006a0f5 commit 70f3006

File tree

1 file changed

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

1 file changed

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

0 commit comments

Comments
 (0)