Module: Aikido::Zen::AttackWave::Helpers
- Defined in:
- lib/aikido/zen/attack_wave/helpers.rb
Constant Summary collapse
- SUSPICIOUS_METHODS =
[ "BADMETHOD", "BADHTTPMETHOD", "BADDATA", "BADMTHD", "BDMTHD" ].map(&:downcase).freeze
- SUSPICIOUS_DIRECTORY_NAMES =
[ ".", "..", ".anydesk", ".aptitude", ".aws", ".azure", ".cache", ".circleci", ".config", ".dbus", ".docker", ".drush", ".gem", ".git", ".github", ".gnupg", ".gsutil", ".hg", ".idea", ".java", ".kube", ".lftp", ".minikube", ".npm", ".nvm", ".pki", ".snap", ".ssh", ".subversion", ".svn", ".tconn", ".thunderbird", ".tor", ".vagrant.d", ".vidalia", ".vim", ".vmware", ".vscode", "apache", "apache2", "grub", "System32", "tmp", "xampp", "cgi-bin", "%systemroot%" ].map(&:downcase).freeze
- SUSPICIOUS_FILE_NAMES =
[ ".addressbook", ".atom", ".bashrc", ".boto", ".config", ".config.json", ".config.xml", ".config.yaml", ".config.yml", ".envrc", ".eslintignore", ".fbcindex", ".forward", ".gitattributes", ".gitconfig", ".gitignore", ".gitkeep", ".gitlab-ci.yaml", ".gitlab-ci.yml", ".gitmodules", ".google_authenticator", ".hgignore", ".htaccess", ".htpasswd", ".htdigest", ".ksh_history", ".lesshst", ".lhistory", ".lighttpdpassword", ".lldb-history", ".lynx_cookies", ".my.cnf", ".mysql_history", ".nano_history", ".netrc", ".node_repl_history", ".npmrc", ".nsconfig", ".nsr", ".password-store", ".pearrc", ".pgpass", ".php_history", ".pinerc", ".proclog", ".procmailrc", ".profile", ".psql_history", ".python_history", ".rediscli_history", ".rhosts", ".selected_editor", ".sh_history", ".sqlite_history", ".svnignore", ".tcshrc", ".tmux.conf", ".travis.yaml", ".travis.yml", ".viminfo", ".vimrc", ".www_acl", ".wwwacl", ".xauthority", ".yarnrc", ".zhistory", ".zsh_history", ".zshenv", ".zshrc", "Dockerfile", "aws-key.yaml", "aws-key.yml", "aws.yaml", "aws.yml", "docker-compose.yaml", "docker-compose.yml", "npm-shrinkwrap.json", "package-lock.json", "package.json", "phpinfo.php", "wp-config.php", "wp-config.php3", "wp-config.php4", "wp-config.php5", "wp-config.phtml", "composer.json", "composer.lock", "composer.phar", "yarn.lock", ".env.local", ".env.development", ".env.test", ".env.production", ".env.prod", ".env.dev", ".env.example", "php.ini", "wp-settings.php", "config.asp", "config_dev.asp", "config-dev.asp", "config.dev.asp", "config_prod.asp", "config-prod.asp", "config.prod.asp", "config.sample.asp", "config-sample.asp", "config_sample.asp", "config_test.asp", "config-test.asp", "config.test.asp", "config.ini", "config_dev.ini", "config-dev.ini", "config.dev.ini", "config_prod.ini", "config-prod.ini", "config.prod.ini", "config.sample.ini", "config-sample.ini", "config_sample.ini", "config_test.ini", "config-test.ini", "config.test.ini", "config.json", "config_dev.json", "config-dev.json", "config.dev.json", "config_prod.json", "config-prod.json", "config.prod.json", "config.sample.json", "config-sample.json", "config_sample.json", "config_test.json", "config-test.json", "config.test.json", "config.php", "config_dev.php", "config-dev.php", "config.dev.php", "config_prod.php", "config-prod.php", "config.prod.php", "config.sample.php", "config-sample.php", "config_sample.php", "config_test.php", "config-test.php", "config.test.php", "config.pl", "config_dev.pl", "config-dev.pl", "config.dev.pl", "config_prod.pl", "config-prod.pl", "config.prod.pl", "config.sample.pl", "config-sample.pl", "config_sample.pl", "config_test.pl", "config-test.pl", "config.test.pl", "config.py", "config_dev.py", "config-dev.py", "config.dev.py", "config_prod.py", "config-prod.py", "config.prod.py", "config.sample.py", "config-sample.py", "config_sample.py", "config_test.py", "config-test.py", "config.test.py", "config.rb", "config_dev.rb", "config-dev.rb", "config.dev.rb", "config_prod.rb", "config-prod.rb", "config.prod.rb", "config.sample.rb", "config-sample.rb", "config_sample.rb", "config_test.rb", "config-test.rb", "config.test.rb", "config.toml", "config_dev.toml", "config-dev.toml", "config.dev.toml", "config_prod.toml", "config-prod.toml", "config.prod.toml", "config.sample.toml", "config-sample.toml", "config_sample.toml", "config_test.toml", "config-test.toml", "config.test.toml", "config.txt", "config_dev.txt", "config-dev.txt", "config.dev.txt", "config_prod.txt", "config-prod.txt", "config.prod.txt", "config.sample.txt", "config-sample.txt", "config_sample.txt", "config_test.txt", "config-test.txt", "config.test.txt", "config.xml", "config_dev.xml", "config-dev.xml", "config.dev.xml", "config_prod.xml", "config-prod.xml", "config.prod.xml", "config.sample.xml", "config-sample.xml", "config_sample.xml", "config_test.xml", "config-test.xml", "config.test.xml", "config.yaml", "config_dev.yaml", "config-dev.yaml", "config.dev.yaml", "config_prod.yaml", "config-prod.yaml", "config.prod.yaml", "config.sample.yaml", "config-sample.yaml", "config_sample.yaml", "config_test.yaml", "config-test.yaml", "config.test.yaml", "config.yml", "config_dev.yml", "config-dev.yml", "config.dev.yml", "config_prod.yml", "config-prod.yml", "config.prod.yml", "config.sample.yml", "config-sample.yml", "config_sample.yml", "config_test.yml", "config-test.yml", "config.test.yml", "boot.ini", "gruntfile.js", "localsettings.php", "my.ini", "npm-debug.log", "parameters.yml", "parameters.yaml", "services.yml", "services.yaml", "web.config", "webpack.config.js", "config.old", "config.inc.php", "error.log", "access.log", ".DS_Store", "passwd", "win.ini", "cmd.exe", "my.cnf", ".bash_history", "docker-compose-dev.yml", "docker-compose.override.yml", "docker-compose.dev.yml", "Cargo.lock", "secrets.yml", "secrets.yaml", "docker-compose.staging.yml", "docker-compose.production.yml", "yaws-key.pem", "mysql_config.ini", "firewall.log", "log4j.properties", "serviceAccountCredentials.json", "haproxy.cfg", "service-account-credentials.json", "vpn.log", "system.log", "webuser-auth.xml", "fastcgi.conf", "smb.conf", "iis.log", "pom.xml", "openapi.json", "vim_settings.xml", "winscp.ini", "ws_ftp.ini" ].map(&:downcase).freeze
- SUSPICIOUS_FILE_EXTENSIONS =
[ "env", "bak", "sql", "sqlite", "sqlite3", "db", "old", "save", "orig", "sqlitedb", "sqlite3db" ].map(&:downcase).freeze
- FOREIGN_EXTENSIONS =
Extensions that a Ruby app would not natively serve. Requests to these paths are only treated as scan hits when the response is 404 — a 200 may indicate the app is proxying to a PHP/Java backend.
Set.new(%w[php php3 php4 php5 phtml java jsp jspx]).freeze
- SUSPICIOUS_SQL_KEYWORDS =
[ "SELECT (CASE WHEN", "SELECT COUNT(", "SLEEP(", "WAITFOR DELAY", "SELECT LIKE(CHAR(", "INFORMATION_SCHEMA.COLUMNS", "INFORMATION_SCHEMA.TABLES", "MD5(", "DBMS_PIPE.RECEIVE_MESSAGE", "SYSIBM.SYSTABLES", "RANDOMBLOB(", "SELECT * FROM", "1'='1", "PG_SLEEP(", "UNION ALL SELECT", "../" ].map(&:downcase).freeze
Class Method Summary collapse
- .include_suspicious_payload?(context) ⇒ Boolean
-
.original_fullpath(request) ⇒ String
Rails rewrites PATH_INFO to /status before invoking an exceptions_app.
-
.original_path(request) ⇒ String
Rails rewrites PATH_INFO to /status before invoking an exceptions_app.
-
.sample_for(context) ⇒ Aikido::Zen::AttackWave::Sample
Builds the sample for a request that has been classified as suspicious.
- .suspicious_method?(method) ⇒ Boolean
- .suspicious_path?(path, status_code) ⇒ Boolean
- .suspicious_request?(context, status_code) ⇒ Boolean
- .web_scanner?(context, status_code) ⇒ Boolean
Class Method Details
.include_suspicious_payload?(context) ⇒ Boolean
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 77 def self.include_suspicious_payload?(context) context.payloads.each do |payload| next unless payload.source == :query value = payload.value.downcase length = value.length next if length < 5 || length > 1_000 return true if SUSPICIOUS_SQL_KEYWORDS.any? do |keyword| value.include?(keyword) end end false end |
.original_fullpath(request) ⇒ String
Rails rewrites PATH_INFO to /status before invoking an exceptions_app. Returns the path that Rails rewrote, including the same query string.
44 45 46 47 48 49 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 44 def self.original_fullpath(request) path = original_path(request) query = request.query_string query.empty? ? path : "#{path}?#{query}" end |
.original_path(request) ⇒ String
Rails rewrites PATH_INFO to /status before invoking an exceptions_app. Returns the path that Rails rewrote.
36 37 38 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 36 def self.original_path(request) request.env["action_dispatch.original_path"] || request.path_info end |
.sample_for(context) ⇒ Aikido::Zen::AttackWave::Sample
Builds the sample for a request that has been classified as suspicious.
20 21 22 23 24 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 20 def self.sample_for(context) request = context.request Sample.new(verb: request.request_method, path: original_fullpath(request)) end |
.suspicious_method?(method) ⇒ Boolean
51 52 53 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 51 def self.suspicious_method?(method) SUSPICIOUS_METHODS.include?(method.downcase) end |
.suspicious_path?(path, status_code) ⇒ Boolean
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 55 def self.suspicious_path?(path, status_code) path_parts = path.downcase.split("/") file_name = path_parts.pop if path_parts.length > 0 if file_name return true if SUSPICIOUS_FILE_NAMES.include?(file_name) file_name_parts = file_name.split(".") file_extension = file_name_parts.pop if file_name_parts.length > 1 return true if SUSPICIOUS_FILE_EXTENSIONS.include?(file_extension) return true if FOREIGN_EXTENSIONS.include?(file_extension) && status_code == 404 end path_parts.any? do |directory_name| SUSPICIOUS_DIRECTORY_NAMES.include?(directory_name) end end |
.suspicious_request?(context, status_code) ⇒ Boolean
26 27 28 29 30 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 26 def self.suspicious_request?(context, status_code) request = context.request suspicious_method?(request.request_method) || suspicious_path?(original_path(request), status_code) end |
.web_scanner?(context, status_code) ⇒ Boolean
8 9 10 11 12 13 14 |
# File 'lib/aikido/zen/attack_wave/helpers.rb', line 8 def self.web_scanner?(context, status_code) return true if suspicious_request?(context, status_code) return true if include_suspicious_payload?(context) false end |