Module: Contrast::Agent::Protect::Rule::SqlSampleBuilder::AttackBuilder

Included in:
NoSqli, Contrast::Agent::Protect::Rule::Sqli
Defined in:
lib/contrast/agent/protect/rule/sqli/sql_sample_builder.rb

Overview

This Module is how we apply the attack fo NoSQL and SQL Injection rule. It includes methods for building attack with match and database scanners

Instance Method Summary collapse

Instance Method Details

#append_match(context, input_analysis_result, result, query_string, **kwargs) ⇒ Object



144
145
146
147
148
# File 'lib/contrast/agent/protect/rule/sqli/sql_sample_builder.rb', line 144

def append_match context, input_analysis_result, result, query_string, **kwargs
  input_analysis_result.attack_count = input_analysis_result.attack_count + 1
  update_successful_attack_response(context, input_analysis_result, result, query_string)
  append_sample(context, input_analysis_result, result, query_string, **kwargs)
end

#build_attack_with_match(context, input_analysis_result, result, query_string, **kwargs) ⇒ Contrast::Agent::Reporting

Set up an attack result and assigns Database scanner for the No-SQL and SQLI injection detection rules

Parameters:

  • context (Contrast::Agent::RequestContext)

    the context for the current request

  • input_analysis_result (Contrast::Agent::Reporting, nil)

    previous attack result for this rule, if one exists, in the case of multiple inputs being found to violate the protection criteria

  • result (Contrast::Agent::Reporting, nil)

    previous attack result for this rule, if one exists, in the case of multiple inputs being found to violate the protection criteria

  • query_string (String)

    the value of the input which may be an attack

  • kwargs (Hash)

    key - value pairs of context individual rules need to build out details to send to TeamServer to tell the story of the attack

Returns:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/contrast/agent/protect/rule/sqli/sql_sample_builder.rb', line 73

def build_attack_with_match context, input_analysis_result, result, query_string, **kwargs
  return result if mode == :NO_ACTION || mode == :PERMIT

  attack_string = input_analysis_result.value
  regexp = Regexp.new(Regexp.escape(attack_string), Regexp::IGNORECASE)
  # extract struct result from kwargs
  agent_lib_struct_result = kwargs[:result_struct]
  return unless query_string.match?(regexp)

  database = kwargs[:database]
  scanner = select_scanner(database)
  ss = StringScanner.new(query_string)
  length = attack_string.length
  while ss.scan_until(regexp)
    # the pos of StringScanner is at the end of the regexp (input string), we need the beginning
    idx = ss.pos - attack_string.length
    last_boundary, boundary = scanner.crosses_boundary(query_string, idx, input_analysis_result.value)
    next unless last_boundary && boundary

    result ||= build_attack_result(context)

    # if the struct actually has the needed data in it - use it
    if agent_lib_struct_result.cs__is_a?(Hash)
      record_agent_lib_match(agent_lib_struct_result, length, kwargs)
    else
      record_match(idx, length, boundary, last_boundary, kwargs)
    end

    append_match(context, input_analysis_result, result, query_string, **kwargs)
  end

  result
end

#record_agent_lib_match(struct, length, kwargs) ⇒ Object

Parameters:

  • struct (ResultingStruct)

    The struct including all the data from the agent_lib scan



133
134
135
136
137
138
139
140
141
142
# File 'lib/contrast/agent/protect/rule/sqli/sql_sample_builder.rb', line 133

def record_agent_lib_match struct, length, kwargs
  kwargs[:start_idx] = struct[:start_index]
  kwargs[:end_idx] = if (struct[:end_index]).zero?
                       struct[:start_index] + length
                     else
                       struct[:end_index]
                     end
  kwargs[:boundary_overrun_idx] = struct[:boundary_overrun_index]
  kwargs[:input_boundary_idx] = struct[:input_boundary_index]
end

#record_match(idx, length, boundary, last_boundary, kwargs) ⇒ Object



123
124
125
126
127
128
# File 'lib/contrast/agent/protect/rule/sqli/sql_sample_builder.rb', line 123

def record_match idx, length, boundary, last_boundary, kwargs
  kwargs[:start_idx] = idx
  kwargs[:end_idx] = idx + length
  kwargs[:boundary_overrun_idx] = boundary
  kwargs[:input_boundary_idx] = last_boundary
end

#select_scanner(database) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/contrast/agent/protect/rule/sqli/sql_sample_builder.rb', line 107

def select_scanner database
  @scanners ||= {
      Contrast::Agent::Protect::Policy::AppliesSqliRule::DATABASE_MYSQL =>
      Contrast::Agent::Protect::Rule::Sqli::MysqlSqlScanner.new,
      Contrast::Agent::Protect::Policy::AppliesSqliRule::DATABASE_PG =>
      Contrast::Agent::Protect::Rule::Sqli::PostgresSqlScanner.new,
      Contrast::Agent::Protect::Policy::AppliesSqliRule::DATABASE_SQLITE =>
      Contrast::Agent::Protect::Rule::Sqli::SqliteSqlScanner.new,
      Contrast::Agent::Protect::Policy::AppliesNoSqliRule::DATABASE_NOSQL =>
      Contrast::Agent::Protect::Rule::NoSqli::MongoNoSqlScanner.new
  }.cs__freeze

  @default_scanner ||= Contrast::Agent::Protect::Rule::Sqli::DefaultSqlScanner.new
  @scanners[database.to_s] || @default_scanner
end