diff --git a/java/ql/lib/semmle/code/java/frameworks/Servlets.qll b/java/ql/lib/semmle/code/java/frameworks/Servlets.qll index de82d49a7aaa..b3fa7ff4e363 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Servlets.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Servlets.qll @@ -377,3 +377,26 @@ class RequestDispatchMethod extends Method { this.hasName(["forward", "include"]) } } + +/** + * The interface `javax.servlet.ServletContext`. + */ +class ServletContext extends RefType { + ServletContext() { this.hasQualifiedName("javax.servlet", "ServletContext") } +} + +/** The `getResource` method of `ServletContext`. */ +class GetServletResourceMethod extends Method { + GetServletResourceMethod() { + this.getDeclaringType() instanceof ServletContext and + this.hasName("getResource") + } +} + +/** The `getResourceAsStream` method of `ServletContext`. */ +class GetServletResourceAsStreamMethod extends Method { + GetServletResourceAsStreamMethod() { + this.getDeclaringType() instanceof ServletContext and + this.hasName("getResourceAsStream") + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java new file mode 100644 index 000000000000..8b3583bf59e2 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java @@ -0,0 +1,18 @@ +// BAD: no URI validation +URL url = request.getServletContext().getResource(requestUrl); +url = getClass().getResource(requestUrl); +InputStream in = url.openStream(); + +InputStream in = request.getServletContext().getResourceAsStream(requestPath); +in = getClass().getClassLoader().getResourceAsStream(requestPath); + +// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix: +// (alternatively use `Path.normalize` instead of checking for `..`) +if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) { + InputStream in = request.getServletContext().getResourceAsStream(requestPath); +} + +Path path = Paths.get(requestUrl).normalize().toRealPath(); +if (path.startsWith("/trusted")) { + URL url = request.getServletContext().getResource(path.toString()); +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp index 345eca1e5d43..b1bcf6350c3c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp @@ -36,6 +36,13 @@ attacks. It also shows how to remedy the problem by validating the user input. +

The following examples show an HTTP request parameter or request path being used directly to +retrieve a resource of a Java EE application without validating the input, which allows sensitive +file exposure attacks. It also shows how to remedy the problem by validating the user input. +

+ + +
  • File Disclosure: @@ -47,5 +54,8 @@ attacks. It also shows how to remedy the problem by validating the user input.
  • Micro Focus: File Disclosure: J2EE
  • +
  • CVE-2015-5174: + Apache Tomcat 6.0/7.0/8.0/9.0 Servletcontext getResource/getResourceAsStream/getResourcePaths Path Traversal +
  • diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql index 9a9a70e45462..0e8fd0a4fe57 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql @@ -14,6 +14,7 @@ import java import UnsafeUrlForward import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking +import experimental.semmle.code.java.frameworks.Jsf import experimental.semmle.code.java.PathSanitizer import DataFlow::PathGraph @@ -43,6 +44,20 @@ class UnsafeUrlForwardFlowConfig extends TaintTracking::Configuration { override DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext } + + override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodAccess ma | + ( + ma.getMethod() instanceof GetServletResourceMethod or + ma.getMethod() instanceof GetFacesResourceMethod or + ma.getMethod() instanceof GetClassResourceMethod or + ma.getMethod() instanceof GetClassLoaderResourceMethod or + ma.getMethod() instanceof GetWildflyResourceMethod + ) and + ma.getArgument(0) = prev.asExpr() and + ma = succ.asExpr() + ) + } } from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeUrlForwardFlowConfig conf diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll index 9601a988f9fd..5471f55b212a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll @@ -1,7 +1,9 @@ import java +private import experimental.semmle.code.java.frameworks.Jsf private import semmle.code.java.dataflow.ExternalFlow private import semmle.code.java.dataflow.FlowSources private import semmle.code.java.dataflow.StringPrefixes +private import semmle.code.java.frameworks.javaee.ejb.EJBRestrictions /** A sink for unsafe URL forward vulnerabilities. */ abstract class UnsafeUrlForwardSink extends DataFlow::Node { } @@ -19,6 +21,84 @@ private class RequestDispatcherSink extends UnsafeUrlForwardSink { } } +/** The `getResource` method of `Class`. */ +class GetClassResourceMethod extends Method { + GetClassResourceMethod() { + this.getDeclaringType() instanceof TypeClass and + this.hasName("getResource") + } +} + +/** The `getResourceAsStream` method of `Class`. */ +class GetClassResourceAsStreamMethod extends Method { + GetClassResourceAsStreamMethod() { + this.getDeclaringType() instanceof TypeClass and + this.hasName("getResourceAsStream") + } +} + +/** The `getResource` method of `ClassLoader`. */ +class GetClassLoaderResourceMethod extends Method { + GetClassLoaderResourceMethod() { + this.getDeclaringType() instanceof ClassLoaderClass and + this.hasName("getResource") + } +} + +/** The `getResourceAsStream` method of `ClassLoader`. */ +class GetClassLoaderResourceAsStreamMethod extends Method { + GetClassLoaderResourceAsStreamMethod() { + this.getDeclaringType() instanceof ClassLoaderClass and + this.hasName("getResourceAsStream") + } +} + +/** The JBoss class `FileResourceManager`. */ +class FileResourceManager extends RefType { + FileResourceManager() { + this.hasQualifiedName("io.undertow.server.handlers.resource", "FileResourceManager") + } +} + +/** The JBoss method `getResource` of `FileResourceManager`. */ +class GetWildflyResourceMethod extends Method { + GetWildflyResourceMethod() { + this.getDeclaringType().getASupertype*() instanceof FileResourceManager and + this.hasName("getResource") + } +} + +/** The JBoss class `VirtualFile`. */ +class VirtualFile extends RefType { + VirtualFile() { this.hasQualifiedName("org.jboss.vfs", "VirtualFile") } +} + +/** The JBoss method `getChild` of `FileResourceManager`. */ +class GetVirtualFileChildMethod extends Method { + GetVirtualFileChildMethod() { + this.getDeclaringType().getASupertype*() instanceof VirtualFile and + this.hasName("getChild") + } +} + +/** An argument to `getResource()` or `getResourceAsStream()`. */ +private class GetResourceSink extends UnsafeUrlForwardSink { + GetResourceSink() { + sinkNode(this, "open-url") + or + exists(MethodAccess ma | + ( + ma.getMethod() instanceof GetServletResourceAsStreamMethod or + ma.getMethod() instanceof GetFacesResourceAsStreamMethod or + ma.getMethod() instanceof GetClassResourceAsStreamMethod or + ma.getMethod() instanceof GetClassLoaderResourceAsStreamMethod or + ma.getMethod() instanceof GetVirtualFileChildMethod + ) and + ma.getArgument(0) = this.asExpr() + ) + } +} + /** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */ private class SpringModelAndViewSink extends UnsafeUrlForwardSink { SpringModelAndViewSink() { @@ -80,7 +160,7 @@ private class ServletGetPathSource extends SourceModelCsv { } } -/** Taint model related to `java.nio.file.Path`. */ +/** Taint model related to `java.nio.file.Path` and `io.undertow.server.handlers.resource.Resource`. */ private class FilePathFlowStep extends SummaryModelCsv { override predicate row(string row) { row = @@ -88,7 +168,10 @@ private class FilePathFlowStep extends SummaryModelCsv { "java.nio.file;Paths;true;get;;;Argument[0..1];ReturnValue;taint", "java.nio.file;Path;true;resolve;;;Argument[-1..0];ReturnValue;taint", "java.nio.file;Path;true;normalize;;;Argument[-1];ReturnValue;taint", - "java.nio.file;Path;true;toString;;;Argument[-1];ReturnValue;taint" + "java.nio.file;Path;true;toString;;;Argument[-1];ReturnValue;taint", + "io.undertow.server.handlers.resource;Resource;true;getFile;;;Argument[-1];ReturnValue;taint", + "io.undertow.server.handlers.resource;Resource;true;getFilePath;;;Argument[-1];ReturnValue;taint", + "io.undertow.server.handlers.resource;Resource;true;getPath;;;Argument[-1];ReturnValue;taint" ] } } diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Jsf.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Jsf.qll new file mode 100644 index 000000000000..a013c341c67c --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Jsf.qll @@ -0,0 +1,34 @@ +/** + * Provides classes and predicates for working with the Java Server Faces (JSF). + */ + +import java + +/** + * The JSF class `ExternalContext` for processing HTTP requests. + */ +class ExternalContext extends RefType { + ExternalContext() { + this.hasQualifiedName(["javax.faces.context", "jakarta.faces.context"], "ExternalContext") + } +} + +/** + * The method `getResource()` declared in JSF `ExternalContext`. + */ +class GetFacesResourceMethod extends Method { + GetFacesResourceMethod() { + this.getDeclaringType().getASupertype*() instanceof ExternalContext and + this.hasName("getResource") + } +} + +/** + * The method `getResourceAsStream()` declared in JSF `ExternalContext`. + */ +class GetFacesResourceAsStreamMethod extends Method { + GetFacesResourceAsStreamMethod() { + this.getDeclaringType().getASupertype*() instanceof ExternalContext and + this.hasName("getResourceAsStream") + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeResourceGet.java b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeResourceGet.java new file mode 100644 index 000000000000..64c23334f187 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeResourceGet.java @@ -0,0 +1,270 @@ +package com.example; + +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.net.URI; +import java.net.URL; +import java.net.URISyntaxException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletException; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import io.undertow.server.handlers.resource.FileResourceManager; +import io.undertow.server.handlers.resource.Resource; +import org.jboss.vfs.VFS; +import org.jboss.vfs.VirtualFile; + +public class UnsafeResourceGet extends HttpServlet { + private static final String BASE_PATH = "/pages"; + + @Override + // BAD: getResource constructed from `ServletContext` without input validation + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + ServletOutputStream out = response.getOutputStream(); + + ServletConfig cfg = getServletConfig(); + ServletContext sc = cfg.getServletContext(); + + // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file + URL url = sc.getResource(requestUrl); + + InputStream in = url.openStream(); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + + // GOOD: getResource constructed from `ServletContext` with input validation + protected void doGetGood(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + ServletOutputStream out = response.getOutputStream(); + + ServletConfig cfg = getServletConfig(); + ServletContext sc = cfg.getServletContext(); + + Path path = Paths.get(requestUrl).normalize().toRealPath(); + if (path.startsWith(BASE_PATH)) { + URL url = sc.getResource(path.toString()); + + InputStream in = url.openStream(); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + } + + // GOOD: getResource constructed from `ServletContext` with null check only + protected void doGetGood2(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + PrintWriter writer = response.getWriter(); + + ServletConfig cfg = getServletConfig(); + ServletContext sc = cfg.getServletContext(); + + // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file + URL url = sc.getResource(requestUrl); + if (url == null) { + writer.println("Requested source not found"); + } + } + + // GOOD: getResource constructed from `ServletContext` with `equals` check + protected void doGetGood3(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + ServletOutputStream out = response.getOutputStream(); + + ServletContext sc = request.getServletContext(); + + if (requestUrl.equals("/public/crossdomain.xml")) { + URL url = sc.getResource(requestUrl); + + InputStream in = url.openStream(); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + } + + @Override + // BAD: getResourceAsStream constructed from `ServletContext` without input validation + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestPath = request.getParameter("requestPath"); + ServletOutputStream out = response.getOutputStream(); + + // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file + InputStream in = request.getServletContext().getResourceAsStream(requestPath); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + + // GOOD: getResourceAsStream constructed from `ServletContext` with input validation + protected void doPostGood(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestPath = request.getParameter("requestPath"); + ServletOutputStream out = response.getOutputStream(); + + if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) { + InputStream in = request.getServletContext().getResourceAsStream(requestPath); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + } + + @Override + // BAD: getResource constructed from `Class` without input validation + protected void doHead(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + ServletOutputStream out = response.getOutputStream(); + + // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file + // Note the class is in two levels of subpackages and `Class.getResource` starts from its own directory + URL url = getClass().getResource(requestUrl); + + InputStream in = url.openStream(); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + + // GOOD: getResource constructed from `Class` with input validation + protected void doHeadGood(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + ServletOutputStream out = response.getOutputStream(); + + Path path = Paths.get(requestUrl).normalize().toRealPath(); + if (path.startsWith(BASE_PATH)) { + URL url = getClass().getResource(path.toString()); + + InputStream in = url.openStream(); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + } + + @Override + // BAD: getResourceAsStream constructed from `ClassLoader` without input validation + protected void doPut(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestPath = request.getParameter("requestPath"); + ServletOutputStream out = response.getOutputStream(); + + ServletConfig cfg = getServletConfig(); + ServletContext sc = cfg.getServletContext(); + + // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file + // Note the class is in two levels of subpackages and `ClassLoader.getResourceAsStream` starts from its own directory + InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + + // GOOD: getResourceAsStream constructed from `ClassLoader` with input validation + protected void doPutGood(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestPath = request.getParameter("requestPath"); + ServletOutputStream out = response.getOutputStream(); + + ServletConfig cfg = getServletConfig(); + ServletContext sc = cfg.getServletContext(); + + if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) { + InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + } + + // BAD: getResource constructed from `ClassLoader` without input validation + protected void doPutBad(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestUrl = request.getParameter("requestURL"); + ServletOutputStream out = response.getOutputStream(); + + // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file + // Note the class is in two levels of subpackages and `ClassLoader.getResource` starts from its own directory + URL url = getClass().getClassLoader().getResource(requestUrl); + + InputStream in = url.openStream(); + byte[] buf = new byte[4 * 1024]; // 4K buffer + int bytesRead; + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + + // BAD: getResource constructed using Undertow IO without input validation + protected void doPutBad2(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestPath = request.getParameter("requestPath"); + + try { + FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile()); + Resource rs = rm.getResource(requestPath); + + VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/")); + // Do file operations + overlay.getChild(rs.getPath()); + } catch (URISyntaxException ue) { + throw new IOException("Cannot parse the URI"); + } + } + + // GOOD: getResource constructed using Undertow IO with input validation + protected void doPutGood2(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String requestPath = request.getParameter("requestPath"); + + try { + FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile()); + Resource rs = rm.getResource(requestPath); + + VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/")); + String path = rs.getPath(); + if (path.startsWith("/trusted_path") && !path.contains("..")) { + // Do file operations + overlay.getChild(path); + } + } catch (URISyntaxException ue) { + throw new IOException("Cannot parse the URI"); + } + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeResourceGet2.java b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeResourceGet2.java new file mode 100644 index 000000000000..b3d041d024cf --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeResourceGet2.java @@ -0,0 +1,58 @@ +package com.example; + +import javax.faces.context.FacesContext; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.net.URL; +import java.util.Map; + +/** Sample class of JSF managed bean */ +public class UnsafeResourceGet2 { + // BAD: getResourceAsStream constructed from `ExternalContext` without input validation + public String parameterActionBad1() throws IOException { + FacesContext fc = FacesContext.getCurrentInstance(); + Map params = fc.getExternalContext().getRequestParameterMap(); + String loadUrl = params.get("loadUrl"); + + InputStreamReader isr = new InputStreamReader(fc.getExternalContext().getResourceAsStream(loadUrl)); + BufferedReader br = new BufferedReader(isr); + if(br.ready()) { + //Do Stuff + return "result"; + } + + return "home"; + } + + // BAD: getResource constructed from `ExternalContext` without input validation + public String parameterActionBad2() throws IOException { + FacesContext fc = FacesContext.getCurrentInstance(); + Map params = fc.getExternalContext().getRequestParameterMap(); + String loadUrl = params.get("loadUrl"); + + URL url = fc.getExternalContext().getResource(loadUrl); + + InputStream in = url.openStream(); + //Do Stuff + return "result"; + } + + // GOOD: getResource constructed from `ExternalContext` with input validation + public String parameterActionGood1() throws IOException { + FacesContext fc = FacesContext.getCurrentInstance(); + Map params = fc.getExternalContext().getRequestParameterMap(); + String loadUrl = params.get("loadUrl"); + + if (loadUrl.equals("/public/crossdomain.xml")) { + URL url = fc.getExternalContext().getResource(loadUrl); + + InputStream in = url.openStream(); + //Do Stuff + return "result"; + } + + return "home"; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected index 185508dfc575..179d2b372655 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected @@ -1,5 +1,18 @@ edges | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | +| UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:17:20:17:25 | params : Map | +| UnsafeResourceGet2.java:17:20:17:25 | params : Map | UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | +| UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | +| UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:33:20:33:25 | params : Map | +| UnsafeResourceGet2.java:33:20:33:25 | params : Map | UnsafeResourceGet2.java:33:20:33:40 | get(...) : Object | +| UnsafeResourceGet2.java:33:20:33:40 | get(...) : Object | UnsafeResourceGet2.java:37:20:37:22 | url | +| UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:41:20:41:22 | url | +| UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath | +| UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:150:20:150:22 | url | +| UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | UnsafeResourceGet.java:189:68:189:78 | requestPath | +| UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | UnsafeResourceGet.java:226:20:226:22 | url | +| UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | UnsafeResourceGet.java:245:21:245:22 | rs : Resource | +| UnsafeResourceGet.java:245:21:245:22 | rs : Resource | UnsafeResourceGet.java:245:21:245:32 | getPath(...) | | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | UnsafeServletRequestDispatch.java:76:53:76:56 | path | @@ -19,6 +32,27 @@ edges nodes | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | semmle.label | getServletPath(...) : String | | UnsafeRequestPath.java:23:33:23:36 | path | semmle.label | path | +| UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map | +| UnsafeResourceGet2.java:17:20:17:25 | params : Map | semmle.label | params : Map | +| UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | semmle.label | get(...) : Object | +| UnsafeResourceGet2.java:19:93:19:99 | loadUrl | semmle.label | loadUrl | +| UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map | +| UnsafeResourceGet2.java:33:20:33:25 | params : Map | semmle.label | params : Map | +| UnsafeResourceGet2.java:33:20:33:40 | get(...) : Object | semmle.label | get(...) : Object | +| UnsafeResourceGet2.java:37:20:37:22 | url | semmle.label | url | +| UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| UnsafeResourceGet.java:41:20:41:22 | url | semmle.label | url | +| UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| UnsafeResourceGet.java:115:68:115:78 | requestPath | semmle.label | requestPath | +| UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| UnsafeResourceGet.java:150:20:150:22 | url | semmle.label | url | +| UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| UnsafeResourceGet.java:189:68:189:78 | requestPath | semmle.label | requestPath | +| UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| UnsafeResourceGet.java:226:20:226:22 | url | semmle.label | url | +| UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| UnsafeResourceGet.java:245:21:245:22 | rs : Resource | semmle.label | rs : Resource | +| UnsafeResourceGet.java:245:21:245:32 | getPath(...) | semmle.label | getPath(...) | | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | semmle.label | getParameter(...) : String | | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | semmle.label | returnURL | | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | semmle.label | getParameter(...) : String | @@ -49,6 +83,14 @@ nodes subpaths #select | UnsafeRequestPath.java:23:33:23:36 | path | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | Potentially untrusted URL forward due to $@. | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) | user-provided value | +| UnsafeResourceGet2.java:19:93:19:99 | loadUrl | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) | user-provided value | +| UnsafeResourceGet2.java:37:20:37:22 | url | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:37:20:37:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) | user-provided value | +| UnsafeResourceGet.java:41:20:41:22 | url | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:41:20:41:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) | user-provided value | +| UnsafeResourceGet.java:115:68:115:78 | requestPath | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) | user-provided value | +| UnsafeResourceGet.java:150:20:150:22 | url | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:150:20:150:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) | user-provided value | +| UnsafeResourceGet.java:189:68:189:78 | requestPath | UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | UnsafeResourceGet.java:189:68:189:78 | requestPath | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:181:24:181:58 | getParameter(...) | user-provided value | +| UnsafeResourceGet.java:226:20:226:22 | url | UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | UnsafeResourceGet.java:226:20:226:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:219:23:219:56 | getParameter(...) | user-provided value | +| UnsafeResourceGet.java:245:21:245:32 | getPath(...) | UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | UnsafeResourceGet.java:245:21:245:32 | getPath(...) | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:237:24:237:58 | getParameter(...) | user-provided value | | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) | user-provided value | | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) | user-provided value | | UnsafeServletRequestDispatch.java:76:53:76:56 | path | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | UnsafeServletRequestDispatch.java:76:53:76:56 | path | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) | user-provided value | diff --git a/java/ql/test/experimental/query-tests/security/CWE-552/options b/java/ql/test/experimental/query-tests/security/CWE-552/options index ba166b547a02..095b86c3e9a4 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-552/options +++ b/java/ql/test/experimental/query-tests/security/CWE-552/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.3.8/ \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.3.8/:${testdir}/../../../../stubs/javax-faces-2.3/:${testdir}/../../../../stubs/undertow-io-2.2/:${testdir}/../../../../stubs/jboss-vfs-3.2/ diff --git a/java/ql/test/stubs/jboss-vfs-3.2/org/jboss/vfs/VFS.java b/java/ql/test/stubs/jboss-vfs-3.2/org/jboss/vfs/VFS.java new file mode 100644 index 000000000000..e35282395586 --- /dev/null +++ b/java/ql/test/stubs/jboss-vfs-3.2/org/jboss/vfs/VFS.java @@ -0,0 +1,19 @@ +package org.jboss.vfs; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +public class VFS { + public static VirtualFile getChild(URL url) throws URISyntaxException { + return null; + } + + public static VirtualFile getChild(URI uri) { + return null; + } + + public static VirtualFile getChild(String path) { + return null; + } +} diff --git a/java/ql/test/stubs/jboss-vfs-3.2/org/jboss/vfs/VirtualFile.java b/java/ql/test/stubs/jboss-vfs-3.2/org/jboss/vfs/VirtualFile.java new file mode 100644 index 000000000000..ff6c17caff68 --- /dev/null +++ b/java/ql/test/stubs/jboss-vfs-3.2/org/jboss/vfs/VirtualFile.java @@ -0,0 +1,29 @@ +package org.jboss.vfs; + +import java.io.File; +import java.io.IOException; + +public class VirtualFile { + VirtualFile(String name, VirtualFile parent) { + } + + public String getName() { + return null; + } + + public String getPathName() { + return null; + } + + String getPathName(boolean url) { + return null; + } + + public File getPhysicalFile() throws IOException { + return null; + } + + public VirtualFile getChild(String path) { + return null; + } +} diff --git a/java/ql/test/stubs/undertow-io-2.2/io/undertow/server/handlers/resource/FileResourceManager.java b/java/ql/test/stubs/undertow-io-2.2/io/undertow/server/handlers/resource/FileResourceManager.java new file mode 100644 index 000000000000..815222f2f9f5 --- /dev/null +++ b/java/ql/test/stubs/undertow-io-2.2/io/undertow/server/handlers/resource/FileResourceManager.java @@ -0,0 +1,31 @@ +package io.undertow.server.handlers.resource; + +import java.io.File; + +public class FileResourceManager { + public FileResourceManager(final File base) { + } + + public FileResourceManager(final File base, long transferMinSize) { + } + + public FileResourceManager(final File base, long transferMinSize, boolean caseSensitive) { + } + + public FileResourceManager(final File base, long transferMinSize, boolean followLinks, final String... safePaths) { + } + + protected FileResourceManager(long transferMinSize, boolean caseSensitive, boolean followLinks, final String... safePaths) { + } + + public FileResourceManager(final File base, long transferMinSize, boolean caseSensitive, boolean followLinks, final String... safePaths) { + } + + public File getBase() { + return null; + } + + public Resource getResource(final String p) { + return null; + } +} diff --git a/java/ql/test/stubs/undertow-io-2.2/io/undertow/server/handlers/resource/Resource.java b/java/ql/test/stubs/undertow-io-2.2/io/undertow/server/handlers/resource/Resource.java new file mode 100644 index 000000000000..579e08107c6e --- /dev/null +++ b/java/ql/test/stubs/undertow-io-2.2/io/undertow/server/handlers/resource/Resource.java @@ -0,0 +1,33 @@ +package io.undertow.server.handlers.resource; + +import java.io.File; +import java.net.URL; +import java.nio.file.Path; +import java.util.Date; +import java.util.List; + +public interface Resource { + String getPath(); + + Date getLastModified(); + + String getLastModifiedString(); + + String getName(); + + boolean isDirectory(); + + List list(); + + Long getContentLength(); + + File getFile(); + + Path getFilePath(); + + File getResourceManagerRoot(); + + Path getResourceManagerRootPath(); + + URL getUrl(); +}