fofa 0.3.13 → 0.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/Gemfile.lock +2 -2
- data/bin/fofacli +118 -5
- data/lib/fofa.rb +99 -10
- data/lib/fofa/version.rb +19 -1
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d545f5e3f2e72200759bf4f2f113cf4ae3933cacc79e7436db2948fca942f092
|
4
|
+
data.tar.gz: e72a5f234fdd0d8ffc0319140dd1e9a5493f53da7c0d212c19807be4a516f0b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f610a997d2fc71c76c2d960426d1fc80346a19ef306d808c8e7a09175cd4e625105a108d4534a4dc01e49546b4f730cc05014c28ffed22e87ac5bdf364fabda
|
7
|
+
data.tar.gz: c768c528f1ba58e8e5823df16e4b2ea533800057c24411f0d47989ef3f0ef117e162073e60348ac4eb31840b0e03ba49ec349d4c4b09e67e892459e0f84c740b
|
data/Gemfile.lock
CHANGED
data/bin/fofacli
CHANGED
@@ -18,7 +18,11 @@ options = {
|
|
18
18
|
fields: 'host',
|
19
19
|
post: false,
|
20
20
|
query: nil,
|
21
|
-
format: 'csv'
|
21
|
+
format: 'csv',
|
22
|
+
check_app_category: nil,
|
23
|
+
check_app_application: nil,
|
24
|
+
check_app_all: false,
|
25
|
+
task_id: nil
|
22
26
|
}
|
23
27
|
|
24
28
|
ARGV.options do |opts|
|
@@ -39,12 +43,16 @@ ARGV.options do |opts|
|
|
39
43
|
options[:page] = val.to_i
|
40
44
|
end
|
41
45
|
|
42
|
-
opts.on('-m', '--mode=MODE', String, 'Mode, default to [search], -m should be specified when [import_service, query_ip_list] ') do |val|
|
46
|
+
opts.on('-m', '--mode=MODE', String, 'Mode, default to [search], -m should be specified when [import_service, query_ip_list, check_app, ip_tags] ') do |val|
|
43
47
|
options[:mode] = val.to_sym
|
44
48
|
end
|
45
49
|
|
46
|
-
opts.on('-f', '--file=FILE', String, 'Used at [import_service] mode') do |val|
|
50
|
+
opts.on('-f', '--file=FILE', String, 'Used at [import_service, check_app, ip_tags] mode') do |val|
|
47
51
|
options[:file] = val
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on('-t', '--task_id=ID', Integer, 'Used at [ip_tags] mode') do |val|
|
55
|
+
options[:task_id] = val.to_i
|
48
56
|
end
|
49
57
|
|
50
58
|
opts.on('-s', '--limit=SIZE', Integer, "Limit size to fetch, default to #{options[:limit]}") do |val|
|
@@ -67,7 +75,17 @@ ARGV.options do |opts|
|
|
67
75
|
raise "File not exist of #{val}" unless File.exists? val
|
68
76
|
options[:query] = File.read(val).strip
|
69
77
|
options[:post] = true
|
70
|
-
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.on('-l', "--application=APPLICATION", String, "Application to check, only used in check_app mode." ) do |val|
|
81
|
+
options[:check_app_application] = val
|
82
|
+
options[:mode] = :check_app
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on('-g', "--category=CATEGORY", String, "Category to check, only used in check_app mode." ) do |val|
|
86
|
+
options[:check_app_category] = val
|
87
|
+
options[:mode] = :check_app
|
88
|
+
end
|
71
89
|
|
72
90
|
opts.separator "Common Options:"
|
73
91
|
|
@@ -84,6 +102,17 @@ ARGV.options do |opts|
|
|
84
102
|
options[:verbose] = true
|
85
103
|
end
|
86
104
|
|
105
|
+
opts.on( "-V", "--version", "Display version" ) do
|
106
|
+
puts "Version: #{Fofa::VERSION}"
|
107
|
+
exit(0)
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on( nil, "--check_app_all", "Check all applications, only used in check_app mode." ) do
|
111
|
+
options[:check_app_all] = true
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
|
87
116
|
opts.separator ""
|
88
117
|
opts.separator "For example:"
|
89
118
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx domain=\"baidu.com\""
|
@@ -91,7 +120,10 @@ ARGV.options do |opts|
|
|
91
120
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx --query_file /tmp/fofaquery"
|
92
121
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -d ip,domain,title,port,protocol -m query_ip_list -f ip.txt"
|
93
122
|
opts.separator %Q@\t cat vapps.txt | xargs -I{} -n 1 sh -c 'fofacli "app=$1" -d host,ip,port,country,province,city -s 1000 -o json -v > "$1.txt"' -- {}@
|
94
|
-
|
123
|
+
opts.separator "\t fofacli -m check_app --app \"Coremail\" mail.tsinghua.edu.cn"
|
124
|
+
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -m ip_tags -f ./ip.txt"
|
125
|
+
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -m ip_tags -t 1"
|
126
|
+
|
95
127
|
begin
|
96
128
|
opts.parse!
|
97
129
|
rescue OptionParser::InvalidOption => e
|
@@ -227,5 +259,86 @@ case options[:mode]
|
|
227
259
|
} #File
|
228
260
|
pool.shutdown
|
229
261
|
pool.wait_for_termination
|
262
|
+
when :check_app
|
263
|
+
query = options[:query] || ARGV.join(' ')
|
264
|
+
fofa = Fofa::API.new(options[:email], options[:apikey], {debug:options[:verbose]})
|
265
|
+
if options[:file]
|
266
|
+
File.open(options[:file]){|f|
|
267
|
+
f.each_line{|line|
|
268
|
+
query = line.strip
|
269
|
+
res = fofa.check_app(query, {
|
270
|
+
category:options[:check_app_category],
|
271
|
+
application:options[:check_app_application],
|
272
|
+
all:options[:all],
|
273
|
+
})
|
274
|
+
|
275
|
+
if res && res.size>0
|
276
|
+
res.each{|r|
|
277
|
+
log_record(options, [query, r])
|
278
|
+
}
|
279
|
+
else
|
280
|
+
log_record(options, [query, nil])
|
281
|
+
end
|
282
|
+
|
283
|
+
}
|
284
|
+
}
|
285
|
+
else
|
286
|
+
res = fofa.check_app(query, {
|
287
|
+
category:options[:check_app_category],
|
288
|
+
application:options[:check_app_application],
|
289
|
+
all:options[:all],
|
290
|
+
})
|
291
|
+
|
292
|
+
if res && res.size>0
|
293
|
+
res.each{|r|
|
294
|
+
log_record(options, r)
|
295
|
+
}
|
296
|
+
else
|
297
|
+
$stderr.puts "[WARNING] No result!"
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
when :ip_tags
|
302
|
+
fofa = Fofa::API.new(options[:email], options[:apikey], {debug:options[:verbose]})
|
303
|
+
if options[:task_id]
|
304
|
+
task_id = options[:task_id]
|
305
|
+
else
|
306
|
+
unless options[:file]
|
307
|
+
puts "File not specified.".red
|
308
|
+
puts ARGV.options
|
309
|
+
exit -1
|
310
|
+
end
|
311
|
+
puts "Import ip and get tags from '#{options[:file]}'"
|
312
|
+
result = fofa.ip_tags(options[:file])
|
313
|
+
if result['error']
|
314
|
+
puts result
|
315
|
+
exit -1
|
316
|
+
end
|
317
|
+
puts result
|
318
|
+
task_id = result['task_id']
|
319
|
+
end
|
320
|
+
|
321
|
+
if task_id
|
322
|
+
get_info = -> (fofa, id) { fofa.tag_info(id) }
|
323
|
+
puts "Checking progress!"
|
324
|
+
sleep(2)
|
325
|
+
|
326
|
+
loop do
|
327
|
+
info = get_info.call(fofa, task_id)
|
328
|
+
if info['error']
|
329
|
+
puts info
|
330
|
+
break
|
331
|
+
elsif info['progress'].to_i == 100
|
332
|
+
puts "state: #{info['state']}; progress: #{info['progress']}."
|
333
|
+
puts info['download_url']
|
334
|
+
break
|
335
|
+
else
|
336
|
+
puts "state: #{info['state']}; progress: #{info['progress']}."
|
337
|
+
sleep(10)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
|
230
343
|
end
|
231
344
|
|
data/lib/fofa.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "fofa/version"
|
2
2
|
require 'net/http'
|
3
3
|
require 'json'
|
4
|
+
require 'base64'
|
4
5
|
|
5
6
|
module Fofa
|
6
7
|
class API
|
@@ -29,13 +30,10 @@ module Fofa
|
|
29
30
|
options = {page:1, size:100, fields:'host'}.merge(options)
|
30
31
|
|
31
32
|
url = "#{@api_server}/api/v1/search/all?key=#{@apikey}&email=#{@email}&page=#{options[:page]}&size=#{options[:size]}&fields=#{options[:fields]}"
|
32
|
-
url += "&
|
33
|
+
url += "&qbase64=#{Base64.encode64(query)}" unless options[:post]
|
33
34
|
puts url if @options[:debug]
|
34
35
|
uri = URI.parse(url)
|
35
|
-
http =
|
36
|
-
if uri.scheme == 'https'
|
37
|
-
http.use_ssl = true
|
38
|
-
end
|
36
|
+
http = http_new(uri)
|
39
37
|
|
40
38
|
if options[:post]
|
41
39
|
req = Net::HTTP::Post.new(uri.request_uri)
|
@@ -47,6 +45,7 @@ module Fofa
|
|
47
45
|
resp = http.request(req)
|
48
46
|
JSON.parse(resp.body)
|
49
47
|
rescue => e
|
48
|
+
$stderr.puts "[WARNING]: #{e.to_s}"
|
50
49
|
{"error"=>"Error: #{e.to_s}"}
|
51
50
|
end
|
52
51
|
|
@@ -104,11 +103,7 @@ module Fofa
|
|
104
103
|
url = "#{@api_server}/api/v1/import/services?key=#{@apikey}&email=#{@email}&port=#{options[:port]}"
|
105
104
|
puts url if @options[:debug]
|
106
105
|
uri = URI.parse(url)
|
107
|
-
http =
|
108
|
-
if uri.scheme == 'https'
|
109
|
-
http.use_ssl = true
|
110
|
-
end
|
111
|
-
http.set_debug_output $stderr if @options[:debug]
|
106
|
+
http = http_new(uri)
|
112
107
|
|
113
108
|
File.open(file) do |f|
|
114
109
|
results = []
|
@@ -137,5 +132,99 @@ module Fofa
|
|
137
132
|
{"error"=>"Error: #{e.to_s}"}
|
138
133
|
end
|
139
134
|
|
135
|
+
# Check applications of asset
|
136
|
+
#
|
137
|
+
# Example:
|
138
|
+
# >> Fofa::API.new(email,apikey).checkapp("mail.tsinghua.edu.cn", category:"邮件系统")
|
139
|
+
# => ["Coremail"]
|
140
|
+
#
|
141
|
+
# Arguments:
|
142
|
+
# host: (String) Category name
|
143
|
+
# options: (Hash) category: Category name, application: Application name, all: return all applications or break when match first
|
144
|
+
def check_app(host, options={})
|
145
|
+
options = {all:false}.merge(options)
|
146
|
+
url = "#{@api_server}/api/v1/search/checkapp?key=#{@apikey}&email=#{@email}&host=#{host}"
|
147
|
+
url += "&all=#{options[:all]}" if options[:all]
|
148
|
+
url += "&application=#{URI.escape(options[:application])}" if options[:application]
|
149
|
+
url += "&category=#{URI.escape(options[:category])}" if options[:category]
|
150
|
+
puts url if @options[:debug]
|
151
|
+
uri = URI.parse(url)
|
152
|
+
http = http_new(uri)
|
153
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
154
|
+
resp = http.request(req)
|
155
|
+
JSON.parse(resp.body)
|
156
|
+
rescue => e
|
157
|
+
{"error"=>"Error: #{e.to_s}"}
|
158
|
+
end
|
159
|
+
|
160
|
+
# Import ip and get tags
|
161
|
+
#
|
162
|
+
# Example:
|
163
|
+
# >> Fofa::API.new(email,apikey).ip_tags('./ips.txt')
|
164
|
+
# => {"task_id"=>1}
|
165
|
+
#
|
166
|
+
# Arguments:
|
167
|
+
# file: (String) ip file
|
168
|
+
def ip_tags(file)
|
169
|
+
url = "#{@api_server}/api/v1/ip_tags?key=#{@apikey}&email=#{@email}"
|
170
|
+
puts url if @options[:debug]
|
171
|
+
|
172
|
+
# Token used to terminate the file in the post body. Make sure it is not
|
173
|
+
# present in the file you're uploading.
|
174
|
+
# You might want to use `SecureRandom` class to generate this random strings
|
175
|
+
boundary = "AaB03x"
|
176
|
+
uri = URI.parse(url)
|
177
|
+
|
178
|
+
post_body = []
|
179
|
+
post_body << "--#{boundary}\r\n"
|
180
|
+
post_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{File.basename(file)}\"\r\n"
|
181
|
+
post_body << "Content-Type: text/plain\r\n"
|
182
|
+
post_body << "\r\n"
|
183
|
+
post_body << File.read(file)
|
184
|
+
post_body << "\r\n--#{boundary}--\r\n"
|
185
|
+
|
186
|
+
http = http_new(uri)
|
187
|
+
req = Net::HTTP::Post.new(uri.request_uri)
|
188
|
+
req.body = post_body.join
|
189
|
+
req["Content-Type"] = "multipart/form-data, boundary=#{boundary}"
|
190
|
+
|
191
|
+
resp = http.request(req)
|
192
|
+
puts resp if @options[:debug]
|
193
|
+
JSON.parse(resp.body)
|
194
|
+
rescue => e
|
195
|
+
{"error"=>"Error: #{e.to_s}"}
|
196
|
+
end
|
197
|
+
|
198
|
+
# Check ip_tags's task state, progress, and download_url
|
199
|
+
#
|
200
|
+
# Example:
|
201
|
+
# >> Fofa::API.new(email,apikey).tag_info(1)
|
202
|
+
# => {"state"=>"success", "progress"=>100, "download_url"=>"https://host/xxx/56af409c1c55762a7b9e9a39a801f80d.json"}
|
203
|
+
#
|
204
|
+
# Arguments:
|
205
|
+
# task_id: (Integer) task id
|
206
|
+
def tag_info(task_id)
|
207
|
+
url = "#{@api_server}/api/v1/ip_tags/info?key=#{@apikey}&email=#{@email}&task_id=#{task_id}"
|
208
|
+
puts url if @options[:debug]
|
209
|
+
uri = URI.parse(url)
|
210
|
+
http = http_new(uri)
|
211
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
212
|
+
|
213
|
+
resp = http.request(req)
|
214
|
+
JSON.parse(resp.body)
|
215
|
+
rescue => e
|
216
|
+
$stderr.puts "[WARNING]: #{e.to_s}"
|
217
|
+
{"error"=>"Error: #{e.to_s}"}
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
def http_new(uri)
|
222
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
223
|
+
if uri.scheme == 'https'
|
224
|
+
http.use_ssl = true
|
225
|
+
end
|
226
|
+
http.set_debug_output $stderr if @options[:debug]
|
227
|
+
http
|
228
|
+
end
|
140
229
|
end
|
141
230
|
end
|
data/lib/fofa/version.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# 0.4.20
|
2
|
+
# add -V option, and ip_tags method need to upgrade major version
|
3
|
+
#
|
4
|
+
# 0.3.19
|
5
|
+
# add feature: ip_tags, tag_info
|
6
|
+
#
|
7
|
+
# 0.3.18
|
8
|
+
# add feature: check applications from file
|
9
|
+
#
|
10
|
+
# 0.3.17
|
11
|
+
# add checkapp api call
|
12
|
+
#
|
13
|
+
# 0.3.15
|
14
|
+
# fixed query encode bug of '&&'
|
15
|
+
#
|
16
|
+
# 0.3.14
|
17
|
+
# fixed bug of search_all yield when size reached
|
18
|
+
#
|
1
19
|
# 0.3.13
|
2
20
|
# search_all yield with all size
|
3
21
|
#
|
@@ -19,5 +37,5 @@
|
|
19
37
|
# 0.3.6
|
20
38
|
# add fields
|
21
39
|
module Fofa
|
22
|
-
VERSION = "0.
|
40
|
+
VERSION = "0.4.20"
|
23
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fofa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fofa
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -106,7 +106,7 @@ homepage: https://fofa.so
|
|
106
106
|
licenses:
|
107
107
|
- MIT
|
108
108
|
metadata: {}
|
109
|
-
post_install_message:
|
109
|
+
post_install_message:
|
110
110
|
rdoc_options: []
|
111
111
|
require_paths:
|
112
112
|
- lib
|
@@ -121,9 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '0'
|
123
123
|
requirements: []
|
124
|
-
|
125
|
-
|
126
|
-
signing_key:
|
124
|
+
rubygems_version: 3.0.6
|
125
|
+
signing_key:
|
127
126
|
specification_version: 4
|
128
127
|
summary: A Ruby library to interact with the FOFA API. https://fofa.so
|
129
128
|
test_files: []
|