Initial commit (history cleared)
CI / test (3.4.1) (push) Has been cancelled

This commit is contained in:
2026-04-29 11:21:39 +01:00
commit 298610b5f6
277 changed files with 30877 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
# frozen_string_literal: true
require "spec_helper"
feature "broken_auth" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "one\nTutorial: https://github.com/OWASP/railsgoat/wiki/A2-Credential-Enumeration" do
wrong_email = normal_user.email + "not"
visit "/"
fill_in "email", with: wrong_email
fill_in "password", with: normal_user.clear_password
find("input[type='submit'][value='Login']").click
expect(find("div#flash_notice").text).not_to include(wrong_email)
end
scenario "two\nTutorial: https://github.com/OWASP/railsgoat/wiki/A2-Credential-Enumeration" do
visit "/"
fill_in "email", with: normal_user.email
fill_in "password", with: normal_user.clear_password + "not"
find("input[type='submit'][value='Login']").click
expect(find("div#flash_notice").text).not_to include("Incorrect Password!")
end
end
@@ -0,0 +1,32 @@
# frozen_string_literal: true
require "spec_helper"
require "tmpdir"
feature "command injection" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/A1-Command-Injection", js: true do
login(normal_user)
legit_file = File.join(Rails.root, "public", "data", "legit.txt")
File.open(legit_file, "w") { |f| f.puts "totes legit" }
visit "/users/#{normal_user.id}/benefit_forms"
Dir.mktmpdir do |dir|
hackety_file = File.join(dir, "test; cd public && cd data && rm -f * ;")
File.open(hackety_file, "w") { |f| f.print "mwahaha" }
within(".new_benefits") do
attach_file "benefits_upload", hackety_file
find(:xpath, "//input[@id='benefits_backup']", visible: false).set "true"
end
click_on "Start Upload"
end
expect(File.exist?(legit_file)).to be_truthy
end
end
+47
View File
@@ -0,0 +1,47 @@
# frozen_string_literal: true
require "spec_helper"
require "tmpdir"
feature "csrf" do
let(:normal_user) { UserFixture.normal_user }
before(:each) do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/R4-A8-CSRF", js: true do
visit "/"
# TODO: is there a way to get this without visiting root first?
base_url = current_url
login(normal_user)
Dir.mktmpdir do |dir|
hackety_file = File.join(dir, "form.on.bad.guy.site.html")
post_url = "#{base_url}schedule.json"
File.open(hackety_file, "w") do |f|
f.print <<-HTML
<html>
<body>
<form id='submit_me' action="#{post_url}" method="POST">
<input type="hidden" name="schedule&#91;event&#95;name&#93;" value="Bad&#32;Guy" />
<input type="hidden" name="schedule&#91;event&#95;type&#93;" value="pto" />
<input type="hidden" name="schedule&#91;event&#95;desc&#93;" value="Fun&#32;Fun" />
<input type="hidden" name="date&#95;range1" value="06&#47;08&#47;2013&#32;&#45;&#32;06&#47;09&#47;2013" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
HTML
end
page.driver.visit "file://#{hackety_file}"
within("#submit_me") do
click_on "Submit request"
end
end
expect(normal_user.reload.paid_time_off.schedule.last.event_name).not_to eq("Bad Guy")
end
end
+34
View File
@@ -0,0 +1,34 @@
# frozen_string_literal: true
require "spec_helper"
feature "insecure direct object reference" do
let(:normal_user) { UserFixture.normal_user }
let(:another_user) { User.find_by(id: 2) }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack one" do
login(normal_user)
visit "/users/#{normal_user.id}/benefit_forms"
download_url = first(".widget-body a")[:href]
visit download_url.sub(/name=(.*?)&/, "name=config/database.yml&")
expect(page.status_code).not_to eq(200)
expect(page.response_headers["Content-Disposition"].to_a).not_to include("database.yml")
end
scenario "attack two\nTutorial: https://github.com/OWASP/railsgoat/wiki/A4-Insecure-Direct-Object-Reference" do
login(normal_user)
expect(normal_user.id).not_to eq(another_user.id)
visit "/users/#{another_user.id}/work_info"
expect(first("td").text).not_to include(another_user.full_name)
expect(first("td").text).to include(normal_user.full_name)
end
end
@@ -0,0 +1,38 @@
# frozen_string_literal: true
require "spec_helper"
feature "mass assignment" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack one" do
expect(normal_user.admin).to be_falsey
login(normal_user)
params = { user: { admin: "t",
id: normal_user.id,
password: normal_user.clear_password,
password_confirmation: normal_user.clear_password }}
page.driver.put "/users/#{normal_user.id}.json", params
expect(normal_user.reload.admin).to be_falsy
end
scenario "attack two, Tutorial: https://github.com/OWASP/railsgoat/wiki/R4-Extras-Mass-Assignment-Admin-Role" 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
expect(User.find_by(email: "hackety@h4x0rs.c0m").admin).to be_falsy
end
end
@@ -0,0 +1,26 @@
# frozen_string_literal: true
require "spec_helper"
feature "password complexity" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "one\nTutorial: https://github.com/OWASP/railsgoat/wiki/A2-Lack-of-Password-Complexity" do
new_user_email = normal_user.email + "two"
visit "/signup"
fill_in "email", with: new_user_email
fill_in "first_name", with: normal_user.first_name
fill_in "last_name", with: normal_user.last_name + "not"
fill_in "password", with: "password"
fill_in "password_confirmation", with: "password"
click_on "Create Account"
expect(User.find_by(email: new_user_email)).to be_nil
expect(current_path).to eq("/signup")
end
end
@@ -0,0 +1,26 @@
# frozen_string_literal: true
require "spec_helper"
feature "improper password hashing" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
end
scenario "with just md5\nTutorial: https://github.com/OWASP/railsgoat/wiki/A6-Sensitive-Data-Exposure-Insecure-Password-Storage" do
new_pass = "testPassw0rd!"
normal_user.password = new_pass
normal_user.password_confirmation = new_pass
normal_user.save!
if verifying_fixed?
# Training mode: expect BCrypt (not MD5) - test should fail because vulnerability exists
expect(normal_user.password).not_to eq(Digest::MD5.hexdigest(new_pass))
else
# Maintainer mode: expect MD5 to verify vulnerability still exists - test should pass
expect(normal_user.password).to eq(Digest::MD5.hexdigest(new_pass))
end
end
end
@@ -0,0 +1,24 @@
# frozen_string_literal: true
require "spec_helper"
feature "sensitive data exposure" do
let(:normal_user) { UserFixture.normal_user }
let(:user_ssn) { "999-99-9999" }
before do
UserFixture.reset_all_users
normal_user.work_info.update(:SSN, user_ssn)
skip unless verifying_fixed?
end
# this won't work with javascript_driver, as it'll apply the javascript
# function to mask this value and the source will be overwritten.
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/A6-Sensitive-Data-Exposure-Cleartext-Storage-SSNs" do
login(normal_user)
visit "/users/#{normal_user.id}/work_info"
expect(page.source).not_to include(user_ssn)
end
end
@@ -0,0 +1,32 @@
# frozen_string_literal: true
require "spec_helper"
feature "sql injection" do
let(:normal_user) { UserFixture.normal_user }
let(:admin_user) { User.where(admin: true).first }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/R5-A1-SQL-Injection-Concatentation" do
expect(admin_user.admin).to be_truthy
login(normal_user)
visit "/users/#{normal_user.id}/account_settings"
within("#account_edit") do
fill_in "Email", with: "joe.admin@schmoe.com"
fill_in "user_password", with: "hacketyhack"
fill_in "user_password_confirmation", with: "hacketyhack"
# this is a hidden field, so cannot use fill_in to access it.
find(:xpath, "//input[@id='user_id']", visible: false).set "8' OR 1 == 1) --"
end
click_on "Submit"
admin_user = User.where(admin: true).first
expect(admin_user.email).not_to eq("joe.admin@schmoe.com")
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
require "spec_helper"
feature "unvalidated redirect" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/A10-Unvalidated-Redirects-and-Forwards-(redirect_to)", js: true do
visit "/?url=http://example.com/do/evil/things"
fill_in "email", with: normal_user.email
fill_in "password", with: normal_user.clear_password
find("input[type='submit'][value='Login']").click
expect(current_url).to start_with("http://127.0.0.1")
expect(current_path).to eq("/dashboard/home")
end
end
+20
View File
@@ -0,0 +1,20 @@
# frozen_string_literal: true
require "spec_helper"
feature "url access" do
let(:normal_user) { UserFixture.normal_user }
before do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/A7-Missing-Function-Level-Access-Control--(Admin-Controller)", js: true do
login(normal_user)
visit "/admin/1/dashboard"
expect(current_path).to eq("/dashboard/home")
end
end
+36
View File
@@ -0,0 +1,36 @@
# frozen_string_literal: true
require "spec_helper"
feature "xss" do
let(:normal_user) { UserFixture.normal_user }
before(:each) do
UserFixture.reset_all_users
skip unless verifying_fixed?
end
scenario "attack\nTutorial: https://github.com/OWASP/railsgoat/wiki/A3-Cross-Site-Scripting", js: true do
login(normal_user)
visit "/users/#{normal_user.id}/account_settings"
within("#account_edit") do
fill_in "First name", with: "<script>$(function() { $('div input.btn').val('RailsGoat h4x0r3d') } )</script>"
# password gets screwed up if you don't re-submit - need to fix
fill_in "user_password", with: normal_user.clear_password
fill_in "user_password_confirmation", with: normal_user.clear_password
end
click_on "Submit"
sleep(1)
visit "/users/#{normal_user.id}/account_settings"
expect(find("#submit_button").value).not_to include("RailsGoat h4x0r3d")
# might be nice to demonstrate posting cookie contents or somesuch, but
# this at least shows the vulnerability still exists.
end
end