FRP 0.38.0 流量加密分析
FRP是一款开源的轻量级反向代理工具,可快速、稳定地代理NAT或者防火墙后面的服务,应用较为广泛。其使用Go语言编写,具备很好的跨平台特性。
FRP仓库地址:https://github.com/fatedier/frp
由于网络上几乎没有分析frp协议及其加密机制的文章,而且frp每个版本的加密逻辑还不一样(例如0.38.0与0.52.0),笔者跟了一遍源码,简单记下这篇文章,供相关从业者参考。
##结论
- 加密算法:
AES-CFB
- iv:首次发送报文时向对方传递
- salt:固定盐值
- 会话密钥:用配置文件里的
token
以pbkdf2
算法派生
分析过程
首先下载源码,搜索关键字encrypt
,发现一处可能与加密相关的地方,跟进去。
发现引用了frpIo这个包,而这个包是从github引用,去它仓库克隆下代码来。
很明显WithEncryption
就是加密逻辑的入口:传入密钥,对读写函数进行封装。
跟进NewReader()
函数,找到具体的加密逻辑:
+ 第一步,使用pbkdf2
算法从主密钥派生出会话密钥。需要的参数及寻找位置如下:
+ 主密钥:从frp代码的/server/control.go
中发现,主密钥就是serverCfg.Token
,也就是我们配置文件frps.ini
Common中的token
字段。
+ 盐值:从frp代码的/server/main.go
入口函数中找到,默认是"frp"
。
+ 迭代次数:固定64。
+ 输出长度:与aes每个block长度一致,默认为16字节。
+ 哈希函数:固定为sha1。
+ 第二步,生成iv向量。虽然代码注释上写着“random iv”,但查看代码发现,iv只初始化了大小,没有赋值,因此固定是16字节的0.**当时狠狠坑了我好长时间**
+ 第三步,AES CFB加密。这点需要了解基础的密码学常识,在CFB模式下首部不能有多余字符,否则分组错乱,整个密文解开都是错的。而在抓包分析时,经常有使用0或者其他标志填充首部,这点也容易导致解密失败。**编写解密脚本时需要注意。**
解密脚本编写
到此为止,整个加密逻辑就很清楚了。可以参照源码,用go编写解密脚本如下:
1 | func Decrypt(token, ciphertext, iv []byte) ([]byte, error) { |
总结
总结来说,frp是用配置文件里的token
以pbkdf2
算法派生会话密钥;首次发送报文时向对方传递iv
;使用固定值作为salt
;采用AES-CFB模式对流量进行加密。
FRP 0.38.0 流量加密分析