class Pentest::Endpoint

Attributes

app_path[R]
route[R]

Public Class Methods

new(route, app_path, hooks) click to toggle source
# File lib/pentest/endpoint.rb, line 7
def initialize(route, app_path, hooks)
  @route = route
  @app_path = app_path
  @hooks = hooks

  @controller = route.defaults[:controller]
  @action = route.defaults[:action]

  return if @controller.nil? || @action.nil?

  @controller_name = ::ActiveSupport::Inflector.camelize(@controller) + "Controller"
  @controller_class = ::ActiveSupport::Inflector.constantize(@controller_name)

  @error_patterns = Set.new
end

Public Instance Methods

dispatch(payload) click to toggle source
# File lib/pentest/endpoint.rb, line 60
def dispatch(payload)
  request = ActionDispatch::TestRequest.create
  request.request_method = @route.verb
  request.path = path(payload.params_hash)

  @hooks[:before_attacks].each do |before_attack_proc|
    before_attack_proc.call(request)
  end

  request.path_parameters = {
    controller: @controller,
    action: @action,
  }

  payload.params_hash.each do |param_parts, value|
    if param_parts.size == 1
      param, = param_parts
      if @route.required_parts.include? param
        request.path_parameters[param] = value
      else
        request.query_parameters[param] = value
      end
    elsif param_parts.size == 2
      request.query_parameters[param_parts[0]] ||= {}
      request.query_parameters[param_parts[0]][param_parts[1]] = value
    end
  end

  request.path_parameters.each do |param, value|
    request.update_param(param, value)
  end

  request.query_parameters.each do |param, value|
    request.update_param(param, value)
  end

  response = ActionDispatch::TestResponse.create

  err = nil
  begin
    @controller_class.new.dispatch(@action.to_sym, request, response)
  rescue => e
    err = e
  end

  [request, response, err]
end
scan!(ingredients) click to toggle source
# File lib/pentest/endpoint.rb, line 27
def scan!(ingredients)
  params = get_params

  Logger.info "#{@route.verb} #{path}"
  Logger.debug "Attacking #{@controller_class.inspect}##{@action}...", timestamp: false
  Logger.debug "Detected Parameters: #{params.to_a.inspect}", timestamp: false

  error_patterns = Set.new
  penetrated_payloads = []

  Logger.start_progress

  Checkers.run_checkers(self, params) do |checker|
    params.each_with_index do |param, injection_point|
      penetrated_payload, errors = checker.attack(param, injection_point, ingredients)

      accumulate_errors(errors)

      unless penetrated_payload.nil?
        penetrated_payloads << penetrated_payload
      end
    end
  end

  Logger.end_progress

  @error_patterns.each do |error_pattern|
    Logger.warn("Error: #{error_pattern}", timestamp: false)
  end

  penetrated_payloads
end
valid?() click to toggle source
# File lib/pentest/endpoint.rb, line 23
def valid?
  !@controller.nil? && !@action.nil? && @controller_class.method_defined?(@action.to_sym)
end

Private Instance Methods

accumulate_errors(errors) click to toggle source
# File lib/pentest/endpoint.rb, line 141
def accumulate_errors(errors)
  errors.each do |error|
    unless error.nil?
      @error_patterns << error
    end
  end
end
get_params() click to toggle source
# File lib/pentest/endpoint.rb, line 122
def get_params
  exp = RubyParser.get_sexp(method)
  param_usages = AstUtils.search_for_params(exp)
  deep_parameters = Set.new
  non_deep_parameters = Set.new

  param_usages.each do |param, type, method, arg|
    if type == :callee && method == :[]
      deep_parameters << [ param, arg[1] ]
    else
      non_deep_parameters << param
    end
  end

  non_deep_parameters += @route.required_parts.map(&:to_sym)
  non_deep_parameters -= deep_parameters.map {|a| a[0]}
  deep_parameters.to_a + non_deep_parameters.map {|param| [param]}
end
method() click to toggle source
# File lib/pentest/endpoint.rb, line 110
def method
  @controller_class.instance_method(@action.to_sym)
end
path(options = {}) click to toggle source
# File lib/pentest/endpoint.rb, line 114
def path(options = {})
  @route.required_parts.each do |part|
    options[part] ||= ":#{part}"
  end

  @route.format(options)
end