aikido-zen 0.2.0-x86_64-mingw-64 → 1.0.1.beta.2-x86_64-mingw-64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.aikido +6 -0
- data/.simplecov +6 -0
- data/README.md +67 -83
- data/benchmarks/README.md +8 -12
- data/docs/rails.md +1 -1
- data/lib/aikido/zen/agent.rb +10 -8
- data/lib/aikido/zen/api_client.rb +14 -4
- data/lib/aikido/zen/background_worker.rb +52 -0
- data/lib/aikido/zen/collector.rb +12 -1
- data/lib/aikido/zen/config.rb +20 -0
- data/lib/aikido/zen/context.rb +4 -0
- data/lib/aikido/zen/detached_agent/agent.rb +78 -0
- data/lib/aikido/zen/detached_agent/front_object.rb +37 -0
- data/lib/aikido/zen/detached_agent/server.rb +41 -0
- data/lib/aikido/zen/detached_agent.rb +2 -0
- data/lib/aikido/zen/errors.rb +8 -0
- data/lib/aikido/zen/internals.rb +41 -7
- data/lib/aikido/zen/libzen-v0.1.39-x86_64-mingw-64.dll +0 -0
- data/lib/aikido/zen/middleware/rack_throttler.rb +9 -3
- data/lib/aikido/zen/middleware/request_tracker.rb +6 -4
- data/lib/aikido/zen/outbound_connection_monitor.rb +4 -0
- data/lib/aikido/zen/rails_engine.rb +8 -8
- data/lib/aikido/zen/rate_limiter/breaker.rb +3 -3
- data/lib/aikido/zen/rate_limiter.rb +6 -11
- data/lib/aikido/zen/request/heuristic_router.rb +6 -0
- data/lib/aikido/zen/request/rails_router.rb +6 -18
- data/lib/aikido/zen/request/schema/auth_schemas.rb +14 -0
- data/lib/aikido/zen/request/schema.rb +18 -0
- data/lib/aikido/zen/runtime_settings.rb +2 -2
- data/lib/aikido/zen/scanners/path_traversal_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/shell_injection_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/sql_injection_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/ssrf/private_ip_checker.rb +33 -21
- data/lib/aikido/zen/scanners/ssrf_scanner.rb +6 -1
- data/lib/aikido/zen/scanners/stored_ssrf_scanner.rb +6 -0
- data/lib/aikido/zen/sink.rb +11 -1
- data/lib/aikido/zen/sinks/action_controller.rb +9 -4
- data/lib/aikido/zen/sinks/async_http.rb +35 -16
- data/lib/aikido/zen/sinks/curb.rb +52 -26
- data/lib/aikido/zen/sinks/em_http.rb +39 -25
- data/lib/aikido/zen/sinks/excon.rb +63 -45
- data/lib/aikido/zen/sinks/file.rb +67 -71
- data/lib/aikido/zen/sinks/http.rb +38 -19
- data/lib/aikido/zen/sinks/httpclient.rb +51 -22
- data/lib/aikido/zen/sinks/httpx.rb +37 -18
- data/lib/aikido/zen/sinks/kernel.rb +18 -57
- data/lib/aikido/zen/sinks/mysql2.rb +19 -7
- data/lib/aikido/zen/sinks/net_http.rb +37 -19
- data/lib/aikido/zen/sinks/patron.rb +41 -24
- data/lib/aikido/zen/sinks/pg.rb +50 -27
- data/lib/aikido/zen/sinks/resolv.rb +37 -16
- data/lib/aikido/zen/sinks/socket.rb +46 -17
- data/lib/aikido/zen/sinks/sqlite3.rb +31 -12
- data/lib/aikido/zen/sinks/trilogy.rb +19 -7
- data/lib/aikido/zen/sinks.rb +29 -20
- data/lib/aikido/zen/sinks_dsl.rb +226 -0
- data/lib/aikido/zen/version.rb +2 -2
- data/lib/aikido/zen/worker.rb +5 -0
- data/lib/aikido/zen.rb +59 -9
- data/placeholder/.gitignore +4 -0
- data/placeholder/README.md +11 -0
- data/placeholder/Rakefile +75 -0
- data/placeholder/lib/placeholder.rb.template +3 -0
- data/placeholder/placeholder.gemspec.template +20 -0
- data/tasklib/bench.rake +29 -6
- data/tasklib/libzen.rake +70 -66
- data/tasklib/wrk.rb +88 -0
- metadata +23 -13
- data/CHANGELOG.md +0 -25
- data/lib/aikido/zen/libzen-v0.1.37.x86_64.dll +0 -0
- data/lib/aikido.rb +0 -3
@@ -1,25 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Net
|
9
9
|
module HTTP
|
10
|
+
def self.load_sinks!
|
11
|
+
# In stdlib but not always required
|
12
|
+
require "net/http"
|
13
|
+
|
14
|
+
::Net::HTTP.prepend(Net::HTTP::HTTPExtensions)
|
15
|
+
end
|
16
|
+
|
10
17
|
SINK = Sinks.add("net-http", scanners: [
|
11
|
-
|
12
|
-
|
18
|
+
Scanners::SSRFScanner,
|
19
|
+
OutboundConnectionMonitor
|
13
20
|
])
|
14
21
|
|
15
|
-
module
|
22
|
+
module Helpers
|
16
23
|
# Maps a Net::HTTP connection to an Aikido OutboundConnection,
|
17
24
|
# which our tooling expects.
|
18
25
|
#
|
19
26
|
# @param http [Net::HTTP]
|
20
27
|
# @return [Aikido::Zen::OutboundConnection]
|
21
28
|
def self.build_outbound(http)
|
22
|
-
|
29
|
+
OutboundConnection.new(
|
23
30
|
host: http.address,
|
24
31
|
port: http.port
|
25
32
|
)
|
@@ -34,7 +41,7 @@ module Aikido::Zen
|
|
34
41
|
path: req.path
|
35
42
|
}))
|
36
43
|
|
37
|
-
|
44
|
+
Scanners::SSRFScanner::Request.new(
|
38
45
|
verb: req.method,
|
39
46
|
uri: uri,
|
40
47
|
headers: req.to_hash,
|
@@ -43,33 +50,44 @@ module Aikido::Zen
|
|
43
50
|
end
|
44
51
|
|
45
52
|
def self.wrap_response(response)
|
46
|
-
|
53
|
+
Scanners::SSRFScanner::Response.new(
|
47
54
|
status: response.code.to_i,
|
48
55
|
headers: response.to_hash,
|
49
56
|
header_normalizer: ->(val) { Array(val).join(", ") }
|
50
57
|
)
|
51
58
|
end
|
52
59
|
|
53
|
-
def request
|
54
|
-
|
60
|
+
def self.scan(request, connection, operation)
|
61
|
+
SINK.scan(
|
62
|
+
request: request,
|
63
|
+
connection: connection,
|
64
|
+
operation: operation
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module HTTPExtensions
|
70
|
+
extend Sinks::DSL
|
71
|
+
|
72
|
+
sink_around :request do |super_call, req|
|
73
|
+
wrapped_request = Helpers.wrap_request(req, self)
|
55
74
|
|
56
75
|
# Store the request information so the DNS sinks can pick it up.
|
57
|
-
|
76
|
+
context = Aikido::Zen.current_context
|
77
|
+
if context
|
58
78
|
prev_request = context["ssrf.request"]
|
59
79
|
context["ssrf.request"] = wrapped_request
|
60
80
|
end
|
61
81
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
operation: "request"
|
66
|
-
)
|
82
|
+
connection = Helpers.build_outbound(self)
|
83
|
+
|
84
|
+
Helpers.scan(wrapped_request, connection, "request")
|
67
85
|
|
68
|
-
response =
|
86
|
+
response = super_call.call
|
69
87
|
|
70
|
-
|
88
|
+
Scanners::SSRFScanner.track_redirects(
|
71
89
|
request: wrapped_request,
|
72
|
-
response:
|
90
|
+
response: Helpers.wrap_response(response)
|
73
91
|
)
|
74
92
|
|
75
93
|
response
|
@@ -82,4 +100,4 @@ module Aikido::Zen
|
|
82
100
|
end
|
83
101
|
end
|
84
102
|
|
85
|
-
|
103
|
+
Aikido::Zen::Sinks::Net::HTTP.load_sinks!
|
@@ -1,56 +1,75 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Patron
|
9
|
+
def self.load_sinks!
|
10
|
+
if Gem.loaded_specs["patron"]
|
11
|
+
require "patron"
|
12
|
+
|
13
|
+
::Patron::Session.prepend(SessionExtensions)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
SINK = Sinks.add("patron", scanners: [
|
10
|
-
|
11
|
-
|
18
|
+
Scanners::SSRFScanner,
|
19
|
+
OutboundConnectionMonitor
|
12
20
|
])
|
13
21
|
|
14
|
-
module
|
22
|
+
module Helpers
|
15
23
|
def self.wrap_response(request, response)
|
16
24
|
# In this case, automatic redirection happened inside libcurl.
|
17
25
|
if response.url != request.url && !response.url.to_s.empty?
|
18
|
-
|
26
|
+
Scanners::SSRFScanner::Response.new(
|
19
27
|
status: 302, # We can't know what the actual status was, but we just need a 3XX
|
20
28
|
headers: response.headers.merge("Location" => response.url)
|
21
29
|
)
|
22
30
|
else
|
23
|
-
|
31
|
+
Scanners::SSRFScanner::Response.new(
|
24
32
|
status: response.status,
|
25
33
|
headers: response.headers
|
26
34
|
)
|
27
35
|
end
|
28
36
|
end
|
29
37
|
|
30
|
-
def
|
31
|
-
|
38
|
+
def self.scan(request, connection, operation)
|
39
|
+
SINK.scan(
|
40
|
+
request: request,
|
41
|
+
connection: connection,
|
42
|
+
operation: operation
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module SessionExtensions
|
48
|
+
extend Sinks::DSL
|
49
|
+
|
50
|
+
sink_around :handle_request do |super_call, request|
|
51
|
+
wrapped_request = Scanners::SSRFScanner::Request.new(
|
32
52
|
verb: request.action,
|
33
53
|
uri: URI(request.url),
|
34
54
|
headers: request.headers
|
35
55
|
)
|
36
56
|
|
37
57
|
# Store the request information so the DNS sinks can pick it up.
|
38
|
-
|
58
|
+
context = Aikido::Zen.current_context
|
59
|
+
if context
|
39
60
|
prev_request = context["ssrf.request"]
|
40
61
|
context["ssrf.request"] = wrapped_request
|
41
62
|
end
|
42
63
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
operation: "request"
|
47
|
-
)
|
64
|
+
connection = OutboundConnection.from_uri(URI(request.url))
|
65
|
+
|
66
|
+
Helpers.scan(wrapped_request, connection, "request")
|
48
67
|
|
49
|
-
response =
|
68
|
+
response = super_call.call
|
50
69
|
|
51
|
-
|
70
|
+
Scanners::SSRFScanner.track_redirects(
|
52
71
|
request: wrapped_request,
|
53
|
-
response:
|
72
|
+
response: Helpers.wrap_response(request, response)
|
54
73
|
)
|
55
74
|
|
56
75
|
# When libcurl has follow_location set, it will handle redirections
|
@@ -62,18 +81,16 @@ module Aikido::Zen
|
|
62
81
|
# stop the response from being exposed to the user. This downgrades
|
63
82
|
# the SSRF into a blind SSRF, which is better than doing nothing.
|
64
83
|
if request.url != response.url && !response.url.to_s.empty?
|
65
|
-
last_effective_request =
|
84
|
+
last_effective_request = Scanners::SSRFScanner::Request.new(
|
66
85
|
verb: request.action,
|
67
86
|
uri: URI(response.url),
|
68
87
|
headers: request.headers
|
69
88
|
)
|
70
89
|
context["ssrf.request"] = last_effective_request if context
|
71
90
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
operation: "request"
|
76
|
-
)
|
91
|
+
connection = OutboundConnection.from_uri(URI(response.url))
|
92
|
+
|
93
|
+
Helpers.scan(last_effective_request, connection, "request")
|
77
94
|
end
|
78
95
|
|
79
96
|
response
|
@@ -85,4 +102,4 @@ module Aikido::Zen
|
|
85
102
|
end
|
86
103
|
end
|
87
104
|
|
88
|
-
|
105
|
+
Aikido::Zen::Sinks::Patron.load_sinks!
|
data/lib/aikido/zen/sinks/pg.rb
CHANGED
@@ -1,51 +1,74 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../sink"
|
4
|
-
|
5
3
|
module Aikido::Zen
|
6
4
|
module Sinks
|
7
5
|
module PG
|
6
|
+
def self.load_sinks!
|
7
|
+
if Gem.loaded_specs["pg"]
|
8
|
+
require "pg"
|
9
|
+
|
10
|
+
::PG::Connection.prepend(PG::ConnectionExtensions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
SINK = Sinks.add("pg", scanners: [Scanners::SQLInjectionScanner])
|
9
15
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
module Helpers
|
17
|
+
# For some reason, the ActiveRecord pg adaptor does not wrap exceptions
|
18
|
+
# in ActiveRecord::StatementInvalid, leading to inconsistent handling.
|
19
|
+
# This guarantees that Aikido::Zen::SQLInjectionErrors are wrapped in
|
20
|
+
# an ActiveRecord::StatementInvalid.
|
21
|
+
def self.safe(&block)
|
22
|
+
# Code coverage is disabled here because this ActiveRecord behavior is
|
23
|
+
# exercised in end-to-end tests, which are not covered by SimpleCov.
|
24
|
+
# :nocov:
|
25
|
+
if !defined?(ActiveRecord::StatementInvalid)
|
26
|
+
Sinks::DSL.safe(&block)
|
27
|
+
else
|
28
|
+
begin
|
29
|
+
Sinks::DSL.safe(&block)
|
30
|
+
rescue Aikido::Zen::SQLInjectionError => err
|
31
|
+
raise ActiveRecord::StatementInvalid, cause: err
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# :nocov:
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.scan(query, operation)
|
38
|
+
SINK.scan(
|
39
|
+
query: query,
|
40
|
+
dialect: :postgresql,
|
41
|
+
operation: operation
|
42
|
+
)
|
43
|
+
end
|
19
44
|
end
|
20
45
|
|
21
|
-
module
|
46
|
+
module ConnectionExtensions
|
47
|
+
extend Sinks::DSL
|
48
|
+
|
22
49
|
%i[
|
23
50
|
send_query exec sync_exec async_exec
|
24
51
|
send_query_params exec_params sync_exec_params async_exec_params
|
25
|
-
].each do |
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
super
|
30
|
-
#{WRAP_EXCEPTIONS}
|
52
|
+
].each do |method_name|
|
53
|
+
presafe_sink_before method_name do |query|
|
54
|
+
Helpers.safe do
|
55
|
+
Helpers.scan(query, method_name)
|
31
56
|
end
|
32
|
-
|
57
|
+
end
|
33
58
|
end
|
34
59
|
|
35
60
|
%i[
|
36
61
|
send_prepare prepare async_prepare sync_prepare
|
37
|
-
].each do |
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
super
|
42
|
-
#{WRAP_EXCEPTIONS}
|
62
|
+
].each do |method_name|
|
63
|
+
presafe_sink_before method_name do |_, query|
|
64
|
+
Helpers.safe do
|
65
|
+
Helpers.scan(query, method_name)
|
43
66
|
end
|
44
|
-
|
67
|
+
end
|
45
68
|
end
|
46
69
|
end
|
47
70
|
end
|
48
71
|
end
|
49
72
|
end
|
50
73
|
|
51
|
-
|
74
|
+
Aikido::Zen::Sinks::PG.load_sinks!
|
@@ -1,28 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../sink"
|
4
3
|
require_relative "../scanners/stored_ssrf_scanner"
|
5
4
|
require_relative "../scanners/ssrf_scanner"
|
6
5
|
|
7
6
|
module Aikido::Zen
|
8
7
|
module Sinks
|
9
8
|
module Resolv
|
9
|
+
def self.load_sinks!
|
10
|
+
# In stdlib but not always required
|
11
|
+
require "resolv"
|
12
|
+
|
13
|
+
::Resolv.prepend(ResolvExtensions)
|
14
|
+
end
|
15
|
+
|
10
16
|
SINK = Sinks.add("resolv", scanners: [
|
11
|
-
|
12
|
-
|
17
|
+
Scanners::StoredSSRFScanner,
|
18
|
+
Scanners::SSRFScanner
|
13
19
|
])
|
14
20
|
|
15
|
-
module
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
addresses << address
|
21
|
-
yield address
|
22
|
-
end
|
23
|
-
ensure
|
24
|
-
if (context = Aikido::Zen.current_context)
|
25
|
-
context["dns.lookups"] ||= Aikido::Zen::Scanners::SSRF::DNSLookups.new
|
21
|
+
module Helpers
|
22
|
+
def self.scan(name, addresses, operation)
|
23
|
+
context = Aikido::Zen.current_context
|
24
|
+
if context
|
25
|
+
context["dns.lookups"] ||= Scanners::SSRF::DNSLookups.new
|
26
26
|
context["dns.lookups"].add(name, addresses)
|
27
27
|
end
|
28
28
|
|
@@ -30,12 +30,33 @@ module Aikido::Zen
|
|
30
30
|
hostname: name,
|
31
31
|
addresses: addresses,
|
32
32
|
request: context && context["ssrf.request"],
|
33
|
-
operation:
|
33
|
+
operation: operation
|
34
34
|
)
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
module ResolvExtensions
|
39
|
+
def each_address(*args, **kwargs, &blk)
|
40
|
+
# each_address is defined "manually" because no sink method pattern
|
41
|
+
# is applicable.
|
42
|
+
|
43
|
+
name, = args
|
44
|
+
|
45
|
+
addresses = []
|
46
|
+
super(*args, **kwargs) do |address| # rubocop:disable Style/SuperArguments
|
47
|
+
addresses << address
|
48
|
+
blk.call(address)
|
49
|
+
end
|
50
|
+
ensure
|
51
|
+
# Ensure partial results are scanned.
|
52
|
+
|
53
|
+
Sinks::DSL.safe do
|
54
|
+
Helpers.scan(name, addresses, "lookup")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
37
58
|
end
|
38
59
|
end
|
39
60
|
end
|
40
61
|
|
41
|
-
|
62
|
+
Aikido::Zen::Sinks::Resolv.load_sinks!
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "socket"
|
4
|
+
require_relative "../scanners/stored_ssrf_scanner"
|
5
|
+
require_relative "../scanners/ssrf_scanner"
|
4
6
|
|
5
7
|
module Aikido::Zen
|
6
8
|
module Sinks
|
@@ -8,44 +10,71 @@ module Aikido::Zen
|
|
8
10
|
# there's no way to access the internal DNS resolution that happens in C
|
9
11
|
# when using the socket primitives.
|
10
12
|
module Socket
|
13
|
+
def self.load_sinks!
|
14
|
+
::IPSocket.singleton_class.prepend(Socket::IPSocketExtensions)
|
15
|
+
end
|
16
|
+
|
11
17
|
SINK = Sinks.add("socket", scanners: [
|
12
|
-
|
13
|
-
|
18
|
+
Scanners::StoredSSRFScanner,
|
19
|
+
Scanners::SSRFScanner
|
14
20
|
])
|
15
21
|
|
16
|
-
module
|
17
|
-
def self.
|
22
|
+
module Helpers
|
23
|
+
def self.scan(hostname, socket, operation)
|
24
|
+
# We're patching IPSocket.open(..) method.
|
25
|
+
# The IPSocket class hierarchy is:
|
26
|
+
# IPSocket
|
27
|
+
# / \
|
28
|
+
# TCPSocket UDPSocket
|
29
|
+
# / \
|
30
|
+
# TCPServer SOCKSSocket
|
31
|
+
#
|
32
|
+
# Because we want to scan only HTTP requests, we skip in case the
|
33
|
+
# socket is not *exactly* an instance of TCPSocket — it's any
|
34
|
+
# of it subclasses
|
35
|
+
return unless socket.instance_of?(TCPSocket)
|
36
|
+
|
18
37
|
# ["AF_INET", 80, "10.0.0.1", "10.0.0.1"]
|
19
|
-
|
38
|
+
address_family, _port, _hostname, numeric_address = socket.peeraddr(:numeric)
|
20
39
|
|
21
40
|
# We only care about IPv4 (AF_INET) or IPv6 (AF_INET6) sockets
|
22
41
|
# This might be overcautious, since this is _IP_Socket, so you
|
23
42
|
# would expect it's only used for IP connections?
|
24
|
-
return unless addr_family.start_with?("AF_INET")
|
25
43
|
|
26
|
-
|
27
|
-
|
28
|
-
|
44
|
+
# Code coverage is disabled here because the then clause is a no-op,
|
45
|
+
# so there is nothing to cover.
|
46
|
+
# :nocov:
|
47
|
+
return unless address_family.start_with?("AF_INET")
|
48
|
+
# :nocov:
|
49
|
+
|
50
|
+
context = Aikido::Zen.current_context
|
51
|
+
if context
|
52
|
+
context["dns.lookups"] ||= Scanners::SSRF::DNSLookups.new
|
53
|
+
context["dns.lookups"].add(hostname, numeric_address)
|
29
54
|
end
|
30
55
|
|
31
56
|
SINK.scan(
|
32
57
|
hostname: hostname,
|
33
|
-
addresses: [
|
58
|
+
addresses: [numeric_address],
|
34
59
|
request: context && context["ssrf.request"],
|
35
|
-
operation:
|
60
|
+
operation: operation
|
36
61
|
)
|
37
62
|
end
|
63
|
+
end
|
38
64
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
IPSocketExtensions.scan_socket(name, socket)
|
65
|
+
module IPSocketExtensions
|
66
|
+
extend Sinks::DSL
|
43
67
|
|
44
|
-
|
68
|
+
sink_after :open do |socket, remote_host|
|
69
|
+
# Code coverage is disabled here because the tests are contrived and
|
70
|
+
# intentionally do not call open.
|
71
|
+
# :nocov:
|
72
|
+
Helpers.scan(remote_host, socket, "open")
|
73
|
+
# :nocov:
|
45
74
|
end
|
46
75
|
end
|
47
76
|
end
|
48
77
|
end
|
49
78
|
end
|
50
79
|
|
51
|
-
|
80
|
+
Aikido::Zen::Sinks::Socket.load_sinks!
|
@@ -1,30 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../sink"
|
4
|
-
|
5
3
|
module Aikido::Zen
|
6
4
|
module Sinks
|
7
5
|
module SQLite3
|
6
|
+
def self.load_sinks!
|
7
|
+
if Gem.loaded_specs["sqlite3"]
|
8
|
+
require "sqlite3"
|
9
|
+
|
10
|
+
::SQLite3::Database.prepend(DatabaseExtensions)
|
11
|
+
::SQLite3::Statement.prepend(StatementExtensions)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
8
15
|
SINK = Sinks.add("sqlite3", scanners: [Scanners::SQLInjectionScanner])
|
9
16
|
|
10
|
-
module
|
11
|
-
def
|
12
|
-
SINK.scan(
|
17
|
+
module Helpers
|
18
|
+
def self.scan(query, operation)
|
19
|
+
SINK.scan(
|
20
|
+
query: query,
|
21
|
+
dialect: :sqlite,
|
22
|
+
operation: operation
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module DatabaseExtensions
|
28
|
+
extend Sinks::DSL
|
29
|
+
|
30
|
+
private
|
13
31
|
|
14
|
-
|
32
|
+
# SQLite3::Database#exec_batch is an internal native private method.
|
33
|
+
sink_before :exec_batch do |sql|
|
34
|
+
Helpers.scan(sql, "exec_batch")
|
15
35
|
end
|
16
36
|
end
|
17
37
|
|
18
|
-
module
|
19
|
-
|
20
|
-
SINK.scan(query: sql, dialect: :sqlite, operation: "statement.execute")
|
38
|
+
module StatementExtensions
|
39
|
+
extend Sinks::DSL
|
21
40
|
|
22
|
-
|
41
|
+
sink_before :initialize do |_db, sql|
|
42
|
+
Helpers.scan(sql, "statement.execute")
|
23
43
|
end
|
24
44
|
end
|
25
45
|
end
|
26
46
|
end
|
27
47
|
end
|
28
48
|
|
29
|
-
|
30
|
-
::SQLite3::Statement.prepend(Aikido::Zen::Sinks::SQLite3::StatementExt)
|
49
|
+
Aikido::Zen::Sinks::SQLite3.load_sinks!
|
@@ -1,21 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../sink"
|
4
|
-
|
5
3
|
module Aikido::Zen
|
6
4
|
module Sinks
|
7
5
|
module Trilogy
|
6
|
+
def self.load_sinks!
|
7
|
+
if Gem.loaded_specs["trilogy"]
|
8
|
+
require "trilogy"
|
9
|
+
|
10
|
+
::Trilogy.prepend(TrilogyExtensions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
SINK = Sinks.add("trilogy", scanners: [Scanners::SQLInjectionScanner])
|
9
15
|
|
10
|
-
module
|
11
|
-
def
|
12
|
-
SINK.scan(query: query, dialect: :mysql, operation:
|
16
|
+
module Helpers
|
17
|
+
def self.scan(query, operation)
|
18
|
+
SINK.scan(query: query, dialect: :mysql, operation: operation)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module TrilogyExtensions
|
23
|
+
extend Sinks::DSL
|
13
24
|
|
14
|
-
|
25
|
+
sink_before :query do |query|
|
26
|
+
Helpers.scan(query, "query")
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
21
|
-
|
33
|
+
Aikido::Zen::Sinks::Trilogy.load_sinks!
|
data/lib/aikido/zen/sinks.rb
CHANGED
@@ -1,30 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# Code coverage is disabled in this file because it is environment-specific and
|
4
|
+
# not intended to be tested directly.
|
5
|
+
# :nocov:
|
4
6
|
|
5
|
-
require_relative "
|
7
|
+
require_relative "sink"
|
8
|
+
require_relative "sinks_dsl"
|
6
9
|
|
7
10
|
require_relative "sinks/action_controller" if defined?(::ActionController)
|
8
|
-
require_relative "sinks/file" if defined?(::File)
|
9
11
|
|
10
12
|
# Sadly, in ruby versions lower than 3.0, it's not possible to patch the
|
11
13
|
# Kernel module because how the `prepend` method is applied
|
12
14
|
# (https://stackoverflow.com/questions/78110397/prepend-kernel-module-function-globally#comment137713906_78112924)
|
13
|
-
if RUBY_VERSION >= "3.0"
|
14
|
-
|
15
|
-
|
16
|
-
require_relative "sinks/
|
17
|
-
require_relative "sinks/
|
18
|
-
require_relative "sinks/
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
require_relative "sinks/
|
23
|
-
|
15
|
+
require_relative "sinks/kernel" if RUBY_VERSION >= "3.0"
|
16
|
+
|
17
|
+
require_relative "sinks/file"
|
18
|
+
require_relative "sinks/socket"
|
19
|
+
require_relative "sinks/resolv"
|
20
|
+
require_relative "sinks/net_http"
|
21
|
+
|
22
|
+
# http.rb aims to support and is tested against Ruby 3.0+:
|
23
|
+
# https://github.com/httprb/http?tab=readme-ov-file#supported-ruby-versions
|
24
|
+
require_relative "sinks/http" if RUBY_VERSION >= "3.0"
|
25
|
+
|
26
|
+
require_relative "sinks/httpx"
|
27
|
+
require_relative "sinks/httpclient"
|
28
|
+
require_relative "sinks/excon"
|
29
|
+
require_relative "sinks/curb"
|
30
|
+
require_relative "sinks/patron"
|
24
31
|
require_relative "sinks/typhoeus" if defined?(::Typhoeus)
|
25
|
-
require_relative "sinks/async_http"
|
26
|
-
require_relative "sinks/em_http"
|
27
|
-
require_relative "sinks/mysql2"
|
28
|
-
require_relative "sinks/pg"
|
29
|
-
require_relative "sinks/sqlite3"
|
30
|
-
require_relative "sinks/trilogy"
|
32
|
+
require_relative "sinks/async_http"
|
33
|
+
require_relative "sinks/em_http"
|
34
|
+
require_relative "sinks/mysql2"
|
35
|
+
require_relative "sinks/pg"
|
36
|
+
require_relative "sinks/sqlite3"
|
37
|
+
require_relative "sinks/trilogy"
|
38
|
+
|
39
|
+
# :nocov:
|