-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[Java] CWE-552: Unsafe url forward #6240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only taken a quick look so do please check in more detail, but I think there are already queries for the Spring aspects of this. getRequestDispatcher(...)
does appear to be new.
} | ||
|
||
/** A Unsafe url forward sink from spring controller method. */ | ||
private class SpringUrlForwardSink extends UnsafeUrlForwardSink { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overlap with CWE-601/SpringUrlRedirect.ql?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No overlap, no url jump will be triggered here, files will be read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @pwntester, do you have any suggestions for this?
) | ||
or | ||
exists(MethodAccess ma | | ||
ma.getMethod().hasName("setViewName") and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overlap with CWE-094/SpringViewManipulation.ql?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CWE-094/SpringViewManipulation
must use the Thymeleaf
template engine.
exists(AddExpr ae | | ||
ae.getRightOperand() = node.asExpr() and | ||
( | ||
not ae.getLeftOperand().(CompileTimeConstantExpr).getStringValue().matches("/WEB-INF/%") | ||
and | ||
not ae.getLeftOperand().(CompileTimeConstantExpr).getStringValue() = "forward:" | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to account for string building patterns. This has been implemented in the past (#4530)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made changes, please review again, thank you!
not exists(MethodAccess ma | | ||
ma.getMethod().getName() in ["getRequestURI", "getRequestURL", "getPathInfo"] and | ||
ma.getMethod() | ||
.getDeclaringType() | ||
.getASupertype*() | ||
.hasQualifiedName("javax.servlet.http", "HttpServletRequest") | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to connect ma
and source
. Probably you want to add source.asExpr() = ma
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some inline comments.
Also, I agree there's some overlap with SpringUrlRedirect
, since that query also looks for forward:
URLs, but I guess it makes sense because that would be both an open redirect and a local file include. So I think there's no need to change it in this PR, but it's something to take into account when we eventually promote all of these (altogether with the copy-pasted code from SpringUrlRedirect
, SpringViewManipulation
and RequestForgery
).
getNumberOfParameters() = 1 and | ||
getParameter(0).getType() instanceof TypeString |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there overloads of this method with different parameters? If not, these two conditions aren't needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
/** | ||
* A concatenate expression using the string `forward:` on the left. | ||
* | ||
* E.g: `"forward:" + url` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid contractions in QLDoc: https://github.com/github/codeql/blob/main/docs/qldoc-style-guide.md#language-requirements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
/** | ||
* A call to `StringBuilder.append` or `StringBuffer.append` method, and the parameter value is `"forward:"`. | ||
* | ||
* E.g: `StringBuilder.append("forward:")` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid contractions in QLDoc: https://github.com/github/codeql/blob/main/docs/qldoc-style-guide.md#language-requirements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
ma.getMethod() | ||
.getDeclaringType() | ||
.getASupertype*() | ||
.hasQualifiedName("javax.servlet.http", "HttpServletRequest") and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use the HttpServletRequest
class from Servlets.qll
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
) | ||
or | ||
exists(ClassInstanceExpr cie | | ||
cie.getConstructedType().hasQualifiedName("org.springframework.web.servlet", "ModelAndView") and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the ModelAndView
class from SpringWeb.qll
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
ma.getMethod().hasName("setViewName") and | ||
ma.getMethod() | ||
.getDeclaringType() | ||
.hasQualifiedName("org.springframework.web.servlet", "ModelAndView") and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the ModelAndView
class from SpringWeb.qll
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
In <code>bad1</code> method and <code>bad2</code> method and <code>bad3</code> method and | ||
<code>bad4</code> method and <code>bad5</code> method and <code>bad6</code> method, shows an HTTP request parameter being used directly in a URL forward |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In <code>bad1</code> method and <code>bad2</code> method and <code>bad3</code> method and | |
<code>bad4</code> method and <code>bad5</code> method and <code>bad6</code> method, shows an HTTP request parameter being used directly in a URL forward | |
The <code>bad</code> methods show an HTTP request parameter being used directly in a URL forward |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also consider should the user manual example have so many cases? Are they all illustrating sufficiently different things, or would one or two do, with the rest kept in the tests but not the documentation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
private Expr getQualifier(Expr e) { result = e.(MethodAccess).getQualifier() } | ||
|
||
/** | ||
* An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This being copy-pasted from RequestForgery.qll
, let's pull it out into a library rather than duplicate
Rewritten to use the shared library; will merge on green |
Constructing a server-side redirect path with user input could allow an attacker to download application binaries
(including application classes or jar files) or view arbitrary files within protected directories.