Comparison

plugins/mod_http_files.lua @ 7058:e9f07febafb3

mod_http_files: Santize the path relative to our base URL before translating it to a filesystem path, fixes a relative path traversal vulnerability
author Matthew Wild <mwild1@gmail.com>
date Thu, 07 Jan 2016 15:37:47 +0000
parent 6873:6dae43341b44
child 7061:eda0feeaf759
child 7228:b5b7ae2901e6
comparison
equal deleted inserted replaced
7057:c633e1338554 7058:e9f07febafb3
47 end 47 end
48 }); 48 });
49 end 49 end
50 end 50 end
51 51
52 local forbidden_chars_pattern = "[/%z]";
53 if prosody.platform == "windows" then
54 forbidden_chars_pattern = "[/%z\001-\031\127\"*:<>?|]"
55 end
56
57 local urldecode = require "util.http".urldecode;
58 function sanitize_path(path)
59 local out = {};
60
61 local c = 0;
62 for component in path:gmatch("([^/]+)") do
63 component = urldecode(component);
64 if component:find(forbidden_chars_pattern) then
65 return nil;
66 elseif component == ".." then
67 if c <= 0 then
68 return nil;
69 end
70 out[c] = nil;
71 c = c - 1;
72 elseif component ~= "." then
73 c = c + 1;
74 out[c] = component;
75 end
76 end
77 return "/"..table.concat(out, "/");
78 end
79
52 local cache = setmetatable({}, { __mode = "kv" }); -- Let the garbage collector have it if it wants to. 80 local cache = setmetatable({}, { __mode = "kv" }); -- Let the garbage collector have it if it wants to.
53 81
54 function serve(opts) 82 function serve(opts)
55 if type(opts) ~= "table" then -- assume path string 83 if type(opts) ~= "table" then -- assume path string
56 opts = { path = opts }; 84 opts = { path = opts };
58 local base_path = opts.path; 86 local base_path = opts.path;
59 local dir_indices = opts.index_files or dir_indices; 87 local dir_indices = opts.index_files or dir_indices;
60 local directory_index = opts.directory_index; 88 local directory_index = opts.directory_index;
61 local function serve_file(event, path) 89 local function serve_file(event, path)
62 local request, response = event.request, event.response; 90 local request, response = event.request, event.response;
63 local orig_path = request.path; 91 path = sanitize_path(path);
92 if not path then
93 return 400;
94 end
95 local orig_path = sanitize_path(request.path);
64 local full_path = base_path .. (path and "/"..path or ""):gsub("/", path_sep); 96 local full_path = base_path .. (path and "/"..path or ""):gsub("/", path_sep);
65 local attr = stat(full_path:match("^.*[^\\/]")); -- Strip trailing path separator because Windows 97 local attr = stat(full_path:match("^.*[^\\/]")); -- Strip trailing path separator because Windows
66 if not attr then 98 if not attr then
67 return 404; 99 return 404;
68 end 100 end