12

FRP 分析与改造

 1 year ago
source link: https://qftm.github.io/2022/12/10/frp-modify/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

客户端执行流程分析

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

image-20221130010957529
image-20221130010957529

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

image-20221130011153892
image-20221130011153892

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

加载配置文件

image-20221130012344726
image-20221130012344726

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

image-20221130012546011
image-20221130012546011

UnmarshalClientConfFromIni主要解析ini文件common项

image-20221130012848030
image-20221130012848030

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

image-20221130013534950
image-20221130013534950

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

image-20221130012344726
image-20221130012344726

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

image-20221130014456833
image-20221130014456833

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

image-20221130014709324
image-20221130014709324

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

image-20221130020153107
image-20221130020153107

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

image-20221130020838762
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
image-20221219103457696

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

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

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

image-20221219110753318
image-20221219110753318

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

10{"version":"0.45.0","run_id":"0fa0b38623bbd1bc"}
image-20221219110139262
image-20221219110139262

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

image-20221219113122184
image-20221219113122184

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

image-20221219151504432
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
image-20221219161108174

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

image-20221219162117382
image-20221219162117382

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

TLS特征

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

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

image-20221219164510545
image-20221219164510545

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

image-20221219234426393
image-20221219234426393
image-20221219234451534
image-20221219234451534

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

image-20221219234546161
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
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-20221207160929309
image-20221207225840162
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
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
image-20221130120211485

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

image-20221130120407556
image-20221130120407556

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

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

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

image-20221130122903800
image-20221130122903800

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

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

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

image-20221130172142520
image-20221130172142520

修改常量FrpWebsocketPath,重新编译

image-20221130175456231
image-20221130175456231

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

image-20221130181047095
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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK