-
Notifications
You must be signed in to change notification settings - Fork 10
attack wave detection #474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 37 commits
ce729d6
7e610ca
0915ab7
9477744
cfce8ee
7f9a4ff
0e19cf2
8a0f52c
35036ff
bf524d1
d69ae55
2dbd697
8d48fae
ea347c6
6a667ed
5ff3886
a28d2be
b2839e3
15b7ccc
19039c7
1260b9f
456da70
ef52fcc
c6bc1c6
28a2c13
6907302
4a2106b
26580b3
17be2f3
76ef4c2
ddd8fd3
afac85b
5d762f8
a28516b
541c655
d6cf778
ea201eb
aeb4878
35c14fc
2901ef3
b6fbd3f
6c67704
7714c5a
af8baeb
5ffe713
7f71517
8661905
220283c
b62d4ea
8fe14c9
08f7c78
0b01c40
dcfbfe9
0454e26
60416b0
7f5f989
ea92fec
4946843
eb7f18c
7aaafb6
b428424
75a3d98
7130a74
cf939b3
3030108
b4e00a5
1e428e6
fca21aa
a128e72
fc24c30
dcd71b0
b78496c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| from aikido_zen.context import Context | ||
| from aikido_zen.helpers.get_current_unixtime_ms import get_unixtime_ms | ||
| from aikido_zen.helpers.logging import logger | ||
|
|
||
|
|
||
| def on_detected_attack_wave(connection_manager, context: Context, metadata): | ||
bitterpanda63 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if not connection_manager.token: | ||
| return | ||
| try: | ||
| agent_info = connection_manager.get_manager_info() | ||
| payload = create_attack_wave_payload(agent_info, context, metadata) | ||
|
|
||
| connection_manager.api.report( | ||
| connection_manager.token, | ||
| payload, | ||
| connection_manager.timeout_in_sec, | ||
| ) | ||
| except Exception as e: | ||
| logger.info("Failed to report an attack wave (%s)", str(e)) | ||
|
|
||
|
|
||
| def create_attack_wave_payload(agent_info, context: Context, metadata): | ||
| return { | ||
| "type": "detected_attack_wave", | ||
| "time": get_unixtime_ms(), | ||
| "agent": agent_info, | ||
| "attack": {"metadata": metadata, "user": context.user}, | ||
| "request": { | ||
| "ipAddress": context.remote_address, | ||
| "userAgent": context.get_user_agent(), | ||
| "source": context.source, | ||
| }, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| from aikido_zen.context import Context | ||
|
|
||
|
|
||
| class ReportingQueueAttackWaveEvent: | ||
| def __init__(self, context: Context, metadata): | ||
| self.context = context | ||
| self.metadata = metadata |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,9 @@ | |
| from aikido_zen.thread.thread_cache import get_cache | ||
| from .ip_allowed_to_access_route import ip_allowed_to_access_route | ||
| import aikido_zen.background_process.comms as c | ||
| from ...background_process.commands.check_firewall_lists import CheckFirewallListsRes | ||
| from ...background_process.queue_helpers import ReportingQueueAttackWaveEvent | ||
| from ...vulnerabilities.attack_wave_detection.is_web_scanner import is_web_scanner | ||
|
|
||
|
|
||
| def request_handler(stage, status_code=0): | ||
|
|
@@ -49,7 +52,11 @@ def pre_response(): | |
| message += f" (Your IP: {context.remote_address})" | ||
| return message, 403 | ||
|
|
||
| # Do a check on firewall lists, this happens in background because of the heavy data. | ||
| is_attack_wave_request = is_web_scanner(context) | ||
bitterpanda63 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if is_attack_wave_request: | ||
| logger.debug("Web scan detected for %s:%s", context.method, context.route) | ||
|
|
||
| # Do a check on firewall lists & attack waves, this happens in background because of the heavy data. | ||
bitterpanda63 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # For the timeout we notice the request during heavy loads usually takes 2ms - 2.5ms, we set timeout at 10ms. | ||
| # That way we have a very small timeout with very little risk of not blocking ips. | ||
| comms = c.get_comms() | ||
|
|
@@ -58,28 +65,37 @@ def pre_response(): | |
| obj={ | ||
| "ip": context.remote_address, | ||
| "user-agent": context.get_user_agent(), | ||
| "is_attack_wave_request": bool(is_attack_wave_request), | ||
| }, | ||
| receive=True, | ||
| timeout_in_sec=(10 / 1000), | ||
| ) | ||
| if not check_fw_lists_res["success"] or not check_fw_lists_res["data"]["blocked"]: | ||
| if not check_fw_lists_res.get("success", False): | ||
| return | ||
| res: CheckFirewallListsRes = check_fw_lists_res.get("data") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pre_response() removed a single early guard for 'not blocked' and now repeats 'res.blocked' checks across branches instead of using an early return when not res.blocked. Details🔧 How do I fix it? More info - Comment |
||
|
|
||
| block_type = check_fw_lists_res["data"]["type"] | ||
|
|
||
| if block_type == "allowlist": | ||
| if res.blocked and res.type == "allowlist": | ||
| message = "Your IP address is not allowed." | ||
| message += " (Your IP: " + context.remote_address + ")" | ||
| return message, 403 | ||
| if block_type == "blocklist": | ||
| if res.blocked and res.type == "blocklist": | ||
| message = "Your IP address is blocked due to " | ||
| message += check_fw_lists_res["data"]["reason"] | ||
| message += res.reason | ||
| message += " (Your IP: " + context.remote_address + ")" | ||
| return message, 403 | ||
| if block_type == "bot-blocking": | ||
| if res.blocked and res.type == "bot-blocking": | ||
| msg = "You are not allowed to access this resource because you have been identified as a bot." | ||
| return msg, 403 | ||
|
|
||
| # We only check for attack waves after IP/Bot blocking, the reason being that if you already block the scanner | ||
| # There is no attack wave happening. | ||
| if res.is_attack_wave: | ||
| # Report to core & increase stats | ||
| comms.send_data_to_bg_process( | ||
| "ATTACK", ReportingQueueAttackWaveEvent(context, metadata={}) | ||
| ) | ||
| cache.stats.on_detected_attack_wave(blocked=res.blocked) | ||
|
|
||
|
|
||
| def post_response(status_code): | ||
| """Checks if the current route is useful""" | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.