fingerprintx 源码学习
项目介绍
项目地址:https://github.com/praetorian-inc/fingerprintx
fingerprintx 是一款端口识别工具,支持协议如下:
SERVICE | TRANSPORT | SERVICE | TRANSPORT |
HTTP | TCP | REDIS | TCP |
SSH | TCP | MQTT3 | TCP |
MODBUS | TCP | VNC | TCP |
TELNET | TCP | MQTT5 | TCP |
FTP | TCP | RSYNC | TCP |
SMB | TCP | RPC | TCP |
DNS | TCP | OracleDB | TCP |
SMTP | TCP | RTSP | TCP |
PostgreSQL | TCP | MQTT5 | TCP (TLS) |
RDP | TCP | HTTPS | TCP (TLS) |
POP3 | TCP | SMTPS | TCP (TLS) |
KAFKA | TCP | MQTT3 | TCP (TLS) |
MySQL | TCP | RDP | TCP (TLS) |
MSSQL | TCP | POP3S | TCP (TLS) |
LDAP | TCP | LDAPS | TCP (TLS) |
IMAP | TCP | IMAPS | TCP (TLS) |
SNMP | UDP | Kafka | TCP (TLS) |
OPENVPN | UDP | NETBIOS-NS | UDP |
IPSEC | UDP | DHCP | UDP |
STUN | UDP | NTP | UDP |
DNS | UDP |
项目结构
1 |
|
源码学习
fingerprintx 的端口指纹识别是以插件的形式完成的,感觉很整齐,这种类型的项目看起来也很舒服:
这些识别插件都实现了插件接口:
1 |
|
这里的 PortPriority 表示的是端口优先权,比如 80 对应的是 http 服务,那么 http 识别插件的 PortPriority(80) 就会返回 true。
Priority 是端口优先级,如果优先权未识别出端口,那就会按照服务的优先级进行指纹识别。
很好的思路,而且这种思路使用了这样的写法,很整齐,之前的 go-Portscan 虽然也是这种思路,但是写法和 fingerprintx 比起来就有点乱。
先看一个指纹识别插件,这是 HTTP 包下面的,它实现了 HTTP 和 HTTPS 这里只留 HTTP 的写一下:
1 |
|
指纹识别和之前的 go-Portscan 略有不同,go-Portscan 是统一的,只分了协议、发送动作、接收判断规则。而 fingerprintx 则是对每种协议都做了处理,而且还会获取其详细信息,比如这里的 http 就会进行指纹识别。
再说一下 plugins.CreateServiceFrom 函数,上面说了他对很多规则都做了详细信息的获取函数,但是这些信息的结构是不同的,比如 HTTP 这里就是 plugins.ServiceHTTP 结构,看看 fingerprintx 是如果去处理:
1 |
|
Metadata 接口只有一个 Type 方法:
1 |
|
HTTP 的就是这个了:
1 |
|
再后面输出的时候,都直接调用的是 Service 接口的 Metadata 方法,其按照不同的数据格式进行对应的 json 序列化,这样就解决了输出 json 格式的问题:
1 |
|
然后再看看它具体的识别逻辑 simple_scan.go ,写的很清晰:
1 |
|
setupPlugins 这就是把 plugin_list.go 中 import 导入注册的插件进行分类、排序:
1 |
|
然后是识别的具体流程,很清晰,先遍历一圈,识别默认服务,然后再按照优先级进行指纹识别:
1 |
|
这里是遍历了 2 次,第一次是获取默认服务,第二次是去按照优先级全部扫一遍。这里感觉有些麻烦,可以向 go-Portscan 那样维护一个端口和默认服务的 map,这里就维护一个端口和插件的 map ,就不需要一直遍历获取默认服务插件了。
之后就是 simplePluginRunner 了,它其实就是调用插件的 Run 方法去识别:
1 |
|
学习总结
- fingerprintx 接口 插件,然后通过 import 导包去实现插件注册挺不错的