DCSO/balboa
GitHub: DCSO/balboa
balboa 是一款被动 DNS 观测数据的索引与查询服务器,支持多源数据摄入、灵活过滤标记和 GraphQL/REST 接口查询。
Stars: 50 | Forks: 7
# 📑 balboa

[](https://goreportcard.com/report/github.com/DCSO/balboa)
balboa 是 BAsic Little Book Of Answers(基础小答案书)的缩写。它消费并索引来自[被动 DNS](https://www.farsightsecurity.com/technical/passive-dns/)采集的观测数据,并提供一个 [GraphQL](https://graphql.org/) 接口来访问观测数据库中的聚合内容。我们构建 balboa 来处理从 [Suricata](https://suricata-ids.org)收集的元数据中聚合的被动 DNS 数据。
该 API 应该适合集成到现有的多源可观测数据集成框架中。可以使用 GraphQL API(见下文)或兼容 [CIRCL](https://www.circl.lu/services/passive-dns/)的 REST API,以[通用输出格式](https://datatracker.ietf.org/doc/draft-dulaunoy-dnsop-passive-dns-cof/)兼容的 schema 来生成结果。
balboa 软件...
- 查询和输入/更新速度快
- 使用可插拔后端实现存储,后端可能位于单独的机器上
- 支持追踪和专门查询多个传感器
- 在查询和摄取时利用多核 CPU
- 同时接受来自多个源的输入
- HTTP (POST)
- AMQP
- Unix socket
- 网络 socket(仅限 NMSG 格式)
- 可以根据各种属性对观测数据进行标记和过滤
- 可以根据匹配的选择器将观测数据存储到一个或多个后端
- 接受多种输入格式
- 基于 JSON
- [FEVER](https://github.com/DCSO/fever)
- [gopassivedns](https://github.com/Phillipmartin/gopassivedns)
- [Packetbeat](https://www.elastic.co/guide/en/beats/packetbeat/master/packetbeat-dns-options.html)(通过 Logstash)
- [Suricata EVE DNS v1 和 v2](http://suricata.readthedocs.io/en/latest/output/eve/eve-json-format.html#event-type-dns)
- 平面文本文件
- Edward Fjellskål 的 [PassiveDNS](https://github.com/gamelinux/passivedns) 表格格式(默认顺序 `-f SMcsCQTAtn`)
- 二进制
- Farsight Security [NMSG 格式](https://www.farsightsecurity.com/txt-record/2015/01/28/nmsg-intro/)(通过网络 socket)
## 构建与安装
```
$ go get github.com/DCSO/balboa/cmd/balboa
...
```
这会将 `balboa` 可执行文件放入您的 Go bin 路径中。
构建后端:
```
$ cd $GOPATH/src/github.com/DCSO/balboa/backend
$ make
...
```
这会在每个后端目录的 `build/` 子目录中创建一个可执行二进制文件。
### 依赖项
- Go 1.10 或更高版本
- 对于内置的 RocksDB 后端:[RocksDB](https://rocksdb.org/) 5.0 或更高版本(共享库,支持 LZ4)
例如,在 Debian 上,可以通过以下方式满足这些依赖项:
```
% apt install golang-go librocksdb-dev
...
```
## 用法
### 配置 feeder
Feeder 用于将观测数据导入数据库。它们并发运行并在后台处理输入,一旦数据库中完成了最终的 upsert 事务,即可通过查询接口访问结果。要创建哪些 feeder 在 YAML 配置文件中定义(通过 `-f` 参数传递给 `balboa serve`)。示例:
```
feeder:
- name: AMQP Input
type: amqp
url: amqp://guest:guest@localhost:5672
exchange: [ tdh.pdns ]
input_format: fever_aggregate
- name: HTTP Input
type: http
listen_host: 127.0.0.1
listen_port: 8081
input_format: fever_aggregate
- name: Socket Input
type: socket
path: /tmp/balboa.sock
input_format: gopassivedns
```
给定此 feeder 配置的 balboa 实例将支持以下输入选项:
- 通过 AMQP 从临时队列传递的 FEVER 聚合格式 JSON,该队列附加在 `localhost` 端口 5762 上的交换机 `tdh.pdns` 中,使用用户 `guest` 和密码 `guest` 进行身份验证
- 从本地系统端口 8081 上的 HTTP POST 请求中解析的 FEVER 聚合格式 JSON
- gopassivedns 格式的 JSON,输入到由 balboa 创建的 UNIX socket `/tmp/balboa.sock` 中
所有这些 feeder 同时接受输入,不区分观测数据的来源。只要它们的 `name` 唯一,就可以指定多个相同类型但设置不同的 feeder。
### 配置选择器
Balboa 提供了一个选择器引擎,可用于选择或过滤观测数据。
选择器引擎在 YAML 文件中进行配置,该文件通过 `-s` 参数提供给 balboa。
可用的选择器实现:
* regex:使用一个或多个选择器匹配观测数据的 `RRNAME` 字段
* lua:使用 lua 脚本处理观测数据,有关示例,请参见 *selector.lua*
示例:
```
selectors:
- name: Filter Unwanted TLDs
type: regex
mode: filter
regexp:
- unwanted_regex.txt
tags:
- filtered_tlds
- name: CobaltStrike Regex
type: regex
mode: select
regexp:
- cobaltstrike_regex.txt
ingest:
- filtered_tlds
tags:
- possible_cobaltstrike
```
此配置会将所有**未**被 `unwanted_regex.txt` 中的正则表达式匹配到的观测数据打上 `filtered_tlds` 标签。
所有标记为 `filtered_tlds` 且匹配 `cobaltstrike_regex.txt` 中一个或多个正则表达式的观测数据,都会被标记为 `possible_cobaltstrike`。
### 配置数据库后端
支持多个数据库后端来持久化存储 pDNS 观测数据。每个数据库后端都作为一个独立的二进制(可执行文件)提供。前端只连接到一个数据库后端。但是,后端支持多个客户端或前端连接。
每个后端可以配置为处理所有观测数据(没有 `tags` 参数)或处理一系列标签列表(条件或)。
后端配置在 YAML 文件中定义(通过 `-b` 参数传递给 `balboa server`)。示例:
```
- name: cobaltstrike
host: "localhost:4242"
tags:
- possible_cobaltstrike
- name: all filtered observations
host: "localhost:4343"
tags:
- filtered_tlds
```
具有此后端配置的 balboa 实例会将所有标记为 `possible_cobaltstrike` 的事件存储到监听端口为 `localhost:4242` 的后端中,并将所有标记为 `filtered_tlds` 的事件存储到 `localhost:4343` 上的后端中。
### 运行后端和前端服务并消费输入
所有在命令行上与前端的交互都是通过 `balboa` 前端可执行文件进行的。前端依赖于后端服务,这通常是其独立的可执行文件。
例如,可以使用以下命令启动 RocksDB 后端:
```
$ balboa-rocksdb -h
`balboa-rocksdb` provides a pdns database backend for `balboa`
Usage: balboa-rocksdb [options]
-h display help
-D daemonize (default: off)
-d path to rocksdb database (default: `/tmp/balboa-rocksdb`)
-l listen address (default: 127.0.0.1)
-p listen port (default: 4242)
-v increase verbosity; can be passed multiple times
-j thread throttle limit, maximum concurrent connections (default: 64)
--membudget rocksdb membudget option (value: 134217728)
--parallelism rocksdb parallelism option (value: 8)
--max_log_file_size rocksdb log file size option (value: 10485760)
--max_open_files rocksdb max number of open files (value: 300)
--keep_log_file_num rocksdb max number of log files (value: 2)
--database_path same as `-d`
--version show version thenp exit
$ balboa-rocksdb --database_path /data/pdns -l 127.0.0.1 -p 4242
```
启动后端后,可以按如下方式启动 `balboa` 前端:
```
$ balboa serve -l ''
INFO[0000] starting feeder AMQPInput2
INFO[0000] starting feeder HTTP Input
INFO[0000] accepting submissions on port 8081
INFO[0000] starting feeder Socket Input
INFO[0000] starting feeder Suricata Socket Input
INFO[0000] ConsumeFeed() starting
INFO[0000] serving GraphQL on port 8080
...
```
启动后,即可使用 feeder 进行数据摄取。例如,可以执行以下一些操作来测试数据消费(假设使用了上述 feeder):
- 对于 AMQP:
$ scripts/mkjson.py | rabbitmqadmin publish routing_key="" exchange=tdh.pdns
...
- 对于 HTTP:
$ scripts/mkjson.py | curl -d@- -qs --header "X-Sensor-ID: abcde" http://localhost:8081/submit
...
- 对于 socket:
$ sudo gopassivedns -dev eth0 | socat /tmp/balboa.sock STDIN
...
### 查询服务器
与服务器交互的预期主要接口是通过 GraphQL。例如,查询
```
query {
entries(rrname: "test.foobar.de", sensor_id: "abcde", limit: 1) {
rrname
rrtype
rdata
time_first
time_last
sensor_id
count
}
}
```
将返回类似如下内容
```
{
"data": {
"entries": [
{
"rrname": "test.foobar.de",
"rrtype": "A",
"rdata": "1.2.3.4",
"time_first": 1531943211,
"time_last": 1531949570,
"sensor_id": "abcde",
"count": 3
}
]
}
}
```
这也适用于将 `rdata` 作为查询参数,但必须至少声明 `rrname` 或 `rdata` 中的一个。如果没有 `sensor_id` 参数,则无论 DNS 应答是在哪里观测到的,都会返回所有结果。
请分别使用 `time_first_rfc3339` 和 `time_last_rfc3339` 而不是 `time_first` 和 `time_last`,以获取人类可读的时间戳。
当配置了多个后端时,查询将被分发给每个后端。
因此,当观测数据存储在多个后端中时,查询结果将包含重复项。
### 别名
有时,查询所有解析为相同 IP 地址的域名会很有趣。出于这个原因,GraphQL API 支持一个虚拟的 `aliases` 字段,该字段会返回所有 RRType 为 `A` 或 `AAAA` 且在 Rdata 字段中共享相同地址的条目 (Entry)。
示例:
```
{
entries(rrname: "heise.de", rrtype: A) {
rrname
rdata
rrtype
time_first_rfc3339
time_last_rfc3339
aliases {
rrname
}
}
}
```
```
{
"data": {
"entries": [
{
"rrname": "heise.de",
"rdata": "193.99.144.80",
"rrtype": "A",
"time_first_rfc3339": "2018-07-10T08:05:45Z",
"time_last_rfc3339": "2018-10-18T09:24:38Z",
"aliases": [
{
"rrname": "ct.de"
},
{
"rrname": "ix.de"
},
{
"rrname": "redirector.heise.de"
},
{
"rrname": "www.ix.de"
}
]
}
]
}
}
```
### 批量查询
还有一个快捷工具可以使“批量”查询变得更容易。例如,要获取传感器 `abcde` 观测到的范围 1.2.0.0/16 内主机的所有信息,可以使用:
```
$ balboa query --sensor abcde 1.2.0.0/16
{"count":6,"time_first":1531943211,"time_last":1531949570,"rrtype":"A","rrname":"test.foobar.de","rdata":"1.2.3.4","sensor_id":"abcde"}
{"count":1,"time_first":1531943215,"time_last":1531949530,"rrtype":"A","rrname":"baz.foobar.de","rdata":"1.2.3.7","sensor_id":"abcde"}
```
请注意,此工具目前实际上只是执行了大量并发的独立查询!为了在这些情况下提高性能,未来可能值得考虑同样允许在服务器端进行范围查询。
### 其他工具
运行不带参数的 `balboa` 以列出可用的子命令,并获取有关其作用的简短说明。
另请参见 `backend` 目录中的 `README.md`。
## 作者/联系方式
Sascha Steinbiss
## 许可证
BSD-3-clause
标签:Go, GraphQL, IP 地址批量处理, rizin, Ruby工具, 便携式工具, 威胁情报, 客户端加密, 开发者工具, 数据索引, 日志审计, 网络安全, 被动DNS, 隐私保护