WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Changes from all commits
Commits
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
43 changes: 39 additions & 4 deletions ddtrace/appsec/_common_module_patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def _(module):
try_wrap_function_wrapper("builtins", "open", wrapped_open_CFDDB7ABBA9081B6)
try_wrap_function_wrapper("urllib.request", "OpenerDirector.open", wrapped_open_ED4CF71136E15EBF)
try_wrap_function_wrapper("http.client", "HTTPConnection.request", wrapped_request)
try_wrap_function_wrapper("http.client", "HTTPConnection.getresponse", wrapped_response)
core.on("asm.block.dbapi.execute", execute_4C9BAC8E228EB347)
log.debug("Patching common modules: builtins and urllib.request")
_is_patched = True
Expand All @@ -74,6 +75,8 @@ def unpatch_common_modules():
try_unwrap("urllib3.request", "RequestMethods.request")
try_unwrap("builtins", "open")
try_unwrap("urllib.request", "OpenerDirector.open")
try_unwrap("http.client", "HTTPConnection.request")
try_unwrap("http.client", "HTTPConnection.getresponse")
try_unwrap("_io", "BytesIO.read")
try_unwrap("_io", "StringIO.read")
subprocess_patch.unpatch()
Expand Down Expand Up @@ -190,6 +193,26 @@ def wrapped_request(original_request_callable, instance, args, kwargs):
return original_request_callable(*args, **kwargs)


def wrapped_response(original_response_callable, instance, args, kwargs):
from ddtrace.appsec._asm_request_context import call_waf_callback

response = original_response_callable(*args, *kwargs)
env = _get_asm_context()
try:
if _get_rasp_capability("ssrf") and response.__class__.__name__ == "HTTPResponse" and env is not None:
status = response.getcode()
if 300 <= status < 400:
# api10 for redirected response status and headers in urllib
addresses = {
"DOWN_RES_STATUS": str(status),
"DOWN_RES_HEADERS": _build_headers(response.getheaders()),
}
call_waf_callback(addresses, rule_type=EXPLOIT_PREVENTION.TYPE.SSRF_RES)
except Exception:
pass # nosec
return response


def _parse_http_response_body(response):
try:
if response.length and response.headers.get("content-type", None) == "application/json":
Expand Down Expand Up @@ -228,7 +251,7 @@ def wrapped_open_ED4CF71136E15EBF(original_open_callable, instance, args, kwargs
try:
response = original_open_callable(*args, **kwargs)
# api10 response handler for regular responses
if response.__class__.__name__ == "HTTPResponse":
if response.__class__.__name__ == "HTTPResponse" and not (300 <= response.status < 400):
addresses = {
"DOWN_RES_STATUS": str(response.status),
"DOWN_RES_HEADERS": _build_headers(response.getheaders()),
Expand Down Expand Up @@ -271,7 +294,8 @@ def wrapped_urllib3_make_request(original_request_callable, instance, args, kwar

full_url = core.get_item("full_url")
env = _get_asm_context()
if _get_rasp_capability("ssrf") and full_url is not None and env is not None:
do_rasp = _get_rasp_capability("ssrf") and full_url is not None and env is not None
if do_rasp:
use_body = core.get_item("use_body", False)
method = args[1] if len(args) > 1 else kwargs.get("method", None)
body = args[3] if len(args) > 3 else kwargs.get("body", None)
Expand All @@ -292,7 +316,18 @@ def wrapped_urllib3_make_request(original_request_callable, instance, args, kwar
core.discard_item("full_url")
if res and _must_block(res.actions):
raise BlockingException(get_blocked(), EXPLOIT_PREVENTION.BLOCKING, EXPLOIT_PREVENTION.TYPE.SSRF, full_url)
return original_request_callable(*args, **kwargs)
response = original_request_callable(*args, **kwargs)
try:
if do_rasp and response.__class__.__name__ == "BaseHTTPResponse" and 300 <= response.status < 400:
# api10 for redirected response status and headers in urllib3
addresses = {
"DOWN_RES_STATUS": str(response.status),
"DOWN_RES_HEADERS": response.headers,
}
call_waf_callback(addresses, rule_type=EXPLOIT_PREVENTION.TYPE.SSRF_RES)
except Exception:
pass # nosec
return response


def wrapped_urllib3_urlopen(original_open_callable, instance, args, kwargs):
Expand Down Expand Up @@ -329,7 +364,7 @@ def wrapped_request_D8CB81E472AF98A2(original_request_callable, instance, args,
# API10, doing all request calls in HTTPConnection.request
try:
response = original_request_callable(*args, **kwargs)
if response.__class__.__name__ == "Response":
if response.__class__.__name__ == "Response" and not (300 <= response.status_code < 400):
addresses = {
"DOWN_RES_STATUS": str(response.status_code),
"DOWN_RES_HEADERS": dict(response.headers),
Expand Down
Loading