diff --git a/README.md b/README.md index 447d512..c097aba 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,23 @@ repair_these_headers: ``` +### Remove problematic Response Headers + +With Cobalt Strike 4.7+ I noticed that Teamserver removes Content-Encoding header automatically without any notice, thus violating our malleable `http-(get|post).server` contract. + +Since RedWarden followed the contract, Beacon was either dropping responses or decompressing them incorrectly. + +This option specifies which headers coming from Teamserver responses should be removed before reaching Beacon process: + +```yaml + +remove_these_response_headers: + - Content-Encoding +``` + +RedWarden will now remove `Content-Encoding` header by default from Teamserver responses, to maintain operability with CS4.7+ versions. + + ### Example outputs Let's take a look at the output the proxy produces. diff --git a/lib/proxyhandler.py b/lib/proxyhandler.py index ee241f9..97ba76d 100644 --- a/lib/proxyhandler.py +++ b/lib/proxyhandler.py @@ -794,20 +794,6 @@ def __init__(self, req, origreq): newuri = self.request.uri self.request.uri = origuri - reskeys = [x.lower() for x in res.headers.keys()] - - # if content_encoding == 'identity' and 'content-encoding' in reskeys: - # self.logger.dbg('Removed Content-Encoding response header.') - # del res.headers['Content-Encoding'] - - if plugins.IProxyPlugin.proxy2_metadata_headers['remove_response_headers'] in reskeys: - hdrs = res.headers[IProxyPlugin.proxy2_metadata_headers['remove_response_headers']] - self.logger.dbg('Removing these response headers: ' + hdrs) - - hdrsList = hdrs.split(',') - for h in hdrsList: - del res.headers[h] - if type(modified) == bool: modified |= (newuri != origuri) diff --git a/plugins/malleable_redirector.py b/plugins/malleable_redirector.py index 932b2a6..67972e6 100644 --- a/plugins/malleable_redirector.py +++ b/plugins/malleable_redirector.py @@ -966,10 +966,6 @@ def redirect(self, req, _target, malleable_meta): req.headers[proxy2_metadata_headers['ignore_response_decompression_errors']] = "1" req.headers[proxy2_metadata_headers['override_host_header']] = newhost - if 'remove_these_response_headers' in self.proxyOptions.keys() and len(self.proxyOptions['remove_these_response_headers']) > 0: - removeThese = ','.join([x.lower() for x in self.proxyOptions['remove_these_response_headers']]) - req.headers[proxy2_metadata_headers['remove_response_headers']] = removeThese - if 'host' in malleable_meta.keys() and len(malleable_meta['host']) > 0: req.headers[proxy2_metadata_headers['domain_front_host_header']] = malleable_meta['host'] @@ -1193,6 +1189,15 @@ def _response_handler(self, req, req_body, res, res_body): # return the response as-is, in an "Content-Encoding: identity" kind of fashion res.headers[proxy2_metadata_headers['override_response_content_encoding']] = 'identity' + if 'remove_these_response_headers' in self.proxyOptions.keys() and len(self.proxyOptions['remove_these_response_headers']) > 0: + hdrs = ','.join([x.lower() for x in self.proxyOptions['remove_these_response_headers']]) + self.logger.dbg('Removing these response headers: ' + hdrs) + + hdrsList = hdrs.split(',') + + for h in hdrsList: + del res.headers[h] + req.connection.no_keep_alive = False return res_body