Skip to content
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

feat(iast): implement the stacktrace leak vulnerability #12007

Merged
merged 37 commits into from
Jan 24, 2025
Merged
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c2b172f
checkpoint
juanjux Jan 20, 2025
f8aaa13
checkpoint
juanjux Jan 20, 2025
6a7c552
checkpoint
juanjux Jan 20, 2025
c53ab01
Merge branch 'main' into juanjux/APPSEC-53593-stacktrace-leak
juanjux Jan 20, 2025
bb6e309
fmt
juanjux Jan 20, 2025
8be14e0
release note
juanjux Jan 20, 2025
ad156a5
move test html to a separate file
juanjux Jan 21, 2025
f942d8f
Add stacktrace leak and test for FastAPI
juanjux Jan 21, 2025
321a067
Implement stacktrace leak check for Django debug page
juanjux Jan 21, 2025
65f4c60
Implement stacktrace leak check for Flask debug page
juanjux Jan 21, 2025
ff0551d
fmt
juanjux Jan 21, 2025
491236f
Merge branch 'main' into juanjux/APPSEC-53593-stacktrace-leak
juanjux Jan 21, 2025
5d5f95b
fmt
juanjux Jan 21, 2025
028380c
fmt
juanjux Jan 21, 2025
32e19d7
Merge branch 'main' into juanjux/APPSEC-53593-stacktrace-leak
juanjux Jan 21, 2025
cb4a5c7
fmt
juanjux Jan 21, 2025
1e37719
fmt
juanjux Jan 21, 2025
9461ad0
fix asm context usage
juanjux Jan 21, 2025
93ca54d
fmt
juanjux Jan 21, 2025
4c3bcff
fmt
juanjux Jan 21, 2025
7809bff
Context fixes
juanjux Jan 21, 2025
77249f1
fmt
juanjux Jan 21, 2025
f4807e6
Remove debug stuff
juanjux Jan 21, 2025
076653e
Move the stacktrace report context to IAST
juanjux Jan 21, 2025
b456fe5
fmt
juanjux Jan 21, 2025
e662a2f
Add ignore to decode
juanjux Jan 21, 2025
392b103
Add ignore to decode
juanjux Jan 21, 2025
6b472ba
fmt
juanjux Jan 21, 2025
2c60961
Remove unneded line
juanjux Jan 22, 2025
7f76ba2
Dont patch DebugTraceback if the werkzeug version doesnt support it
juanjux Jan 22, 2025
2b54d60
Merge branch 'main' into juanjux/APPSEC-53593-stacktrace-leak
juanjux Jan 22, 2025
a481732
fmt
juanjux Jan 22, 2025
41ed1af
simplify flask hook
juanjux Jan 22, 2025
31746b3
Merge branch 'main' into juanjux/APPSEC-53593-stacktrace-leak
juanjux Jan 22, 2025
92d3f89
Simplify if condition
juanjux Jan 22, 2025
590a6a0
Fix system tests
juanjux Jan 22, 2025
525c574
Merge branch 'main' into juanjux/APPSEC-53593-stacktrace-leak
avara1986 Jan 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
checkpoint
Signed-off-by: Juanjo Alvarez <juanjo.alvarezmartinez@datadoghq.com>
juanjux committed Jan 20, 2025
commit 6a7c55296e91add7a7e977b35d92cf42955cab86
3 changes: 1 addition & 2 deletions ddtrace/appsec/_iast/_handlers.py
Original file line number Diff line number Diff line change
@@ -405,7 +405,6 @@ def _on_set_request_tags_iast(request, span, flask_config):
)


# JJJ try except... el decode podria fallar
def _on_django_finalize_response_pre(response):
if not _is_iast_enabled() or not is_iast_request_enabled():
return
@@ -422,7 +421,7 @@ def _on_flask_finalize_request_post(response, _):
return

try:
content = response.content.decode("utf-8")
content = response[0].decode("utf-8")
asm_check_stacktrace_leak(content)
except Exception:
log.debug("Unexpected exception checking for stacktrace leak", exc_info=True)
2 changes: 1 addition & 1 deletion ddtrace/appsec/_iast/_listener.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ddtrace.appsec._iast._handlers import _on_django_func_wrapped
from ddtrace.appsec._iast._handlers import _on_django_func_wrapped, _on_flask_finalize_request_post
from ddtrace.appsec._iast._handlers import _on_django_patch
from ddtrace.appsec._iast._handlers import _on_flask_patch
from ddtrace.appsec._iast._handlers import _on_grpc_response
2 changes: 0 additions & 2 deletions ddtrace/appsec/_iast/taint_sinks/stacktrace_leak.py
Original file line number Diff line number Diff line change
@@ -5,8 +5,6 @@
from .._metrics import increment_iast_span_metric, _set_metric_iast_executed_sink
from .._taint_tracking._errors import iast_taint_log_error
from ..constants import VULN_STACKTRACE_LEAK
from .. import _is_iast_enabled
from .._iast_request_context import is_iast_request_enabled
from ..constants import STACKTRACE_FILE_LINE
from ..constants import STACKTRACE_EXCEPTION_REGEX
from ..constants import HTML_TAGS_REMOVE
Original file line number Diff line number Diff line change
@@ -81,4 +81,5 @@ def shutdown(request):
handler("appsec/validate_querydict/$", views.validate_querydict, name="validate_querydict"),
path("appsec/path-params/<int:year>/<str:month>/", views.path_params_view, name="path-params-view"),
path("appsec/checkuser/<str:user_id>/", views.checkuser_view, name="checkuser"),
path("appsec/stacktrace_leak/", views.stacktrace_leak_view),
]
4 changes: 4 additions & 0 deletions tests/appsec/integrations/django_tests/django_app/views.py
Original file line number Diff line number Diff line change
@@ -273,3 +273,7 @@ def validate_querydict(request):
return HttpResponse(
"x=%s, all=%s, keys=%s, urlencode=%s" % (str(res), str(lres), str(keys), qd.urlencode()), status=200
)

def stacktrace_leak_view(request):
from tests.appsec.iast.taint_sinks.test_stacktrace_leak import _html_django_stacktrace
return HttpResponse(_html_django_stacktrace)
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
from ddtrace.appsec._iast import oce
from ddtrace.appsec._iast._patch_modules import patch_iast
from ddtrace.appsec._iast._utils import _is_python_version_supported as python_supported_by_iast
from ddtrace.appsec._iast.constants import VULN_CMDI
from ddtrace.appsec._iast.constants import VULN_CMDI, VULN_STACKTRACE_LEAK
from ddtrace.appsec._iast.constants import VULN_HEADER_INJECTION
from ddtrace.appsec._iast.constants import VULN_INSECURE_COOKIE
from ddtrace.appsec._iast.constants import VULN_SQL_INJECTION
@@ -886,3 +886,24 @@ def test_django_insecure_cookie_special_characters(client, test_spans, tracer):
assert "line" not in vulnerability["location"].keys()
assert vulnerability["location"]["spanId"]
assert vulnerability["hash"]

@pytest.mark.skipif(not python_supported_by_iast(), reason="Python version not supported by IAST")
def test_django_stacktrace_leak(client, test_spans):
with override_global_config(dict(_iast_enabled=True, _deduplication_enabled=False)):
oce.reconfigure()
root_span, _ = _aux_appsec_get_root_span(
client,
test_spans,
tracer,
url="/appsec/stacktrace_leak/",
)

assert root_span.get_metric(IAST.ENABLED) == 1.0

loaded = json.loads(root_span.get_tag(IAST.JSON))
assert loaded["sources"] == []
assert len(loaded["vulnerabilities"]) == 1
vulnerability = loaded["vulnerabilities"][0]
assert vulnerability["type"] == VULN_STACKTRACE_LEAK
assert vulnerability["evidence"] == {"valueParts": [{"value": "Module: home.foobaruser.sources.minimal-django-example.app\nException: IndexError"}]}
assert vulnerability["hash"]
328 changes: 190 additions & 138 deletions tests/contrib/flask/test_flask_appsec_iast.py

Large diffs are not rendered by default.