Rapid7的开源数据项目所拥有的数据种类和数据量是非常惊人的。任何人都可以从网络上下载这些早已被压缩,方便下载的数据。而这篇文章将集中讨论项目中的以下两个数据集,主要涉及DNS记录:
https://opendata.rapid7.com/sonar.rdns_v2/ (rdns)
https://opendata.rapid7.com/sonar.fdns_v2/ (fdns_a)
不幸的是,如果你是初次使用,想查询某条DNS记录,那么你的查询速度会很慢。因为这两个数据集都包含超过10GB的压缩文本,一般查询数据的方法效率都不会太高:
ubuntu@client:~$ time gunzip -c fdns_a.json.gz | grep "erbbysam.com"
{"timestamp":"1535127239","name":"blog.erbbysam.com","type":"a","value":"54.190.33.125"}
{"timestamp":"1535133613","name":"erbbysam.com","type":"a","value":"104.154.120.133"}
{"timestamp":"1535155246","name":"www.erbbysam.com","type":"cname","value":"erbbysam.com"}
real11m31.393s
user12m29.212s
sys 1m37.672s
我觉得有必要想出一种更快的方法来进行数据搜索。
(TLDR、反转和排序域名,然后进行二元搜索)
DNS架构
DNS的一个特征是它的树形结构。一个普通的URL,根域下面往往有三层:
com
com.erbbysam
com.erbbysam.blog
如果你想用grep查询根域下的某个域名,我们可以先将数据集统一整合成一个DNS树形结构,这样查询的时候只需要快速遍历这个树即可。
二元搜索
使用二元搜索算法还可以进一步对大型数据集转换为树型结构以及遍历树型数据这两个任务进行简化。
二元搜索算法的第一步是对数据进行排序。注意,由于上面所提及的域名数据格式是“com.erbbysam.blog”。为了减轻排序难度,请如下所示反转每一个数据:
moc.masybbre.golb,521.33.091.4
moc.masybbre,331.021.451.40
moc.masybbre.www,moc.masybbre
其次,因为文件过大,所以如果要对这些大文件进行排序,请将数据先拆分为小文件,小文件先内部排序,最后将结果合并到一起:
# 提取fdns_a文件
wget -O fdns_a.gz
https://opendata.rapid7.com/sonar.fdns_v2/2019-01-25-1548417890-fdns_a.json.gz
# 提取并格式化我们所需的数据
gunzip -c fdns_a.gz | jq -r '.value + ","+ .name' | tr '[:upper:]' '[:lower:]' | rev > fdns_a.rev.lowercase.txt
# 数据切割分片
split -b100M fdns_a.rev.lowercase.txt fileChunk
# 删除旧文件
rm fdns_a.gz
rm fdns_a.rev.lowercase.txt
# 分割后产生的数据文件继续排序
for f in fileChunk*; do LC_COLLATE=C sort "$f" > "$f".sorted && rm "$f"; done
# 将已排序的文件结合在一起
mkdir -p sorttmp
LC_COLLATE=C sort -T sorttmp/ -muo fdns_a.sort.txt fileChunk*.sorted
# 清理垃圾文件
rm fileChunk*
以上架构的更多细节可以在以下链接找到
https://github.com/erbbysam/DNSGrep#run
DNSGrep
现在,我们可以快速搜索数据了!为此,我用Golang编写了一个简单的应用,你可以在这里找到
https://github.com/erbbysam/dnsgrep
ubuntu@client:~$ ls -lath fdns_a.sort.txt
-rw-rw-r-- 1 ubuntu ubuntu 68G Feb 3 09:11 fdns_a.sort.txt
ubuntu@client:~$ time ./dnsgrep -f fdns_a.sort.txt -i "erbbysam.com"
104.154.120.133,erbbysam.com
54.190.33.125,blog.erbbysam.com
erbbysam.com,
www.erbbysam.com
real0m0.002s
user0m0.000s
sys0m0.000s
速度快得多!
整体的算法非常简单:
使用二元搜索算法搜索文件,查找到查询子字符串匹配的项目。
找到匹配项后,以10KB的增量向后扫描文件,直到找到查询子字符串不匹配的项。
找到子字符串不匹配的项目后,向前扫描文件,直到找到完全匹配的结果。
PoC
PoC免责声明:不保证安全稳定性,你在使用时代码,数据可能已经过时。
由于这个查询速度如此之快,我在亚马逊的云服务器上专门配置了一个服务器来托管这些数据,以方便对这些数据集进行查询:
https://github.com/erbbysam/dnsgrep/tree/master/experialserver
https://dns.bufferover.run/dns?q=erbbysam.com
ubuntu@client:~$ curl 'https://dns.bufferover.run/dns?q=erbbysam.com'
{
"me ta": {
"Runtime": "0.000361 seconds",
"Errors": [
"rdns error: failed to find exact match via binary search"
],
"FileNames": [
"2019-01-25-1548417890-fdns_a.json.gz",
"2019-01-30-1548868121-rdns.json.gz"
],
"TOS": "The source of this data is Rapid7 Labs. Please review the Terms of Service:
https://opendata.rapid7.com/about/"
},
"FDNS_A": [
"104.154.120.133,erbbysam.com",
"54.190.33.125,blog.erbbysam.com",
"erbbysam.com,
www.erbbysam.com"
],
"RDNS": null
}
有意思的是,我查询了每一个朝鲜域名,得出的的IP地址并不属于朝鲜:
https://dns.bufferover.run/dns?q=.kp
ubuntu@client:~$ curl 'https://dns.bufferover.run/dns?q=.kp' 2> /dev/null | grep -v "\"175\.45\.17"
{
"me ta": {
"Runtime": "0.000534 seconds",
"Errors": null,
"FileNames": [
"2019-01-25-1548417890-fdns_a.json.gz",
"2019-01-30-1548868121-rdns.json.gz"
],
"TOS": "The source of this data is Rapid7 Labs. Please review the Terms of Service:
https://opendata.rapid7.com/about/"
},
"FDNS_A": [
"175.45.0.178,ns1.portal.net.kp",
],
"RDNS": [
"185.33.146.18,north-korea.kp",
"66.23.232.124,sverjd.ouie.kp",
"64.86.226.78,ns2.friend.com.kp",
"103.120.178.114,dedi.kani28test.kp",
"198.98.49.51,gfw.kp",
"185.86.149.212,hey.kp"
]
}
感谢你的阅读就这样!希望大家尝试使用我的项目。
https://dns.bufferover.run/dns?q=
本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:
https://blog.erbbysam.com/index.php/2019/02/09/dnsgrep/
https://github.com/erbbysam/DNSGrep
https://dns.bufferover.run/dns?q=baidu.com
[
本帖最后由 linda 于 2019-2-14 11:36 编辑 ]