Skip to main content

反连出网检测与内网穿透技术

yaklang.io 反连技术三板斧#

  1. 反连服务
  2. 多协议复用端口
  3. 内网穿透

反连服务是什么?为什么要做这种服务?#

很多时候,我们在进行漏洞检测时无法通过应用返回的信息来确定一个漏洞是否存在。但是如果命令/特殊操作确实执行了,那我们如何证明这个命令或者特殊操作执行了呢?

我们习惯性把这种漏洞检测技术称为:无回显的漏洞检测技术。

一般来说,无回显漏洞检测技术可以分为两种:

  1. sleep / benchmark 耗时操作检测。
  2. dnslog / http-reverse / tcp / tls / rmi 等服务外连检测。

严格来说,我并不觉得 sleep / benchmark 不算回显,耗时操作本来也算是可直接观测到的指标。除此之外,sleep / benchmark 将会引起服务器端各种各样的小问题:

  1. 如果服务器是单线程,sleep 将会造成阻塞,
  2. 如果服务器 CPU 不太行,benchmark 将会消耗资源
  3. 如果发生在数据库中,很多生产环境中的数据库会针对 SQL 语句执行做各种限制,例如:
    1. 认为超时的 SQL 语句为 badsql,直接切断当前查询进程
    2. SQL 连接池恶意占用会造成其他查询失败,甚至整体 down 机
  4. sleep 如果执行在了 for / while 分支中,将会造成 sleep 的时间远大于预期值,或者直接为 0。

相比之下,服务外连检测是一个更加 "稳妥" 的办法。

DNS 反连检测原理#

举个例子,服务外连时,我们执行 curl abc.example.com 命令:

  1. 这个时候,abc.example.com 将会被解析,会查询 abc.example.com 的 NS 记录和 A 记录
  2. 如果 NS 记录存在(ns1.example.com),会向 ns1.example.com 查询 abc.example.com 的 A 记录。
  3. 如果 NS 不存在,则直接向公共服务器启用 A 记录查询。

上述描述的过程中,如果我们可以控制 ns1.example.com 的话,任何用户查询的过程将会被记录下来。

当然,我们可以人为设置一个子域名,任何查询到这个子域名的被集合展示,这就是 dnslog.cn 的核心原理。

RMI / HTTP / TLS#

当然,在上面的例子中,我们 curl abc.example.com 如果可以找到对应的 IP,将会对 IP 发起一个 HTTP 请求。

这个请求的原始数据包和任何内容都可以被我们控制的反连服务器记录下来。

  1. 如果我们实现了 HTTP 协议,将会记录下 HTTP 相关的详细信息
  2. 如果我们实现了 RMI / LDAP / TLS 等,就可以记录下反连时携带的信息

这些信息对判断漏洞是否存在,或者收集一些敏感信息,例如 AWS_SECRET_KEY / ACCESS_KEY / SECRET_KEY 等很有用。

img.png

多协议复用端口:Facade 技术#

大家在上图可能注意到了一个有趣的现象,RMI 也好 HTTP/HTTPS 也好,我们都监听在了同一个端口上。

有同学问,这样真的不会有问题吗?

这个技术并不是什么高深的技术,端口复用其实是一个很简单的操作,不同协议的协议头是不一样的:

例如:

  1. TLS 协议要先进行 TLS 握手(handshake) 操作。在 TLS 握手时,我们将会识别到这是一个 TLS 握手操作,客户端把服务器当作一个 TLS 服务来判断,那么服务端将会自动返回 TLS 应该收到的东西。
  2. RMI 的协议头为 JRMI,当我们收到客户端发来这几个字节时,我们就应该回复 RMI 应该识别的内容
  3. 当然 HTTP 更简单了,对吧?

当然我们集合了常见的这几种协议,同时在一个端口上开启,早一段时间大家管这个技术叫 拟态其实也可以说是 yaklang.io 实现了 拟态 反连服务器。

我们给这个服务器起名叫 Facade

ous

如果两个协议的头完全一样,将会造成 Facade 服务器混淆协议。

当然这种情况其实比较稀有,如果有,也可以通过设置 Facade 识别协议缓存大小来处理,大家可以不必担心协议错误的问题。

协议复用除了方便,还有别的好处吗?#

在实战过程中,很多用户发现,虽然我们有些协议无法识别,但是 TCP 连接始终可以识别到,这样做是为了 "兜底"。

遇到了见不到的协议,但是反连确实连接回来了,虽然只是 TCP,但是用户至少知道目标存在一个反连问题,不是吗?

内网穿透:对标实现 ngrok 穿透#

很多时候,我们在进行扫描的时候,并不一定及时能搭配起一个公网服务器开启反连服务器。

就算公网服务器开启了反连服务,我们的漏洞 Payload 打出去并不一定及时能知道自己的服务器接收到了对应反连。

那么如何解决这个问题呢?当然,对于 yaklang.io 项目来说,最简单的就是在公网部署一个 yak 引擎。除此之外,还有别的解决办法吗?

熟悉 ngrok 的同学就会说,我们可以部署一个 ngrok 让本地的服务器在远端上线。

很多同学在使用 CS 上线节点的时候都这么操作。

于是,我们在 yak 中实现了一套机制,叫 cybertunnel, 使用 grpc 构建了一套端口穿透的技术,我们可以实现映射一个本地 tcp / udp 协议端口到远端。

甚至于说,我们都可以映射一个本地 dnslog 服务器到远端(远端需要域名提供商配置解析记录)

yak 引擎的穿透服务#

服务器配置#

当然,穿透服务是需要一个远端服务器打配合的

服务器上安装了 yak 核心引擎的话,使用 yak bridge 即可解决这个问题

yak bridge --secret [your-password]

如果只有 docker 环境,可以使用 https://github.com/yaklang/yak-bridge-docker/ 中的解决方案

docker run -d --rm --net=host v1ll4n/yak-bridge yak bridge --secret [your-awesome-password-for-u-bridge]

一条命令即可启动一个 yak bridge 服务器

yak 内网穿透客户端#

yak 用于穿透本地端口到 yak bridge 的时候,其实非常简单,我们执行 yak tunnel -h 即可看到如下帮助信息

➜  yak-engine yak tunnel -hNAME:   yak tunnel -
USAGE:   yak tunnel [command options] [arguments...]
OPTIONS:   --server value                  (default: "cybertunnel.run:64333")   --local-port value              (default: 53)   --remote-port value             (default: 53)   --secret value   --network value, --proto value  (default: "tcp")

其实配置非常简单

  1. --server 内容是我们启动的 yak bridge 的公网地址,[host/ip]:[port] 即可
  2. --local-port 是我们想要穿透的本地端口
  3. --remote-port 是我们想要穿透到 yak bridge 的远端端口
  4. --secret 是我们启动 yak bridge 时设置的密码
  5. --network 是说我们想要映射的本地端口的协议,同时支持 udp 和 tcp,因此我们可以把本地 dnslog 映射出去。

我们可以使用 yak tunnel 映射本地任何端口出去,包括 yak grpc,因此我们在内网进行渗透的时候,只要运行一个 yak grpc,再通过 yak tunnel 穿透出去,就可以使用 yakit 连接了!

yakit 的反连支持#

当然,除了 yak 支持的任意端口的映射之外,我们也可以支持 yakit 把反连服务器映射到远端。

对于 yakit 来说,减轻用户的操作负担其实是最核心的诉求。

img.png

在我们配置完成成功连接之后,所有内容将会保存到 yakit 的本地 ~/yakit-projects/base/yakit-local.json 文件夹中。

在之后每次启动 yakit 的时候,都会自动链接 yak bridge。无需手动再配置。。

info

yak bridge 只有端口映射与获取当前公网 IP 两个功能,并无其他功能,所以版本并不需要太高,只要支持 yak bridge 子命令均可运行。

融合:Yakit 插件与反连技术的完美融合#

当我们在 yakit 任意可执行插件的地方执行

url := risk.NewPublicReverseHTTPUrl(risk.title("反连服务器测试"), risk.type("测试反连"))println(url)rsp, err := http.Get(url)die(err)http.show(rsp)

我们发现我们得到了如下结果

代码其实非常简单,我们在任何需要检测漏洞的时候,如果需要获取反连 URL,特别是公网可以访问的 URL。

我们使用 risk.NewPublicReverseHTTPUrl / risk.NewPublicReverseRMIUrl / ... 等可以获取到一个可用的带 Token 的反连 URL。

把它作为 Payload 传入漏洞检测中,即可实现反连检测漏洞。

所有具体的 API 在这里可以找到

yaklang risk 反连检测套件