skip to content
Back to GitHub.com
Home Research Advisories CodeQL Wall of Fame Get Involved Events
May 31, 2024

GHSL-2024-029: Denial of Service (DoS) in Zammad - CVE-2024-33667

Peter Stöckli

Coordinated Disclosure Timeline

Summary

A denial of service (DoS) vulnerability was found in the helpdesk software Zammad. An authenticated attacker could have prevented the web application from handling any requests.

Project

Zammad

Tested Version

v6.2.0

Details

Remote DoS via arbitrary method call (GHSL-2024-029)

An authenticated user can perform a remote Denial of Service attack against Zammad. Zammad exposes endpoints to export the calendar of a helpdesk worker in the iCal format:

# @path       [GET] /calendar_subscriptions/:object
# @path       [GET] /calendar_subscriptions/:object/:method
[..]
def object
  calendar_subscriptions = CalendarSubscriptions.new(current_user)
  ical                   = calendar_subscriptions.generic(params[:object], params[:method])

Here the method parameter is defined as part of the URL. This method flows into a method named generic on the class CalendarSubscriptions, which itself calls generic_call passing the method name on:

def generic_call(object_name, method_name = 'all')
  method_name ||= 'all'

  events_data = []
  if @preferences[ object_name ].present?
    sub_class_name = object_name.to_s.capitalize
    object         = "CalendarSubscriptions::#{sub_class_name}".constantize
    instance       = object.new(@user, @preferences[ object_name ], @time_zone)
    method         = instance.method(method_name)
    events_data += method.call
  end
  events_data
end

The method generic_call then uses the method_name to create a method object, which is then called using call. (The object name is prefixed and not freely definable.)

Ruby’s method objects can reference any available method on an object including methods defined on parent classes such as Object and BasicObject. The Kernel module is included by the class Object, so its methods are available in every Ruby object. When call is called on a method object the referenced method is executed.

Most public information about this type of vulnerability mentions the Kernel methods exit and exit! as destructive examples to pass to the send method. However, while this might throw an exception or even stop the container (Which seems to be the case when exit! is sent to Zammad). We found out that the Kernel method sleep might be a better candidate to stop a Rails application from answering requests. Calling sleep without a duration parameter will make the current request thread sleep forever.

So, if a Rails application is started with a maximum of 5 threads (RAILS_MAX_THREADS=5) in combination with 2 Puma workers (WEB_CONCURRENCY=2) it will take 10 (2*5) requests to stop the Rails application from responding to any requests.

This vulnerability was discovered with the help of CodeQL’s Code injection query.

Proof of concept

The following request sets the params[:method] to sleep.

curl 'http://127.0.0.1:8080/ical/tickets/sleep' \
  -H 'User-Agent: Mozilla/5.0' \
  -b $'_zammad_session_[..]=[..]'

Hint: replace the _zammad_session_ cookie with a valid (authenticated) value.

Alternatively, an attacker could direct a Zammad helpdesk worker to a website under their control, which would call this endpoint (e.g. by loading it in an img tag). Since a GET request is enough to trigger this vulnerability the authenticated cookie should be sent automatically by the browser.

Impact

This issue may lead to Denial of Service (DoS). (It might also lead to information disclosure if a method could be called that returns information that can be rendered by the calendar renderer)

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-029 in any communication regarding this issue.