Skip to content

[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

Merged
merged 7 commits into from
Oct 19, 2021
Merged

[Java] CWE-552: Unsafe url forward #6240

merged 7 commits into from
Oct 19, 2021

Conversation

haby0
Copy link
Contributor

@haby0 haby0 commented Jul 8, 2021

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.

@haby0 haby0 requested a review from a team as a code owner July 8, 2021 11:44
@haby0 haby0 changed the title [Java] CWE-348: Unsafe url forward [Java] CWE-552: Unsafe url forward Jul 8, 2021
Copy link
Contributor

@smowton smowton left a 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 {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@haby0 haby0 dismissed a stale review via df93cd0 September 16, 2021 12:14
Comment on lines 30 to 45
exists(AddExpr ae |
ae.getRightOperand() = node.asExpr() and
(
not ae.getLeftOperand().(CompileTimeConstantExpr).getStringValue().matches("/WEB-INF/%")
and
not ae.getLeftOperand().(CompileTimeConstantExpr).getStringValue() = "forward:"
)
)
Copy link
Contributor

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)

Copy link
Contributor Author

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!

Comment on lines 23 to 44
not exists(MethodAccess ma |
ma.getMethod().getName() in ["getRequestURI", "getRequestURL", "getPathInfo"] and
ma.getMethod()
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("javax.servlet.http", "HttpServletRequest")
)
}
Copy link
Contributor

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

@smowton smowton requested a review from atorralba September 24, 2021 17:51
Copy link
Contributor

@atorralba atorralba left a 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).

Comment on lines 201 to 202
getNumberOfParameters() = 1 and
getParameter(0).getType() instanceof TypeString
Copy link
Contributor

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.

Copy link
Contributor Author

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`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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:")`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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
Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@haby0 haby0 requested a review from atorralba September 28, 2021 01:45
Comment on lines 20 to 21
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

Copy link
Contributor

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?

Copy link
Contributor Author

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
Copy link
Contributor

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

@haby0 haby0 requested a review from smowton October 8, 2021 04:13
@smowton
Copy link
Contributor

smowton commented Oct 19, 2021

Rewritten to use the shared library; will merge on green

@smowton smowton merged commit 233a334 into github:main Oct 19, 2021
@haby0 haby0 deleted the java/UnsafeUrlForward branch October 26, 2021 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants