diff --git a/Dockerfile b/Dockerfile index 1207287a5..c8c02a011 100644 --- a/Dockerfile +++ b/Dockerfile @@ -78,9 +78,20 @@ RUN adduser --home /beef --gecos beef --disabled-password beef \ zlib1g \ bison \ nodejs \ + firefox-esr \ && apt-get -y clean \ && rm -rf /var/lib/apt/lists/* +# Install geckodriver for Selenium tests +# Pin version and verify checksum to mitigate supply chain attacks +ENV GECKODRIVER_VERSION=v0.36.0 +ENV GECKODRIVER_SHA256=0bde38707eb0a686a20c6bd50f4adcc7d60d4f73c60eb83ee9e0db8f65823e04 +RUN wget -q "https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" \ + && echo "${GECKODRIVER_SHA256} geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" | sha256sum -c - \ + && tar -xzf "geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" -C /usr/local/bin \ + && chmod +x /usr/local/bin/geckodriver \ + && rm "geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" + # Use gemset created by the builder above COPY --chown=beef:beef . /beef COPY --from=builder /usr/local/bundle /usr/local/bundle diff --git a/Gemfile b/Gemfile index 6400ad4b1..dcbb6be0e 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'rake', '~> 13.3' gem 'activerecord', '~> 8.1' gem 'otr-activerecord', '~> 2.6.0' gem 'sqlite3', '~> 2.9' -gem 'rubocop', '~> 1.82.1', require: false +gem 'rubocop', '~> 1.84.0', require: false # Geolocation support group :geoip do @@ -64,11 +64,11 @@ group :test do gem 'simplecov', '~> 0.22' gem 'test-unit-full', '~> 0.0.5' gem 'rspec', '~> 3.13' - gem 'rdoc', '~> 7.0' + gem 'rdoc', '~> 7.1' gem 'browserstack-local', '~> 1.4' gem 'irb', '~> 1.16' - gem 'pry-byebug', '~> 3.11' + gem 'pry-byebug', '~> 3.12' gem 'rest-client', '~> 2.1.0' gem 'websocket-client-simple', '~> 0.6.1' @@ -80,7 +80,7 @@ group :test do # Note: selenium-webdriver 3.x is incompatible with Firefox version 48 and prior # gem 'selenium' # Requires old version of selenium which is no longer available gem 'geckodriver-helper', '~> 0.24.0' - gem 'selenium-webdriver', '~> 4.39' + gem 'selenium-webdriver', '~> 4.40' # Note: nokogiri is needed by capybara which may require one of the below commands # sudo apt-get install libxslt-dev libxml2-dev diff --git a/Gemfile.lock b/Gemfile.lock index 4896da9fe..4c9f06417 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -36,7 +36,8 @@ GEM base64 (0.3.0) bigdecimal (4.0.1) browserstack-local (1.4.3) - byebug (12.0.0) + byebug (13.0.0) + reline (>= 0.6.0) capybara (3.40.0) addressable matrix @@ -133,20 +134,21 @@ GEM activerecord (>= 6.0, < 9.0) parallel (1.27.0) parseconfig (1.1.2) - parser (3.3.10.0) + parser (3.3.10.1) ast (~> 2.4.1) racc power_assert (2.0.5) pp (0.6.3) prettyprint prettyprint (0.2.0) - prism (1.7.0) - pry (0.15.2) + prism (1.8.0) + pry (0.16.0) coderay (~> 1.1) method_source (~> 1.0) - pry-byebug (3.11.0) - byebug (~> 12.0) - pry (>= 0.13, < 0.16) + reline (>= 0.6.0) + pry-byebug (3.12.0) + byebug (~> 13.0) + pry (>= 0.13, < 0.17) psych (5.3.1) date stringio @@ -167,7 +169,7 @@ GEM rack (>= 1.3) rainbow (3.1.1) rake (13.3.1) - rdoc (7.0.3) + rdoc (7.1.0) erb psych (>= 4.0.0) tsort @@ -195,7 +197,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.6) - rubocop (1.82.1) + rubocop (1.84.0) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -203,12 +205,12 @@ GEM parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.48.0, < 2.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.48.0) + rubocop-ast (1.49.0) parser (>= 3.3.7.2) - prism (~> 1.4) + prism (~> 1.7) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) rubyzip (3.2.2) @@ -216,7 +218,7 @@ GEM json rest-client securerandom (0.4.1) - selenium-webdriver (4.39.0) + selenium-webdriver (4.40.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -321,18 +323,18 @@ DEPENDENCIES net-smtp otr-activerecord (~> 2.6.0) parseconfig (~> 1.1, >= 1.1.2) - pry-byebug (~> 3.11) + pry-byebug (~> 3.12) qr4r (~> 0.6.1) rack (~> 3.2) rack-protection (~> 4.2.1) rake (~> 13.3) - rdoc (~> 7.0) + rdoc (~> 7.1) rest-client (~> 2.1.0) rspec (~> 3.13) - rubocop (~> 1.82.1) + rubocop (~> 1.84.0) rubyzip (~> 3.2) rushover (~> 0.3.0) - selenium-webdriver (~> 4.39) + selenium-webdriver (~> 4.40) sinatra (~> 4.1) slack-notifier (~> 2.4) sqlite3 (~> 2.9) diff --git a/package-lock.json b/package-lock.json index 69f3aa8db..a367530f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -666,10 +666,11 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.camelcase": { "version": "4.3.0", diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f583686ff..b4a4e7df2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -239,8 +239,7 @@ require 'socket' @host = '127.0.0.1' unless port_available? - print_error "Port #{@port} is already in use. Exiting." - exit + raise "Port #{@port} is already in use. Cannot start BeEF server." end load_beef_extensions_and_modules @@ -327,11 +326,9 @@ require 'socket' end def stop_beef_server(pid) - exit if pid.nil? - # Shutting down server + return if pid.nil? Process.kill("KILL", pid) unless pid.nil? Process.wait(pid) unless pid.nil? # Ensure the process has exited and the port is released - pid = nil end end diff --git a/spec/support/ui_support.rb b/spec/support/ui_support.rb index dc0c7fe7e..129be11c6 100644 --- a/spec/support/ui_support.rb +++ b/spec/support/ui_support.rb @@ -10,29 +10,36 @@ require 'spec/support/constants.rb' def start_beef_and_hook_browser() reset_beef_db pid = start_beef_server_and_wait - beef_session = BeefTest.login - hooked_browser = BeefTest.new_victim - expect(hooked_browser).not_to be_nil - expect(hooked_browser).to be_a(Capybara::Session) - expect(hooked_browser).to have_content('BeEF', wait: PAGE_LOAD_TIMEOUT) + begin + beef_session = BeefTest.login + hooked_browser = BeefTest.new_victim - expect(beef_session).not_to be_nil - expect(beef_session).to be_a(Capybara::Session) - expect(beef_session).to have_content('Hooked Browsers', wait: PAGE_LOAD_TIMEOUT) + expect(hooked_browser).not_to be_nil + expect(hooked_browser).to be_a(Capybara::Session) + expect(hooked_browser).to have_content('BeEF', wait: PAGE_LOAD_TIMEOUT) - navigate_to_hooked_browser(beef_session) + expect(beef_session).not_to be_nil + expect(beef_session).to be_a(Capybara::Session) + expect(beef_session).to have_content('Hooked Browsers', wait: PAGE_LOAD_TIMEOUT) - expect(beef_session).to have_content('Commands', wait: PAGE_LOAD_TIMEOUT) - beef_session.click_on('Commands') + navigate_to_hooked_browser(beef_session) - return pid, beef_session, hooked_browser + expect(beef_session).to have_content('Commands', wait: PAGE_LOAD_TIMEOUT) + beef_session.click_on('Commands') + + return pid, beef_session, hooked_browser + rescue => e + # If setup fails, cleanup the server before re-raising + stop_beef_server(pid) + raise e + end end def stop_beef_and_unhook_browser(pid, beef_session, hooked_browser) stop_beef_server(pid) - beef_session.driver.browser.close - hooked_browser.driver.browser.close + beef_session.driver.browser.close if beef_session + hooked_browser.driver.browser.close if hooked_browser end def navigate_to_hooked_browser(session, hooked_browser_text = nil)