|
5 | 5 | import java.io.PrintWriter;
|
6 | 6 | import java.nio.file.Path;
|
7 | 7 | import java.nio.file.Paths;
|
| 8 | +import java.net.URI; |
8 | 9 | import java.net.URL;
|
| 10 | +import java.net.URISyntaxException; |
9 | 11 |
|
10 | 12 | import javax.servlet.http.HttpServlet;
|
11 | 13 | import javax.servlet.http.HttpServletRequest;
|
|
15 | 17 | import javax.servlet.ServletConfig;
|
16 | 18 | import javax.servlet.ServletContext;
|
17 | 19 |
|
| 20 | +import io.undertow.server.handlers.resource.FileResourceManager; |
| 21 | +import io.undertow.server.handlers.resource.Resource; |
| 22 | +import org.jboss.vfs.VFS; |
| 23 | +import org.jboss.vfs.VirtualFile; |
| 24 | + |
18 | 25 | public class UnsafeResourceGet extends HttpServlet {
|
19 | 26 | private static final String BASE_PATH = "/pages";
|
20 | 27 |
|
@@ -137,7 +144,7 @@ protected void doHead(HttpServletRequest request, HttpServletResponse response)
|
137 | 144 | ServletOutputStream out = response.getOutputStream();
|
138 | 145 |
|
139 | 146 | // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
|
140 |
| - // Note the class is in two levels of subpackages and `Class.loadResource` starts from its own directory |
| 147 | + // Note the class is in two levels of subpackages and `Class.getResource` starts from its own directory |
141 | 148 | URL url = getClass().getResource(requestUrl);
|
142 | 149 |
|
143 | 150 | InputStream in = url.openStream();
|
@@ -205,4 +212,59 @@ protected void doPutGood(HttpServletRequest request, HttpServletResponse respons
|
205 | 212 | }
|
206 | 213 | }
|
207 | 214 | }
|
| 215 | + |
| 216 | + // BAD: getResource constructed from `ClassLoader` without input validation |
| 217 | + protected void doPutBad(HttpServletRequest request, HttpServletResponse response) |
| 218 | + throws ServletException, IOException { |
| 219 | + String requestUrl = request.getParameter("requestURL"); |
| 220 | + ServletOutputStream out = response.getOutputStream(); |
| 221 | + |
| 222 | + // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file |
| 223 | + // Note the class is in two levels of subpackages and `ClassLoader.getResource` starts from its own directory |
| 224 | + URL url = getClass().getClassLoader().getResource(requestUrl); |
| 225 | + |
| 226 | + InputStream in = url.openStream(); |
| 227 | + byte[] buf = new byte[4 * 1024]; // 4K buffer |
| 228 | + int bytesRead; |
| 229 | + while ((bytesRead = in.read(buf)) != -1) { |
| 230 | + out.write(buf, 0, bytesRead); |
| 231 | + } |
| 232 | + } |
| 233 | + |
| 234 | + // BAD: getResource constructed using Undertow IO without input validation |
| 235 | + protected void doPutBad2(HttpServletRequest request, HttpServletResponse response) |
| 236 | + throws ServletException, IOException { |
| 237 | + String requestPath = request.getParameter("requestPath"); |
| 238 | + |
| 239 | + try { |
| 240 | + FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile()); |
| 241 | + Resource rs = rm.getResource(requestPath); |
| 242 | + |
| 243 | + VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/")); |
| 244 | + // Do file operations |
| 245 | + overlay.getChild(rs.getPath()); |
| 246 | + } catch (URISyntaxException ue) { |
| 247 | + throw new IOException("Cannot parse the URI"); |
| 248 | + } |
| 249 | + } |
| 250 | + |
| 251 | + // GOOD: getResource constructed using Undertow IO with input validation |
| 252 | + protected void doPutGood2(HttpServletRequest request, HttpServletResponse response) |
| 253 | + throws ServletException, IOException { |
| 254 | + String requestPath = request.getParameter("requestPath"); |
| 255 | + |
| 256 | + try { |
| 257 | + FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile()); |
| 258 | + Resource rs = rm.getResource(requestPath); |
| 259 | + |
| 260 | + VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/")); |
| 261 | + String path = rs.getPath(); |
| 262 | + if (path.startsWith("/trusted_path") && !path.contains("..")) { |
| 263 | + // Do file operations |
| 264 | + overlay.getChild(path); |
| 265 | + } |
| 266 | + } catch (URISyntaxException ue) { |
| 267 | + throw new IOException("Cannot parse the URI"); |
| 268 | + } |
| 269 | + } |
208 | 270 | }
|
0 commit comments