FRP 分析与改造


FRP 因其功能丰富,红队攻击者常将其用在内网渗透中,但是 FRP 在实际红蓝对抗中存在很多特征,导致被蓝队发现并溯源。

下面通过对 FRP 0.45.0 版本进行分析,提取特征并进行规避。

客户端执行流程分析

客户端入口:cmd/frpc/main.go

image-20221130010957529

命令行参数处理使用的是 cobra 库,初始化,其中cfgFile默认值是./frpc.ini

image-20221130011153892

rootCmd,判断cfgDir,进入runClient(cfgFile)

加载配置文件

image-20221130012344726

解析配置文件,读取配置文件内容给content,UnmarshalClientConfFromIni进行第一次解析赋值给cfg、content备份的buffer给LoadAllProxyConfsFromIni进行第二次解析

image-20221130012546011

UnmarshalClientConfFromIni主要解析ini文件common项

image-20221130012848030

LoadAllProxyConfsFromIni主要解析ini文件所有的proxy代理项

image-20221130013534950

解析完所有的ini文件配置,开始真正启动服务 startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)

image-20221130012344726

跟进startService,NewService建立服务,svr.Run开始运行

image-20221130014456833

Run()函数内svr.login()尝试登陆到frps服务端,返回conn和session

image-20221130014709324

login()函数,首先检测TLSEnable是否开启,后面开始建立TCP连接,用建立好的连接,发了个0x17的字符,代表等下要建立tls加密传输

image-20221130020153107

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

image-20221130020838762

流量特征修改

基础通信分析

客户端frpc common基础配置

[common]
server_addr = 8.219.248.226
server_port = 2086

[plugin_socks5]
type = tcp
remote_port = 7070
plugin = socks5
plugin_user = admin
plugin_passwd = 123456

frpc启动时,如果客户端[common]未指定协议protocol,则默认使用TCP协议

image-20221219103457696

TCP三次握手建立连接后,开始向服务端发送认证信息

o{"version":"0.45.0","os":"darwin","arch":"arm64","privilege_key":"cacaf2489774a4c69abe80dc57ac5486","timestamp":1671416534,"pool_count":1}

image-20221219104546417

服务端frps接收客户端认证信息,并启动代理插件监听

image-20221219110753318

服务端也会通过TCP协议返回一些信息 version、run_id

10{"version":"0.45.0","run_id":"0fa0b38623bbd1bc"}

image-20221219110139262

客户端显示认证成功的信息和代理情况

image-20221219113122184

在其他主机上配置代理测试访问,当frps收到代理转发请求后,frps服务端会将代理信息(代理插件名、地址、端口、认证等)及代理转发请求数据传送给frpc客户端

image-20221219151504432

基础流量特征

上面客户端连接认证及代理转发过程分析,通过在frpc客户端抓包分析,其中流量特征主要包括两点

  • 客户端连接认证时,双方三次握手建立TCP通信后传递的一些特定格式的登陆信息
  • 客户端代理转发请求时,收到服务端传递的一些特定格式的代理信息

上述特征清理,可开启TLS加密TCP通信内容。

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

[common]
server_addr = 8.219.248.226
server_port = 2086
tls_enbale = true

[plugin_socks5]
type = tcp
remote_port = 7070
plugin = socks5
plugin_user = admin
plugin_passwd = 123456

重新启动frpc客户端,此时双方建立连接后的通信TCP数据流内容已加密

image-20221219161108174

测试frpc客户端代理转发服务端代理请求情况,可看到TCP数据流内容已加密

image-20221219162117382

除了使用tls_enable = true外,还可继续使用use_encryption = trueuse_compression = true进行二次处理。

TLS特征

当开启TLS加密通信内容时,由于 frp 为了端口复用,建立 TLS 连接的第一个字节默认为 0x17,导致开启TLS流量特征明显。

客户端建立TLS发起第一个数据包Client Hello之前,默认会发送一个一字节大小的TCP通信数据

image-20221219164510545

修改TLS默认字节,定位源码pkg/util/net/tls.gopkg/util/net/dial.go,修改如下5处

image-20221219234426393

image-20221219234451534

测试效果,默认一字节0x17变为自定义五字节0x11 0x23 0x66 0x46 0x15

image-20221219234546161

配置文件优化

frpc客户端启动需要指定frpc.ini配置文件,默认frpc配置文件为frpc.ini,同时frpc启动后frpc.ini会保留在目标机子上。

那么,针对frpc配置文件的优化主要包含两点

  • 配置文件的文件名及后缀可自定义
  • frpc运行自删除配置文件

针对frpc运行自删除配置文件,在cmd/frpc/sub/root.go里面进行修改,第一步,在init()函数中添加frpc启动参数

rootCmd.PersistentFlags().BoolVarP(&delCfgFile, "delete", "d", false, "delete config file of frpc")

image-20221201004716813

第二步,在startService()函数中添加判断delCfgFile参数是否开启,如果开启则删除frpc配置文件

    if delCfgFile {
        errs := os.Remove(cfgFile)
        if errs != nil {
            log.Warn("delete config file of frpc fail\n")
        } else {
            log.Info("delete config file of frpc success\n")
        }
    }

image-20221207160929309

效果

image-20221207225840162

CDN域前置

frpc域前置CDN一般结合websocket协议使用,自frp0.21.0及之后支持websocket协议(仅支持ws协议,不支持wss协议)。

WebSocket

测试域前置,客户端frpc common配置

[common]
server_addr = 101.42.233.208
server_port = 2086
protocol = websocket

[plugin_socks5]
type = tcp
remote_port = 7070
plugin = socks5
plugin_user = admin
plugin_passwd = 123456

frpc启动时,如果客户端协议为websocket则会通过先发送http请求进行ws协议切换

image-20221130121210383

然后通过websocket协议向服务端发送认证信息

o\000\000\000\000\000\000\000�{"version":"0.45.0","os":"darwin","arch":"arm64","privilege_key":"aa879aa8dbec993816aa42a498c19069","timestamp":1669782153,"pool_count":1}

wireshark字符串搜索Display filter可以搜索Websocket内的字符串,搜索语句为 data-text-lines contains "darwin"

image-20221130120211485

服务端frps接收客户端认证信息

image-20221130120407556

服务端也会通过ws协议返回一些信息 version、run_id

1\000\000\000\000\000\000\0000{"version":"0.45.0","run_id":"a7bca8b1e7386bdb"}

image-20221130122735133

客户端显示认证成功的信息

image-20221130122903800

上面客户端连接认证过程分析,通过在frpc客户端抓包分析,其中流量特征主要包括两点

  • 客户端连接认证服务端时ws协议切换发起的特定http uri请求(/~!frp)
  • 双方建立WebsSocket通信后传递的一些特定格式的登陆信息

第一处特征清理,修改frp建立WebSocket时请求的路径

image-20221130172142520

修改常量FrpWebsocketPath,重新编译

image-20221130175456231

第二处特征清理,开启TLS加密WebSocket通信内容

image-20221130181047095

网上有人改版frp websocket适配CDN,新增配置 websocket_domain 为了满足在国内云厂商CDN上抢注的可信域名(server_addr=api.baidu.com.dnsv1cdn.cn、websocket_domain=api.baidu.com,websocket_domain为Http包内的Host头),目前国内云厂商都需要验证域名所属和备案已无法抢注。

WebSocket Secure

Web Socket 使用 TLS 即可实现等同 Web Socket Secure 效果。

References


Author: Qftm
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Qftm !
 Current
FRP 分析与改造 FRP 分析与改造
FRP 因其功能丰富,红队攻击者常将其用在内网渗透中,但是 FRP 在实际红蓝对抗中存在很多特征,导致被蓝队发现并溯源。 下面通过对 FRP 0.45.0 版本进行分析,提取特征并进行规避。 客户端执行流程分析客户端入口:cmd/frpc/
2022-12-10
Next 
Java安全详谈-JNI 底层分析 Java安全详谈-JNI 底层分析
JNI (Java Native Interface,JAVA 本地接口) 允许 Java 代码和其它编程语言编写的代码进行交互,主要为Java和Native层(C/C++)相互调用的接口规范
2022-05-29
  TOC