# frozen_string_literal: true
#
# ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
#
# Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-db-activerecord is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-db-activerecord 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-db-activerecord. If not, see .
#
require 'ronin/db/model'
require 'active_record'
module Ronin
module DB
#
# Represents discovered web vulnerabilities.
#
class WebVuln < ActiveRecord::Base
include Model
# NOTE: disable STI so we can use the type column as an enum.
self.inheritance_column = nil
# @!attribute [rw] id
# The primary key of the URL.
#
# @return [Integer]
attribute :id, :integer
# @!attribute [rw] scheme
# The scheme of the URL.
#
# @return [URL]
belongs_to :url, required: true,
class_name: 'URL'
# @!attribute [rw] type
# The type of vuln.
#
# @return ["lfi", "rfi", "sqli", "ssti", "open_redirect", "reflected_xss", "command_injection"]
enum type: {
lfi: 'lfi',
rfi: 'rfi',
sqli: 'sqli',
ssti: 'ssti',
open_redirect: 'open_redirect',
reflected_xss: 'reflected_xss',
command_injection: 'command_injection'
}
validates :type, presence: true
# @!attribute [rw] query_param
# The query param of the URL.
#
# @return [String, nil]
attribute :query_param, :string
# @!attribute [rw] header_name
# The header name string part of the URL.
#
# @return [String, nil]
attribute :header_name, :string
# @!attribute [rw] cookie_param
# The cookie param of the URL.
#
# @return [String, nil]
attribute :cookie_param, :string
# @!attribute [rw] form_param
# The form param of the URL.
#
# @return [String, nil]
attribute :form_param, :string
validate :param_validation
# @!attribute [rw] request_method
# The request method for the URL.
#
# @return ["copy", "delete", "get", "head", "lock", "mkcol", "move", "options", "patch", "post", "propfind", "proppatch", "put", "trace", "unlock"]
enum request_method: {
copy: 'COPY',
delete: 'DELETE',
get: 'GET',
head: 'HEAD',
lock: 'LOCK',
mkcol: 'MKCOL',
move: 'MOVE',
options: 'OPTIONS',
patch: 'PATCH',
post: 'POST',
propfind: 'PROPFIND',
proppatch: 'PROPPATCH',
put: 'PUT',
trace: 'TRACE',
unlock: 'UNLOCK'
}, _suffix: :request
# @!attribute [rw] lfi_os
# The LFI os.
#
# @return [:unix, :windows, nil]
enum lfi_os: {
unix: 'unix',
windows: 'windows'
}, _prefix: true
# @!attribute [rw] lfi_depth
# The LFI depth.
#
# @return [Integer, nil]
attribute :lfi_depth, :integer
# @!attribute [rw] lfi_filter_bypass
# The LFI filter bypass.
#
# @return [:null_byte, :base64, :rot13, :zlib, nil]
enum lfi_filter_bypass: {
null_byte: 'null_byte',
base64: 'base64',
rot13: 'rot13',
zlib: 'zlib'
}, _prefix: true
# @!attribute [rw] rfi_script_lang
# The RFI script lang.
#
# @return [:asp, :asp_net, :cold_fusion, :jsp, :php, :perl, nil]
enum rfi_script_lang: {
asp: 'asp',
asp_net: 'asp_net',
cold_fusion: 'cold_fusion',
jsp: 'jsp',
php: 'php',
perl: 'perl'
}, _prefix: true
# @!attribute [rw] rfi_filter_bypass
# The RFI filter bypass.
#
# @return [:null_byte, :double_encode, nil]
enum rfi_filter_bypass: {
null_byte: 'null_byte',
double_encode: 'double_encode'
}, _prefix: true
# @!attribute [rw] ssti_escape_type
# The SSTI escape type.
#
# @return [:double_curly_braces, :dollar_curly_braces, :dollar_double_curly_braces, :pound_curly_braces, :angle_brackets_percent, :custom, nil]
enum ssti_escape_type: {
double_curly_braces: 'double_curly_braces',
dollar_curly_braces: 'dollar_curly_braces',
dollar_double_curly_braces: 'dollar_double_curly_braces',
pound_curly_braces: 'pound_curly_braces',
angle_brackets_percent: 'angle_brackets_percent',
custom: 'custom'
}, _prefix: true
# @!attribute [rw] sqli_escape_quote
# The SQLi escape quote.
#
# @return [Boolean, nil]
attribute :sqli_escape_quote, :boolean
# @!attribute [rw] sqli_escape_parens
# The SQLi escape parens.
#
# @return [Boolean, nil]
attribute :sqli_escape_parens, :boolean
# @!attribute [rw] sqli_terminate
# The SQLi terminate.
#
# @return [Boolean, nil]
attribute :sqli_terminate, :boolean
# @!attribute [rw] command_injection_escape_quote
# The Command Injection escape quote character.
#
# @return [String, nil]
attribute :command_injection_escape_quote, :string
# @!attribute [rw] command_injection_escape_operator
# The Command Injection escape operator character.
#
# @return [String, nil]
attribute :command_injection_escape_operator, :string
# @!attribute [rw] command_injection_terminator
# The Command Injection terminator character.
#
# @return [String, nil]
attribute :command_injection_terminator, :string
# @!attribute [r] created_at
# Defines the created_at timestamp
#
# @return [Time]
attribute :created_at, :datetime
#
# Queries all web vulnerabilities belonging to the given host name.
#
# @param [String] host_name
# The host name to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.for_host(host_name)
joins(url: [:host_name]).where(
url: {
ronin_host_names: {name: host_name}
}
)
end
#
# Queries all web vulnerabilities belonging to the given domain name.
#
# @param [String] domain
# The domain to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.for_domain(domain)
joins(url: [:host_name]).merge(HostName.with_domain(domain))
end
#
# Queries all web vulnerabilities with the matching URL path.
#
# @param [String] path
# The URL path to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.for_path(path)
joins(:url).where(url: {path: path})
end
#
# Queries all web vulnerabilities of the given type.
#
# @param [:lfi, :rfi, :sqli, :ssti, :open_redirect, :reflected_xss, :command_injection] type
# The web vulnerability type to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.with_type(type)
where(type: type)
end
#
# Queries all web vulnerabilities effecting the given query param name.
#
# @param [String] name
# The query param name to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.with_query_param(name)
where(query_param: name)
end
#
# Queries all web vulnerabilities effecting the given header name.
#
# @param [String] name
# The header name to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.with_header_name(name)
where(header_name: name)
end
#
# Queries all web vulnerabilities effecting the given cookie param name.
#
# @param [String] name
# The cookie param name to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.with_cookie_param(name)
where(cookie_param: name)
end
#
# Queries all web vulnerabilities effecting the given form param name.
#
# @param [String] name
# The form param name to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.with_form_param(name)
where(form_param: name)
end
#
# Queries all web vulnerabilities with the given request method.
#
# @param [String] request_method
# The request method to search for.
#
# @return [Array]
# The matching web vulnerabilities.
#
def self.with_request_method(request_method)
where(request_method: request_method)
end
#
# Validates presence of at least one param fields.
#
def param_validation
unless (query_param || header_name || cookie_param || form_param)
self.errors.add(:base, "query_param, header_name, cookie_param or from_param must be present")
end
end
end
end
end
require 'ronin/db/url'