Add pending code to flip-flop results of specs.
This isn't the cleanest approach, but should be good for now. Obviously, there are two contexts for these specs: one is from the maintainer's standpoint, the other is from the trainee who is using RailsGoat for training. The maintainer wants all of these specs to pass, to ensure the vulnerabilities are still functional as vulnerabilities. The trainee could potentially use these specs (though reading the specs contains spoilers) to track and verify their fixes. I've wired in a pending block around each assertion that checks a method to see what the result of the pending call would be. You can see examples of how this works with conditions here: https://www.relishapp.com/rspec/rspec-core/v/2-14/docs/pending/pending-examples This means these specs will all fail now by default (the trainee context), but will pass, when vulnerable, if the RAILSGOAT_MAINTAINER env var is set. The only flaw at the moment is that in the trainee context, fixing the vulnerabilities will result in the specs going from failing to _pending_, not passing (which makes sense, given how we're using RSpec's pending functionality). Maybe it'd be simpler/better to have a boolean toggle of our own somehow wrap the assertions in blocks to do explicitly what we want (flip-flop the result based on the context).
This commit is contained in:
@@ -6,20 +6,23 @@ feature 'broken_auth' do
|
||||
@normal_user = UserFixture.normal_user
|
||||
end
|
||||
|
||||
scenario 'TMI during login', :js => true do
|
||||
scenario 'TMI during login - username' do
|
||||
visit '/'
|
||||
within('.signup') do
|
||||
fill_in 'email', :with => @normal_user.email + 'not'
|
||||
fill_in 'password', :with => @normal_user.clear_password
|
||||
end
|
||||
click_on 'Login'
|
||||
find('div#flash_notice').text.should == "#{@normal_user.email}not doesn't exist!"
|
||||
pending(:if => verifying_fixed?) { find('div#flash_notice').text.should == "#{@normal_user.email}not doesn't exist!" }
|
||||
end
|
||||
|
||||
scenario 'TMI during login - password' do
|
||||
visit '/'
|
||||
within('.signup') do
|
||||
fill_in 'email', :with => @normal_user.email
|
||||
fill_in 'password', :with => @normal_user.clear_password + 'not'
|
||||
end
|
||||
click_on 'Login'
|
||||
find('div#flash_notice').text.should == 'Incorrect Password!'
|
||||
pending(:if => verifying_fixed?) { find('div#flash_notice').text.should == 'Incorrect Password!' }
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,7 @@ feature 'command injection' do
|
||||
end
|
||||
|
||||
scenario 'injection attack on file upload', :js => true do
|
||||
login(@normal_user)
|
||||
login @normal_user
|
||||
|
||||
legit_file = File.join(Rails.root, 'public', 'data', 'legit.txt')
|
||||
File.open(legit_file, 'w') { |f| f.puts 'totes legit' }
|
||||
@@ -23,6 +23,6 @@ feature 'command injection' do
|
||||
end
|
||||
click_on 'Start Upload'
|
||||
end
|
||||
File.exists?(legit_file).should be_false
|
||||
pending(:if => verifying_fixed?) { File.exists?(legit_file).should be_false }
|
||||
end
|
||||
end
|
||||
@@ -39,6 +39,6 @@ feature 'csrf' do
|
||||
end
|
||||
end
|
||||
|
||||
@normal_user.reload.paid_time_off.schedule.last.event_name.should == 'Bad Guy'
|
||||
pending(:if => verifying_fixed?) { @normal_user.reload.paid_time_off.schedule.last.event_name.should == 'Bad Guy' }
|
||||
end
|
||||
end
|
||||
@@ -13,6 +13,6 @@ feature 'sensitive information disclosure' do
|
||||
login @normal_user
|
||||
|
||||
visit "/users/#{@normal_user.user_id}/work_info"
|
||||
page.source.should include '999-99-9999'
|
||||
pending(:if => verifying_fixed?) { page.source.should include '999-99-9999' }
|
||||
end
|
||||
end
|
||||
@@ -13,9 +13,11 @@ feature 'insecure direct object reference' do
|
||||
download_url = first('.widget-body a')[:href]
|
||||
visit download_url.sub(/name=(.*?)&/, 'name=../../config/database.yml&')
|
||||
|
||||
page.status_code.should == 200
|
||||
page.response_headers['Content-Disposition'].should include('database.yml')
|
||||
page.response_headers['Content-Length'].should == '576'
|
||||
pending(:if => verifying_fixed?) {
|
||||
page.status_code.should == 200
|
||||
page.response_headers['Content-Disposition'].should include('database.yml')
|
||||
page.response_headers['Content-Length'].should == '576'
|
||||
}
|
||||
end
|
||||
|
||||
scenario 'view any user work_info' do
|
||||
@@ -24,6 +26,6 @@ feature 'insecure direct object reference' do
|
||||
@normal_user.user_id.should_not == 2
|
||||
visit '/users/2/work_info'
|
||||
|
||||
first('td').text.should == 'Jack Mannino'
|
||||
pending(:if => verifying_fixed?) { first('td').text.should == 'Jack Mannino' }
|
||||
end
|
||||
end
|
||||
@@ -6,7 +6,7 @@ feature 'sql injection' do
|
||||
@normal_user = UserFixture.normal_user
|
||||
end
|
||||
|
||||
scenario 'mass assignment attack on account_settings' do
|
||||
scenario 'mass assignment attack update account_settings' do
|
||||
@normal_user.admin.should be_false
|
||||
|
||||
login(@normal_user)
|
||||
@@ -17,6 +17,21 @@ feature 'sql injection' do
|
||||
:password_confirmation => @normal_user.clear_password}}
|
||||
page.driver.put "/users/#{@normal_user.user_id}.json", params
|
||||
|
||||
@normal_user.reload.admin.should be_true
|
||||
pending(:if => verifying_fixed?) { @normal_user.reload.admin.should be_true }
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'mass assignment attack create new account' do
|
||||
params = {:user => {:admin => 't',
|
||||
:email => 'hackety@h4x0rs.c0m',
|
||||
:first_name => 'hackety',
|
||||
:last_name => 'hax',
|
||||
:password => 'foobarewe',
|
||||
:password_confirmation => 'foobarewe'}}
|
||||
page.driver.post '/users', params
|
||||
|
||||
pending(:if => verifying_fixed?) {
|
||||
User.last.email.should == 'hackety@h4x0rs.c0m'
|
||||
User.last.admin.should be_true
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,8 +23,10 @@ feature 'sql injection' do
|
||||
end
|
||||
click_on 'Submit'
|
||||
|
||||
@admin_user = User.where("admin='t'").first
|
||||
@admin_user.email.should == 'joe.admin@schmoe.com'
|
||||
@admin_user.admin.should == true
|
||||
pending(:if => verifying_fixed?) {
|
||||
@admin_user = User.where("admin='t'").first
|
||||
@admin_user.email.should == 'joe.admin@schmoe.com'
|
||||
@admin_user.admin.should == true
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -14,6 +14,6 @@ feature 'unvalidated redirect' do
|
||||
end
|
||||
click_on 'Login'
|
||||
|
||||
current_url.should == 'http://example.com/do/evil/things'
|
||||
pending(:if => verifying_fixed?) { current_url.should == 'http://example.com/do/evil/things' }
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,6 @@ feature 'url access' do
|
||||
login @normal_user
|
||||
|
||||
visit '/admin/1/dashboard'
|
||||
current_path.should == '/admin/1/dashboard'
|
||||
pending(:if => verifying_fixed?) { current_path.should == '/admin/1/dashboard' }
|
||||
end
|
||||
end
|
||||
@@ -21,7 +21,7 @@ feature 'xss' do
|
||||
|
||||
visit '/'
|
||||
|
||||
find('form.button_to input.btn.btn-primary').value.should == 'RailsGoat h4x0r3d'
|
||||
pending(:if => verifying_fixed?) { find('form.button_to input.btn.btn-primary').value.should == 'RailsGoat h4x0r3d' }
|
||||
|
||||
# might be nice to demonstrate posting cookie contents or somesuch, but
|
||||
# this at least shows the vulnerability still exists.
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
# By default this will return true, and thus all of the Capybara specs will
|
||||
# fail until a developer using the site for training has patched up all of
|
||||
# the vulnerabilities.
|
||||
#
|
||||
# However, RailsGoat maintainers need the Capybara features to pass to indicate
|
||||
# changes to the site have not inadvertently removed or fixed any vulnerabilities
|
||||
# since the whole point is to provide a site for a developer to fix.
|
||||
def verifying_fixed?
|
||||
!ENV['RAILSGOAT_MAINTAINER']
|
||||
end
|
||||
|
||||
def login(user)
|
||||
visit '/'
|
||||
within('.signup') do
|
||||
|
||||
Reference in New Issue
Block a user