热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

内网渗透代理之frp的应用与改造(一)

 

 

0x0 前言

在内网渗透中,通常为了团队协作和代理的稳定性,我会选择一个合适且持久的沦陷主机来通过docker一键搭建OpenVPN,但是对于通过钓鱼等方式获取到window工作机器,用来搭建OpenVPN显然是不太方便(个人觉得过于笨重,安装麻烦且容易被发现),所以当时自己就在网上物色一些比较轻便、稳定、高速且支持socks代理的工具来满足自己的场景需求。

 

0x1 前置知识



0x1.1 socks 协议


socks是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递。SOCKS是”SOCKetS”的缩写。

当防火墙)后的客户端要访问外部的服务器时,就跟SOCKS代理服务器连接。这个代理服务器控制客户端访问外网的资格,允许的话,就将客户端的请求发往外部的服务器。

这个协议最初由David Koblas开发,而后由NEC的Ying-Da Lee将其扩展到SOCKS4。最新协议是SOCKS5,与前一版本相比,增加支持UDP、验证,以及IPv6。

根据OSI模型,SOCKS是会话层的协议,位于表示层与传输层之间。

SOCKS协议不提供加密

可以简单理解为socks是一种代理协议,处于中介的角色,被大多数软件所支持,支持多种协议的数据转发。


0x1.2 kcp协议


KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据的发送方式,以 callback的方式提供给 KCP。连时钟都需要外部传递进来,内部不会有任何一次系统调用。
TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。

可以简单理解为基于udp的KCP协议就是在保留UDP高传输速度的同时尽可能地提高了可靠性。

 

0x2 frp的使用

通过阅读frp的说明文档,可以知道frp支持相当多的功能,有兴趣的可以自行挖掘一下。

这里只说明下自己在内网渗透中最常使用的配置,主要涉及到稳定性和加密两个点。


0x2.1 kcp模式对比

在网络环境比较差的时候,使用kcp能够有效提高传输效率。

(1) 没有开启kcp模式

frps.ini

[common]
bind_addr = 0.0.0.0
bind_port = 7000
# IP 与 bind_addr 默认相同,可以不设置
# dashboard_addr = 0.0.0.0
# 端口必须设置,只有设置web页面才生效
dashboard_port = 7500
# 用户密码保平安
dashboard_user = xq17
dashboard_pwd = admin888
# 允许客户端绑定的端口
#allow_ports = 40000-50000

frpc.ini

[common]
server_addr = 101.200.157.195
server_port = 7000
[plugin_socks5]
type = tcp
remote_port = 6005
plugin = socks5
plugin_user = abc
plugin_passwd = abc

image-20200811150423808

(2) 开启KCP

frps.ini [common] 下添加 kcp_bind_port参数即可

[common]
bind_addr = 0.0.0.0
bind_port = 7000
# 开启kcp模式
kcp_bind_port = 7000
# IP 与 bind_addr 默认相同,可以不设置
# dashboard_addr = 0.0.0.0
# 端口必须设置,只有设置web页面才生效
dashboard_port = 7500
# 用户密码保平安
dashboard_user = xq17
dashboard_pwd = admin888
# 允许客户端绑定的端口
#allow_ports = 40000-50000

frpc.ini [common]下添加protocol=kcp即可

[common]
server_addr = 101.200.157.195
# kcp监听的端口
server_port = 7000
protocol = kcp
[plugin_socks5]
type = tcp
remote_port = 6005
plugin = socks5
plugin_user = abc
plugin_passwd = abc

image-20200811152458269

可以看到无论在下载还是延迟上都有了很大的优化,由于支持端口复用, 就算环境不支持kcp也不会出错,所以这个选项建议默认开启。


0x2.2 TLS 加密模式对比

从 v0.25.0 版本开始 frpc 和 frps 之间支持通过 TLS 协议加密传输。通过在 frpc.inicommon 中配置 tls_enable = true 来启用此功能,性更高。

为了端口复用,frp 建立 TLS 连接的第一个字节为 0x17。

通过将 frps.ini 的 [common]tls_only 设置为 true,可以强制 frps 只接受 TLS 连接。

注意: 启用此功能后除 xtcp 外,不需要再设置 use_encryption。

(1) 没有开启TLS加密

当没有开启TLS加密的时候,我们可以用WireShark抓包分析一下流量。

规则: ip.dst == 101.200.157.195 || tcp.port == 7000 || udp.port == 7000

由于开启了KCP所以抓到的包走的是UDP协议。

image-20200811163801177

通过观测udp stream, 可以看到:

image-20200811165158589

前面4次udp数据报可以看到client和Server进行版本、任务信息的校鉴过程。

我们尝试使用socks5的插件请求https://www.speedtest.cn/ 这个网站进行测速,然后观察wireshark的流量情况。

查看Firefox 使用socks5的流量规则: tcp.port == 6006

image-20200812113703355

可以看到的确进行了socks的用户和密码检验,这里不知道是不是客户端的原因, wireshark没识别出socks5的协议,导致我们不能很直观地看出对应字段的表示的内容。

直接跟踪流

image-20200812113854763

可以看到信息发送和返回都是明文传输的,这个其实关系不大,因为这些信息是暴露在我们这边,我们再分析下client端的数据交互。

image-20200812121718046

可以看到前面几个包都是再进行一些数据交换,其中出现了很多特定特征,我们可以跟踪udp stream

image-20200812121840384

其中数据也没有进行加密

image-20200812122143887

在这种代理模式下,是很容易被拦截的,数据传输安全得不到保证。

(2) 开启TLS加密

只需在frpc.ini 的 [common] 中配置tls_enable = true 来启用此功能

[common]
server_addr = 101.200.157.195
server_port = 7000
protocol = kcp
tls_enable = true
[plugin_socks5]
type = tcp
remote_port = 6006
plugin = socks5
plugin_user = abc
plugin_passwd = abc

我们再通过wireshark看下流量的情况:

image-20200812125119948

可以看到整个流量过程都已经被加密了。

image-20200812125608410

网络传输的质量保持也良好,不过出现了比较多EOF的错误,不知道是否会对某些情况产生影响。

image-20200812125736810


0x2.3 负载均衡

如果我们同时拿到了多台内网机器,为了进一步提高代理的稳定性,同时也希望避免沦陷主机资源负载过高等异常情况。我们可以考虑使用frp的负载均衡的配置来分担流量,同时开启frp自带的健康检查,避免出现服务单点故障,从而实现高可用架构的稳定代理。

查阅相关文档,得知其用法:

image-20200812100722183

server: frps.ini

[common]
bind_addr = 0.0.0.0
bind_port = 7000
kcp_bind_port = 7000
# IP 与 bind_addr 默认相同,可以不设置
# dashboard_addr = 0.0.0.0
# ,只有设置web页面才生效
dashboard_port = 7500
# 用户密码保平安
dashboard_user = xq17
dashboard_pwd = admin888

client1: frpc.ini

[common]
server_addr = 101.200.157.195
# kcp监听的端口
server_port = 7000
protocol = kcp
[client_socks5_one]
type = tcp
remote_port = 6005
plugin = socks5
# 启用健康检查,类型为 tcp
health_check_type = tcp
# 建立连接超时时间为 3 秒
health_check_timeout_s = 3
# 连续 3 次检查失败,此 proxy 会被摘除
health_check_max_failed = 3
# 每隔 10 秒进行一次健康检查
health_check_interval_s = 10
# 负载均衡配置客户组
group = load_balance
group_key = 123

client2: frpc.ini

[common]
server_addr = 101.200.157.195
# kcp监听的端口
server_port = 7000
protocol = kcp
[client_socks5_two]
type = tcp
remote_port = 6005
plugin = socks5
# 启用健康检查,类型为 tcp
health_check_type = tcp
# 建立连接超时时间为 3 秒
health_check_timeout_s = 3
# 连续 3 次检查失败,此 proxy 会被摘除
health_check_max_failed = 3
# 每隔 10 秒进行一次健康检查
health_check_interval_s = 10
# 负载均衡配置客户组
group = load_balance
group_key = 123

image-20200812104057060

image-20200812104115938

可以看到流量被平均分配到了两个负载的机器上:

image-20200812103727138

 

0x3 frp client执行流程分析

这里主要分析客户端: frp/cmd/frpc/main.go

从入口开始跟起:

image-20200812143152141

可以发现处理参数使用的是 cobra库

image-20200812150857543

在这里定义了持久的参数,其中cfgFile默认值是./frpc.ini, 通过阅读文档,RunE 获取函数后对函数进行操作的函数

image-20200812190321613

跟进runClient

image-20200812193301252

首先加载配置文件内容给content,然后parseClientCommonCfg对配置文件内容进行解析,我们看下解析的规则

image-20200812193504890

跳过一些中间函数

image-20200812193755745

image-20200812194723804

可以看到配置文件中的内容安装key装进了cfg里面,后面这句就是加载自己定义配置

pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(cfg.User, content, cfg.Start)

image-20200812195712089

原理差不多,也是只提取定义好的key然后装进cfg

image-20200812195804364

解析完所有配置文件到cfg,真正开始启动服务

err = startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)

其中pxyCfgs主要存放的内容就是我们添加的插件的配置,

image-20200813162409307

接着会尝试登陆到服务器,然后返回conn和session

image-20210210170740804

image-20210210171637995

然后开始进去ConnectServerByProxyWithTLS->ConnectServerByProxy

和服务器尝试建立连接:

image-20210210171819342

这里就开始建立tcp的连接:

image-20210210171922835

然后用建立好的连接,发了个0x17的字符,代表等下要建立tls加密传输,然后进入了

image-20210210172622864

然后tls.client重新封装的net.conn为tls.conn,作为后续的tls交互使用

image-20210210172858498

然后后面就是利用fmux继续封装,用来实现多路复用,返回cOnn=stream,用来后续的链接

image-20210210173027431

…因为有链接时超时的限制,这里我们直接跟下一个关键断点.

image-20210210174424572

这里主要是yamux建立应用流通道时基于tcp的交互。

最后发送登录信息给服务端完成:

image-20210210185833352

 


推荐阅读
author-avatar
mobiledu2502861133
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有