@@ -59,6 +59,7 @@ def _(module):
5959 try_wrap_function_wrapper ("builtins" , "open" , wrapped_open_CFDDB7ABBA9081B6 )
6060 try_wrap_function_wrapper ("urllib.request" , "OpenerDirector.open" , wrapped_open_ED4CF71136E15EBF )
6161 try_wrap_function_wrapper ("http.client" , "HTTPConnection.request" , wrapped_request )
62+ try_wrap_function_wrapper ("http.client" , "HTTPConnection.getresponse" , wrapped_response )
6263 core .on ("asm.block.dbapi.execute" , execute_4C9BAC8E228EB347 )
6364 log .debug ("Patching common modules: builtins and urllib.request" )
6465 _is_patched = True
@@ -74,6 +75,8 @@ def unpatch_common_modules():
7475 try_unwrap ("urllib3.request" , "RequestMethods.request" )
7576 try_unwrap ("builtins" , "open" )
7677 try_unwrap ("urllib.request" , "OpenerDirector.open" )
78+ try_unwrap ("http.client" , "HTTPConnection.request" )
79+ try_unwrap ("http.client" , "HTTPConnection.getresponse" )
7780 try_unwrap ("_io" , "BytesIO.read" )
7881 try_unwrap ("_io" , "StringIO.read" )
7982 subprocess_patch .unpatch ()
@@ -190,6 +193,26 @@ def wrapped_request(original_request_callable, instance, args, kwargs):
190193 return original_request_callable (* args , ** kwargs )
191194
192195
196+ def wrapped_response (original_response_callable , instance , args , kwargs ):
197+ from ddtrace .appsec ._asm_request_context import call_waf_callback
198+
199+ response = original_response_callable (* args , * kwargs )
200+ env = _get_asm_context ()
201+ try :
202+ if _get_rasp_capability ("ssrf" ) and response .__class__ .__name__ == "HTTPResponse" and env is not None :
203+ status = response .getcode ()
204+ if 300 <= status < 400 :
205+ # api10 for redirected response status and headers in urllib
206+ addresses = {
207+ "DOWN_RES_STATUS" : str (status ),
208+ "DOWN_RES_HEADERS" : _build_headers (response .getheaders ()),
209+ }
210+ call_waf_callback (addresses , rule_type = EXPLOIT_PREVENTION .TYPE .SSRF_RES )
211+ except Exception :
212+ pass # nosec
213+ return response
214+
215+
193216def _parse_http_response_body (response ):
194217 try :
195218 if response .length and response .headers .get ("content-type" , None ) == "application/json" :
@@ -228,7 +251,7 @@ def wrapped_open_ED4CF71136E15EBF(original_open_callable, instance, args, kwargs
228251 try :
229252 response = original_open_callable (* args , ** kwargs )
230253 # api10 response handler for regular responses
231- if response .__class__ .__name__ == "HTTPResponse" :
254+ if response .__class__ .__name__ == "HTTPResponse" and not ( 300 <= response . status < 400 ) :
232255 addresses = {
233256 "DOWN_RES_STATUS" : str (response .status ),
234257 "DOWN_RES_HEADERS" : _build_headers (response .getheaders ()),
@@ -271,7 +294,8 @@ def wrapped_urllib3_make_request(original_request_callable, instance, args, kwar
271294
272295 full_url = core .get_item ("full_url" )
273296 env = _get_asm_context ()
274- if _get_rasp_capability ("ssrf" ) and full_url is not None and env is not None :
297+ do_rasp = _get_rasp_capability ("ssrf" ) and full_url is not None and env is not None
298+ if do_rasp :
275299 use_body = core .get_item ("use_body" , False )
276300 method = args [1 ] if len (args ) > 1 else kwargs .get ("method" , None )
277301 body = args [3 ] if len (args ) > 3 else kwargs .get ("body" , None )
@@ -292,7 +316,18 @@ def wrapped_urllib3_make_request(original_request_callable, instance, args, kwar
292316 core .discard_item ("full_url" )
293317 if res and _must_block (res .actions ):
294318 raise BlockingException (get_blocked (), EXPLOIT_PREVENTION .BLOCKING , EXPLOIT_PREVENTION .TYPE .SSRF , full_url )
295- return original_request_callable (* args , ** kwargs )
319+ response = original_request_callable (* args , ** kwargs )
320+ try :
321+ if do_rasp and response .__class__ .__name__ == "BaseHTTPResponse" and 300 <= response .status < 400 :
322+ # api10 for redirected response status and headers in urllib3
323+ addresses = {
324+ "DOWN_RES_STATUS" : str (response .status ),
325+ "DOWN_RES_HEADERS" : response .headers ,
326+ }
327+ call_waf_callback (addresses , rule_type = EXPLOIT_PREVENTION .TYPE .SSRF_RES )
328+ except Exception :
329+ pass # nosec
330+ return response
296331
297332
298333def wrapped_urllib3_urlopen (original_open_callable , instance , args , kwargs ):
@@ -329,7 +364,7 @@ def wrapped_request_D8CB81E472AF98A2(original_request_callable, instance, args,
329364 # API10, doing all request calls in HTTPConnection.request
330365 try :
331366 response = original_request_callable (* args , ** kwargs )
332- if response .__class__ .__name__ == "Response" :
367+ if response .__class__ .__name__ == "Response" and not ( 300 <= response . status_code < 400 ) :
333368 addresses = {
334369 "DOWN_RES_STATUS" : str (response .status_code ),
335370 "DOWN_RES_HEADERS" : dict (response .headers ),
0 commit comments