diff --git a/README.md b/README.md index 005ac87..5bd8797 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ vulnerable and configurable in its vulnerability. Route | Required parameters | Optional Parameters --- | --- | --- -`/timing/conditional_hashing` | `login` | `delta` +`/timing/conditional_hashing` | `email` | `delta` `/timing/string_comparison` | `password` | `delta` -`/timing/login` | `login`, `password` | `delta` +`/timing/login` | `email`, `password` | `delta` `/timing/basic_auth` | `password` | `delta` `/injections/sql/raw_sql` | `name` | `/injections/sql/raw_where` | `name` | @@ -27,7 +27,7 @@ Edit `.env` to contain appropriate values, then ## Timing Vulnerabilities ### Conditional Hashing -The `login` parameter is the email address to test for inclusion in the +The `email` parameter is the email address to test for inclusion in the "database," and is required. The `delta` URL parameter can be provided to tell the application the timing @@ -48,7 +48,7 @@ comparison (that is, no additional delay is introduced). ### Login -`login` and `password` parameters are required. +`email` and `password` parameters are required. This endpoint simply combines conditional hashing and insecure string comparison for a full vulnerable login experience. A provided `delta` parameter will be diff --git a/app/controllers/injections/template_injections_controller.rb b/app/controllers/injections/template_injections_controller.rb index 9259845..f8adef1 100644 --- a/app/controllers/injections/template_injections_controller.rb +++ b/app/controllers/injections/template_injections_controller.rb @@ -7,7 +7,7 @@ def index end def interpolation - render plain: injection_command.execute + render html: injection_command.execute end private diff --git a/app/controllers/timing_vulnerabilities_controller.rb b/app/controllers/timing_vulnerabilities_controller.rb index 544af0b..ee59df4 100644 --- a/app/controllers/timing_vulnerabilities_controller.rb +++ b/app/controllers/timing_vulnerabilities_controller.rb @@ -1,8 +1,13 @@ class TimingVulnerabilitiesController < ApplicationController def login - user_result = user_finder.execute - comparator_result = string_comparator.execute - determine_access(user_result && comparator_result) + user_result = ConditionalHashing.new(timing_params[:email], + delta: timing_params[:delta] + ).execute + actual_password = Camel.where(email: timing_params[:email]).pluck(:password).first + comparator_result = InsecureStringComparison.new(timing_params[:password], + against: actual_password + ).execute + determine_access(user_result && comparator_result, set: timing_params[:email]) end def conditional_hashing @@ -30,7 +35,7 @@ def index private def user_finder - @user_finder ||= ConditionalHashing.new(timing_params[:login], + @user_finder ||= ConditionalHashing.new(timing_params[:email], delta: timing_params[:delta]) end @@ -40,11 +45,12 @@ def string_comparator end def timing_params - params.permit(:login, :password, :delta) + params.permit(:email, :password, :delta) end - def determine_access(bool) + def determine_access(bool, set: nil) if bool + session[:email] = set if set render plain: "Authorized", status: :ok else render plain: "Unauthorized", status: :unauthorized diff --git a/app/models/camel.rb b/app/models/camel.rb index 91aa43a..84f02ab 100644 --- a/app/models/camel.rb +++ b/app/models/camel.rb @@ -1,2 +1,7 @@ class Camel < ApplicationRecord + validates :name, presence: true + validates :breed, presence: true + validates :email, presence: true + validates_uniqueness_of :email + validates :password, presence: true end diff --git a/app/services/conditional_hashing.rb b/app/services/conditional_hashing.rb index ddf1c31..35943eb 100644 --- a/app/services/conditional_hashing.rb +++ b/app/services/conditional_hashing.rb @@ -8,7 +8,7 @@ def initialize(login, delta: max_delta) # Return value is whether @login is valid def execute - found = valid_logins.include?(login) + found = Camel.where(email: login).present? sleep(delta) if found found end @@ -22,13 +22,8 @@ def hint attr_reader :login, :delta MAX_DELTA = 0.10 - LOGINS = %w(charles@poodles.com camel@sahara.com bactrian@dev.null dromedary@dev.null).freeze def max_delta MAX_DELTA end - - def valid_logins - LOGINS - end end diff --git a/app/services/insecure_string_comparison.rb b/app/services/insecure_string_comparison.rb index 3c8afd5..f29a581 100644 --- a/app/services/insecure_string_comparison.rb +++ b/app/services/insecure_string_comparison.rb @@ -1,9 +1,10 @@ # Performs insecure string comparison, wherein the first non-matching byte # causes an early return. class InsecureStringComparison - def initialize(candidate, delta: max_delta) + def initialize(candidate, delta: max_delta, against: BITSTREAM) @delta = [max_delta, delta.to_f].min @candidate = candidate.to_s.bytes + @bitstream = against.to_s end def execute @@ -39,12 +40,8 @@ def hint MAX_DELTA = 0.05 - def bitstream - BITSTREAM - end - def max_delta MAX_DELTA end - attr_reader :candidate, :delta + attr_reader :candidate, :delta, :bitstream end diff --git a/app/services/template_injection.rb b/app/services/template_injection.rb index 7e2f633..df98248 100644 --- a/app/services/template_injection.rb +++ b/app/services/template_injection.rb @@ -8,13 +8,14 @@ def hint end def execute - erb.result + erb.result.html_safe end private def interpolate(string) <<-EOF.strip_heredoc +
     +--------------------------------------+
     |                Hello, #{string}             |
     +--------------------------------------+
@@ -24,6 +25,7 @@ def interpolate(string)
     `-,,,  ,_      ;'~U'
       _,-' ,'`-__; '--.
     (_/'~~      ''''(;
+    
EOF end diff --git a/config/application.rb b/config/application.rb index 2bfb086..fe9049a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -8,6 +8,10 @@ module Camelflage class Application < Rails::Application - # config.api_only = true + config.action_dispatch.default_headers = { + 'X-Frame-Options' => 'SAMEORIGIN', + 'X-XSS-Protection' => '0', + 'X-Content-Type-Options' => 'nosniff' + } end end diff --git a/config/routes.rb b/config/routes.rb index 98fdf3e..18e916d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Rails.application.routes.draw do + post :login, to: 'timing_vulnerabilities#login' + resource :timing, controller: 'timing_vulnerabilities', only: [] do get :index match :login, via: %i(post get) diff --git a/db/migrate/20170512021209_add_login_fields_to_camels.rb b/db/migrate/20170512021209_add_login_fields_to_camels.rb new file mode 100644 index 0000000..cd9a2fa --- /dev/null +++ b/db/migrate/20170512021209_add_login_fields_to_camels.rb @@ -0,0 +1,7 @@ +class AddLoginFieldsToCamels < ActiveRecord::Migration[5.0] + def change + add_column :camels, :email, :string, unique: true + add_column :camels, :password, :string + add_column :camels, :is_admin, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 44f2a65..4286e11 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,14 +10,20 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20161224052218) do +ActiveRecord::Schema.define(version: 20170512021209) do + + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" create_table "camels", force: :cascade do |t| - t.string "name", null: false - t.string "breed", null: false + t.string "name", null: false + t.string "breed", null: false t.string "notes" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "email" + t.string "password" + t.boolean "is_admin", default: false end end diff --git a/db/seeds.rb b/db/seeds.rb index ec199b7..d0429e9 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,3 +1,24 @@ -Camel.create!(name: "Perl", breed: "dromedary", notes: "Enjoys regex") -Camel.create!(name: "Joe", breed: "dromedary", notes: "Particularly cool") -Camel.create!(name: "Alphons", breed: "bactrian", notes: "Has pretty eyes") +Camel.create!(name: "Perl", + breed: "dromedary", + notes: "Enjoys regex", + email: "perl@perl.org", + password: "3usq7#bJCn4E", + is_admin: true) +Camel.create!(name: "Joe", + breed: "dromedary", + notes: "Particularly cool", + email: "joe@camel.com", + password: "love", + is_admin: false) +Camel.create!(name: "Alphons", + breed: "bactrian", + notes: "Has pretty eyes", + email: "alphons@perl.net", + password: "zKQ4xFZn!7g%", + is_admin: false) +Camel.create!(name: "Charles", + breed: "ACTUALLY A POODLE", + notes: "How did a dog get in the camels table computers are hard", + email: "charles@poodleparade.com", + password: "i<3p0rkC#opz", + is_admin: false) diff --git a/public/index.html b/public/index.html index 3554f03..1063d75 100644 --- a/public/index.html +++ b/public/index.html @@ -12,7 +12,7 @@

Camelflage

/timing/conditional_hashing - login + email delta @@ -22,7 +22,7 @@

Camelflage

/timing/login - login, password + email, password delta @@ -56,7 +56,7 @@

Timing Vulnerabilities

Conditional Hashing

-

The login parameter is the email address to test for inclusion in the +

The email parameter is the email address to test for inclusion in the "database," and is required.

The delta URL parameter can be provided to tell the application the timing @@ -77,7 +77,7 @@

Insecure string comparison

Login

-

login and password parameters are required.

+

email and password parameters are required.

This endpoint simply combines conditional hashing and insecure string comparison for a full vulnerable login experience. A provided delta parameter will be