Coordinated Disclosure Timeline

Summary

A command injection vulnerability was found in the IndieAuth functionality of the Ruby on Rails based Haven blog web application. The affected functionality requires authentication, but an attacker can craft a link that they can pass to a logged in administrator of the blog software. This leads to the immediate execution of the provided commands when the link is accessed by the authenticated administrator.

Project

Haven

Tested Version

9325762

Details

Remote code execution in IndieAuthClient (GHSL-2024-093)

A command injection vulnerability was found in the IndieAuth functionality of the Ruby on Rails based Haven blog web application. An unauthenticated attacker could provide a specially crafted URL to an authenticated administrator of a Haven instance. If such a URL contains the query parameter client_id with a value that starts with the pipe symbol (|) then the following commands are executed as shell commands on the server running Haven. This is due to the used URI.open behaving similar to Ruby’s Kernel.open in addition to being able to open remote URLs.

The entry point for a malicious client_id value is the authorization method on the IndieauthController class:

def authorization
    @auth_request = IndieAuthRequestObj.new(params)
    @client = IndieAuthClient.new(@auth_request.client_id)

In this method a new IndieAuthRequestObj object is created, where checks are made if all required query parameters have been passed in (client_id, redirect_uri, state, code_challenge and code_challenge_method). The client_id of this IndieAuthRequestObj is then passed to initialize of IndieAuthClient, which then calls the dangerous URI.open sink with it:

def initialize(client_id)
    @client_id = client_id
    [..]
    if should_fetch?
      begin
        URI.open(client_id) do |f|

Although the method should_check? calls a method called parse_hostname an attacker can get through this check by creating a client_id with a hostname with scheme after the shell command (e.g. | touch pwned.txt | https://example.org).

This vulnerability was discovered with the help of CodeQL’s Use of Kernel.open, IO.read or similar sinks with user-controlled input query.

Proof of Concept

If an authenticated Haven administrator user visits a URL such as:

https://<haven-host>/indieauth/authorization?response_type=code&client_id=|%20touch%20pwned.txt%20|%20https:%2f%2fexample.org&redirect_uri=any&state=any&code_challenge=12345678&code_challenge_method=S256

The command touch pwned.txt is executed, which leads to the creation of the file pwned.txt. Since the route /indieauth/authorization can be accessed via GET request an attacker could send such an URL to an administrator for a Haven blog (or redirect them to it; assuming the internal or external haven-host is known.)

Impact

This issue may lead to Remote Code Execution (RCE).

Resources

CVE

Credit

This issue was discovered and reported by GHSL team member @p- (Peter Stöckli).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2024-093 in any communication regarding this issue.