Coordinated Disclosure Timeline
- 2024-04-11: Sent vulnerability report to Naver and created a pull request to enable code scanning with CodeQL.
- 2024-06-04: Bugfix release was on 2024-06-13.
Summary
A retest of GHSL-2023-239/CVE-2024-28212 uncovered that the endpoint /script/api/github/validate
of ngrinder remained susceptible to unsafe YAML deserialization. However, it seemed not to be exploitable in an impactful manner.
Project
ngrinder
Tested Version
Details
Unsafe Deserialization (GHSL-2024-069
)
The endpoint /script/api/github/validate
remains susceptible to unsafe YAML deserialization. This is due to the fact that user-controlled YAML is allowed to flow into a vulnerable-by-default YamlReader#read
sink of YamlBeans.
The user-controlled data is passed down from the unauthenticated validateGithubConfig
endpoint:
@PostMapping("/github/validate")
public void validateGithubConfig(@RequestBody FileEntry fileEntry) {
gitHubFileEntryService.validate(fileEntry);
}
Then passed down to the validate
method inside the GitHubFileEntryService
class.
public boolean validate(FileEntry gitConfigYaml) {
for (GitHubConfig config : getAllGithubConfig(gitConfigYaml)) {
The validate
method ultimately calls the getAllGithubConfig
, which ultimately calls the YamlReader#read
sink of YamlBeans:
private Set<GitHubConfig> getAllGithubConfig(FileEntry gitConfigYaml) {
Set<GitHubConfig> gitHubConfig = new HashSet<>();
try (YamlReader reader = new YamlReader(gitConfigYaml.getContent())) {
Map<String, Object> gitConfigMap = cast(reader.read());
This vulnerability was discovered with the help of CodeQL’s Deserialization of user-controlled data query.
Since YamlBeans allows to instantiate classes by user-controlled classnames and populate the resulting objects with data (using setters or public fields) an attacker aware of a so-called gadget chain might use this vulnerability to execute code. E.g. if ngrinder would use the c3p0 library an attacker could use the WrapperConnectionPoolDataSource
class to execute code by making a request such as:
POST /script/api/github/validate HTTP/1.1
Host: <ngrinder-host>:8080
User-Agent: Mozilla/5.0
Accept: application/json
Content-Type: application/json
Connection: close
Content-Length: xx
{
"content": "!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\nuserOverridesAsString: \n \"HexAsciiSerializedMap:aced0005737[..];\""
}
In this hypothetical sample YamlBeans would instantiate the class WrapperConnectionPoolDataSource
and then call the setter setUserOverridesAsString
on it with the abbreviated HexAsciiSerializedMap:[..]
data. This data itself is serialized using Java Serialization. For more information see WrapperConnectionPoolDataSource
inside of the Marshalsec paper.
Theoretically, there could be one or more gadget classes on the ngrinder’s classpath that could have various impacts up to remote code execution.
Impact
This issue may lead up to remote code execution in case an attacker is able to find appropriate gadgets on ngrinder’s classpath.
Resources
Credit
This issue was discovered and reported by GHSL team member @p- (Peter Stöckli).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2024-069
in any communication regarding this issue.