diff --git a/Gemfile b/Gemfile index 8fe2f6f4..dffb0ef8 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,13 @@ gem 'ronin-web-browser', '~> 0.1', github: 'ronin-rb/ronin-web-browser' gem 'ronin-web-session_cookie', '~> 0.1', github: 'ronin-rb/ronin-web-session_cookie', branch: 'main' +gem 'ronin-db', '~> 0.2', github: 'ronin-rb/ronin-db', + branch: '0.2.0' +gem 'ronin-db-activerecord', '~> 0.2', github: 'ronin-rb/ronin-db-activerecord', + branch: '0.2.0' +gem 'ronin-vulns', '~> 0.2', github: 'ronin-rb/ronin-vulns', + branch: '0.2.0' + group :development do gem 'rake' gem 'rubygems-tasks', '~> 0.1' diff --git a/README.md b/README.md index 2ba15980..fb176280 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Commands: session-cookie spider user-agent + vulns wordlist xml ``` @@ -600,6 +601,7 @@ For more examples, see [ronin-web-browser][ronin-web-browser-examples]. * [ronin-web-user_agents] ~> 0.1 * [ronin-web-session_cookie] ~> 0.1 * [ronin-core] ~> 0.2 +* [ronin-vulns] ~> 0.2 ## Install diff --git a/gemspec.yml b/gemspec.yml index efd4ffd0..6ea3b9b7 100644 --- a/gemspec.yml +++ b/gemspec.yml @@ -38,6 +38,7 @@ generated_files: - man/ronin-web-reverse-proxy.1 - man/ronin-web-session-cookie.1 - man/ronin-web-user-agent.1 + - man/ronin-web-vulns.1 - man/ronin-web-wordlist.1 - man/ronin-web-xml.1 @@ -56,6 +57,7 @@ dependencies: ronin-web-user_agents: ~> 0.1 ronin-web-session_cookie: ~> 0.1 ronin-core: ~> 0.2 + ronin-vulns: ~> 0.2 development_dependencies: bundler: ~> 2.0 diff --git a/lib/ronin/web/cli/commands/vulns.rb b/lib/ronin/web/cli/commands/vulns.rb new file mode 100644 index 00000000..f0d5d598 --- /dev/null +++ b/lib/ronin/web/cli/commands/vulns.rb @@ -0,0 +1,308 @@ +# frozen_string_literal: true +# +# ronin-web - A collection of useful web helper methods and commands. +# +# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com) +# +# ronin-web is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ronin-web is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ronin-web. If not, see . +# + +require 'ronin/web/cli/command' +require 'ronin/web/cli/spider_options' +require 'ronin/core/cli/logging' +require 'ronin/vulns/url_scanner' +require 'ronin/vulns/cli/printing' +require 'ronin/vulns/cli/importable' + +module Ronin + module Web + class CLI + module Commands + # + # ## Usage + # + # ronin-web vulns [options] {--host HOST | --domain DOMAIN | --site URL} + # + # ## Options + # + # --host HOST Spiders the specific HOST + # --domain DOMAIN Spiders the whole domain + # --site URL Spiders the website, starting at the URL + # --open-timeout SECS Sets the connection open timeout + # --read-timeout SECS Sets the read timeout + # --ssl-timeout SECS Sets the SSL connection timeout + # --continue-timeout SECS Sets the continue timeout + # --keep-alive-timeout SECS Sets the connection keep alive timeout + # -P, --proxy PROXY Sets the proxy to use. + # -H, --header NAME: VALUE Sets a default header + # --host-header NAME=VALUE Sets a default header + # -u chrome-linux|chrome-macos|chrome-windows|chrome-iphone|chrome-ipad|chrome-android|firefox-linux|firefox-macos|firefox-windows|firefox-iphone|firefox-ipad|firefox-android|safari-macos|safari-iphone|safari-ipad|edge, + # --user-agent The User-Agent to use + # -U, --user-agent-string STRING The User-Agent string to use + # -R, --referer URL Sets the Referer URL + # --delay SECS Sets the delay in seconds between each request + # -l, --limit COUNT Only spiders up to COUNT pages + # -d, --max-depth DEPTH Only spiders up to max depth + # --enqueue URL Adds the URL to the queue + # --visited URL Marks the URL as previously visited + # --strip-fragments Enables/disables stripping the fragment component of every URL + # --strip-query Enables/disables stripping the query component of every URL + # --visit-host HOST Visit URLs with the matching host name + # --visit-hosts-like /REGEX/ Visit URLs with hostnames that match the REGEX + # --ignore-host HOST Ignore the host name + # --ignore-hosts-like /REGEX/ Ignore the host names matching the REGEX + # --visit-port PORT Visit URLs with the matching port number + # --visit-ports-like /REGEX/ Visit URLs with port numbers that match the REGEX + # --ignore-port PORT Ignore the port number + # --ignore-ports-like /REGEX/ Ignore the port numbers matching the REGEXP + # --visit-link URL Visit the URL + # --visit-links-like /REGEX/ Visit URLs that match the REGEX + # --ignore-link URL Ignore the URL + # --ignore-links-like /REGEX/ Ignore URLs matching the REGEX + # --visit-ext FILE_EXT Visit URLs with the matching file ext + # --visit-exts-like /REGEX/ Visit URLs with file exts that match the REGEX + # --ignore-ext FILE_EXT Ignore the URLs with the file ext + # --ignore-exts-like /REGEX/ Ignore URLs with file exts matching the REGEX + # -r, --robots Specifies whether to honor robots.txt + # -v, --verbose Enables verbose output + # --lfi-os unix|windows Sets the OS to test for + # --lfi-depth COUNT Sets the directory depth to escape up + # --lfi-filter-bypass null_byte|double_escape|base64|rot13|zlib + # Sets the filter bypass strategy to use + # --rfi-filter-bypass double-encode|suffix-escape|null-byte + # Optional filter-bypass strategy to use + # --rfi-script-lang asp|asp.net|coldfusion|jsp|php|perl + # Explicitly specify the scripting language to test for + # --rfi-test-script-url URL Use an alternative test script URL + # --sqli-escape-quote Escapes quotation marks + # --sqli-escape-parens Escapes parenthesis + # --sqli-terminate Terminates the SQL expression with a -- + # --ssti-test-expr {X*Y | X/Z | X+Y | X-Y} + # Optional numeric test to use + # --open-redirect-url URL Optional test URL to try to redirect to + # + # @since 2.0.0 + # + class Vulns < Command + + include Core::CLI::Logging + include SpiderOptions + include Ronin::Vulns::CLI::Printing + include Ronin::Vulns::CLI::Importable + + option :first, desc: 'Stops spidering once the first vulnerability is found' do + @scan_mode = :first + end + + option :all, short: '-A', + desc: 'Spiders every URL and tests every param' do + @scan_mode = :all + end + + option :print_curl, desc: 'Also prints an example curl command for each vulnerability' + + option :print_http, desc: 'Also prints an example HTTP request for each vulnerability' + + option :import, desc: 'Imports discovered vulnerabilities into the database' + + option :lfi_os, value: { + type: [:unix, :windows] + }, + desc: 'Sets the OS to test for' + + option :lfi_depth, value: { + type: Integer, + usage: 'COUNT' + }, + desc: 'Sets the directory depth to escape up' + + option :lfi_filter_bypass, value: { + type: [ + :null_byte, + :double_escape, + :base64, + :rot13, + :zlib + ] + }, + desc: 'Sets the filter bypass strategy to use' + + option :rfi_filter_bypass, value: { + type: { + 'double-encode' => :double_encode, + 'suffix-escape' => :suffix_escape, + 'null-byte' => :null_byte + } + }, + desc: 'Optional filter-bypass strategy to use' + + option :rfi_script_lang, value: { + type: { + 'asp' => :asp, + 'asp.net' => :asp_net, + 'coldfusion' => :cold_fusion, + 'jsp' => :jsp, + 'php' => :php, + 'perl' => :perl + } + }, + desc: 'Explicitly specify the scripting language to test for' + + option :rfi_test_script_url, value: { + type: String, + usage: 'URL' + }, + desc: 'Use an alternative test script URL' + + option :sqli_escape_quote, desc: 'Escapes quotation marks' + + option :sqli_escape_parens, desc: 'Escapes parenthesis' + + option :sqli_terminate, desc: 'Terminates the SQL expression with a --' + + option :ssti_test_expr, value: { + type: %r{\A\d+\s*[\*/\+\-]\s*\d+\z}, + usage: '{X*Y | X/Z | X+Y | X-Y}' + }, + desc: 'Optional numeric test to use' do |expr| + @ssti_test_expr = Ronin::Vulns::SSTI::TestExpression.parse(expr) + end + + option :open_redirect_url, value: { + type: String, + usage: 'URL' + }, + desc: 'Optional test URL to try to redirect to' + + description "Spiders a website and scans every URL for web vulnerabilities" + + man_page 'ronin-web-vulns.1' + + # The scan mode + # + # @return [:first, :all] + attr_reader :scan_mode + + # + # Initializes the `ronin-web vulns` command. + # + # @param [Hash{Symbol => Object}] kwargs + # Additional keyword arguments. + # + def initialize(**kwargs) + super(**kwargs) + + @scan_mode = :all + end + + # + # Runs the `ronin-web vulns` command. + # + def run + db_connect if options[:import] + + vulns = [] + + begin + new_agent do |agent| + case @scan_mode + when :first + agent.every_url do |url| + log_info "Testing #{url}" + + if (vuln = test_url(url)) + process_vuln(vuln) + vulns << vuln + + agent.stop + end + end + when :all + agent.every_url do |url| + log_info "Testing #{url}" + + scan_url(url) do |vuln| + process_vuln(vuln) + vulns << vuln + end + end + end + end + rescue Interrupt + puts + end + + puts unless vulns.empty? + print_vulns(vulns) + end + + # + # Logs and optioanlly imports a new discovered web vulnerability. + # + # @param [Ronin::Vulns::WebVuln] vuln + # The discovered web vulnerability. + # + # @since 2.0.0 + # + def process_vuln(vuln) + log_vuln(vuln) + import_vuln(vuln) if options[:import] + end + + # + # Scans the URL for web vulnerabilities. + # + # @param [URI::HTTP, String] url + # The URL to scan. + # + # @yield [vuln] + # The given block will be yielded each discovered web vulnerability. + # + # @yieldparam [Ronin::Vulns::LFI, + # Ronin::Vulns::RFI, + # Ronin::Vulns::SQLI, + # Ronin::Vulns::SSTI, + # Ronin::Vulns::ReflectedXSS, + # Ronin::Vulns::OpenRedirect] vuln + # A discovered web vulnerability in the URL. + # + def scan_url(url,&block) + Ronin::Vulns::URLScanner.scan(url,&block) + end + + # + # Tests the URL for web vulnerabilities and prints the first + # vulnerability. + # + # @param [URI::HTTP, String] url + # The URL to scan. + # + # @return [Ronin::Vulns::LFI, + # Ronin::Vulns::RFI, + # Ronin::Vulns::SQLI, + # Ronin::Vulns::SSTI, + # Ronin::Vulns::ReflectedXSS, + # Ronin::Vulns::OpenRedirect, nil] + # The first discovered web vulnerability or `nil` if no + # vulnerabilities were discovered. + # + def test_url(url) + Ronin::Vulns::URLScanner.test(url) + end + + end + end + end + end +end diff --git a/man/ronin-web-vulns.1.md b/man/ronin-web-vulns.1.md new file mode 100644 index 00000000..5d510e13 --- /dev/null +++ b/man/ronin-web-vulns.1.md @@ -0,0 +1,177 @@ +# ronin-web-spider 1 "2022-01-01" Ronin Web "User Manuals" + +## SYNOPSIS + +`ronin-web spider` [*options*] {`--host` *HOST* \| `--domain` *DOMAIN* \| `--site` *URL*} + +## DESCRIPTION + +Spiders a website and tests every URL for web vulnerabilities. + +## OPTIONS + +`--host` *HOST* + Spiders the specific *HOST*. + +`--domain` *DOMAIN* + Spiders the whole *DOMAIN*. + +`--site` *URL* + Spiders the website, starting at the *URL*. + +`--open-timeout` *SECS* + Sets the connection open timeout. + +`--read-timeout` *SECS* + Sets the read timeout. + +`--ssl-timeout` *SECS* + Sets the SSL connection timeout. + +`--continue-timeout` *SECS* + Sets the continue timeout. + +`--keep-alive-timeout` *SECS* + Sets the connection keep alive timeout. + +`-P`, `--proxy` *PROXY* + Sets the proxy to use. + +`-H`, `--header` "*NAME*: *VALUE*" + Sets a default header. + +`--host-header` *NAME*=*VALUE* + Sets a default header. + +`-u`, `--user-agent` chrome-linux|chrome-macos|chrome-windows|chrome-iphone|chrome-ipad|chrome-android|firefox-linux|firefox-macos|firefox-windows|firefox-iphone|firefox-ipad|firefox-android|safari-macos|safari-iphone|safari-ipad|edge + The `User-Agent` to use. + +`-U`, `--user-agent-string` *STRING* + The raw `User-Agent` string to use. + +`-R`, `--referer` *URL* + Sets the `Referer` URL. + +`--delay` *SECS* + Sets the delay in seconds between each request. + +`-l`, `--limit` *COUNT* + Only spiders up to *COUNT* pages. + +`-d`, `--max-depth` *DEPTH* + Only spiders up to max depth. + +`--enqueue` *URL* + Adds the URL to the queue. + +`--visited` *URL* + Marks the URL as previously visited. + +`--strip-fragments` + Enables/disables stripping the fragment component of every URL. + +`--strip-query` + Enables/disables stripping the query component of every URL. + +`--visit-host` *HOST* + Visit URLs with the matching host name. + +`--visit-hosts-like` `/`*REGEX*`/` + Visit URLs with hostnames that match the *REGEX*. + +`--ignore-host` *HOST* + Ignore the host name. + +`--ignore-hosts-like` `/`*REGEX*`/` + Ignore the host names matching the *REGEX*. + +`--visit-port` *PORT* + Visit URLs with the matching port number. + +`--visit-ports-like` `/`*REGEX*`/` + Visit URLs with port numbers that match the *REGEX*. + +`--ignore-port` *PORT* + Ignore the port number. + +`--ignore-ports-like` `/`*REGEX*`/` + Ignore the port numbers matching the *REGEXP*. + +`--visit-link` *URL* + Visit the *URL*. + +`--visit-links-like` `/`*REGEX*`/` + Visit URLs that match the *REGEX*. + +`--ignore-link` *URL* + Ignore the *URL*. + +`--ignore-links-like` `/`*REGEX*`/` + Ignore URLs matching the *REGEX*. + +`--visit-ext` *FILE_EXT* + Visit URLs with the matching file ext. + +`--visit-exts-like` `/`*REGEX*`/` + Visit URLs with file exts that match the *REGEX*. + +`--ignore-ext` *FILE_EXT* + Ignore the URLs with the file ext. + +`--ignore-exts-like` `/`*REGEX*`/` + Ignore URLs with file exts matching the REGEX. + +`-r`, `--robots` + Specifies whether to honor `robots.txt`. + +`--lfi-os` `unix`\|`windows` +: Sets the OS to test for. + +`--lfi-depth` *NUM* +: Sets the directory depth to escape up. + +`--lfi-filter-bypass` `null_byte`\|`double_escape`\|`base64`\|`rot13`\|`zlib` +: Sets the filter bypass strategy to use. + +`--rfi-filter-bypass` `double-encode`\|`suffix-escape`\|`null-byte` +: Optional filter-bypass strategy to use. + +`--rfi-script-lang` `asp`\|`asp.net`\|`coldfusion`\|`jsp`\|`php`\|`perl` +: Explicitly specify the scripting language to test for. + +`--rfi-test-script-url` *URL* +: Use an alternative test script URL. + +`--sqli-escape-quote` +: Escapes quotation marks. + +`--sqli-escape-parens` +: Escapes parenthesis. + +`--sqli-terminate` +: Terminates the SQL expression with a `--`. + +`--ssti-test-expr` {*X*\**Y* \| *X*/*Z* \| *X*+*Y* \| *X*-*Y*} +: Optional numeric test to use. + +`--open-redirect-url` *URL* +: Optional test URL to try to redirect to. + +`-h`, `--help` + Print help information. + +## ENVIRONMENT + +*HTTP_PROXY* + Sets the global HTTP proxy. + +*RONIN_HTTP_PROXY* + Sets the HTTP proxy for Ronin. + +## AUTHOR + +Postmodern + +## SEE ALSO + +ronin-web-spider(1) diff --git a/spec/cli/commands/vulns_spec.rb b/spec/cli/commands/vulns_spec.rb new file mode 100644 index 00000000..dfe6e69a --- /dev/null +++ b/spec/cli/commands/vulns_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' +require 'ronin/web/cli/commands/vulns' +require_relative 'man_page_example' + +describe Ronin::Web::CLI::Commands::Vulns do + include_examples "man_page" +end