fofa 0.3.12 → 0.3.19
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 +121 -7
- data/lib/fofa.rb +100 -11
- 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: bfc764bb2b5c3d56f6dfd68ac14a74478a7d19c4e14c72bec35b1d3f547fb7aa
|
4
|
+
data.tar.gz: 8c52a5488290a45f3c074fcdccca99bef75685e91d42fe554268eb886cad36f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67ba297c2bba208e41d01700549cb396de980fb3937e932e01699ee90ce0185d2e9f6daac48fd9366ac919adbc883cd3377686ec5b5fff15e5b44c2ff594e381
|
7
|
+
data.tar.gz: c998095f14e85ceeb262b4f6b3b02c102d3a75dd0d2c0088c6b0402b7e8b968e0311a950261c91c45719d80fb02d3e5910da3106d1c8470dd1ab04eba3eaf03a
|
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,13 +102,23 @@ ARGV.options do |opts|
|
|
84
102
|
options[:verbose] = true
|
85
103
|
end
|
86
104
|
|
105
|
+
opts.on( nil, "--check_app_all", "Check all applications, only used in check_app mode." ) do
|
106
|
+
options[:check_app_all] = true
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
87
111
|
opts.separator ""
|
88
112
|
opts.separator "For example:"
|
89
113
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx domain=\"baidu.com\""
|
90
114
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -s 100 domain=\"baidu.com\""
|
91
115
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx --query_file /tmp/fofaquery"
|
92
116
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -d ip,domain,title,port,protocol -m query_ip_list -f ip.txt"
|
93
|
-
|
117
|
+
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"' -- {}@
|
118
|
+
opts.separator "\t fofacli -m check_app --app \"Coremail\" mail.tsinghua.edu.cn"
|
119
|
+
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -m ip_tags -f ./ip.txt"
|
120
|
+
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -m ip_tags -t 1"
|
121
|
+
|
94
122
|
begin
|
95
123
|
opts.parse!
|
96
124
|
rescue OptionParser::InvalidOption => e
|
@@ -125,8 +153,13 @@ def log_record(options, r)
|
|
125
153
|
else
|
126
154
|
puts %Q|{"id":"#{r}"}|
|
127
155
|
end
|
128
|
-
|
129
|
-
|
156
|
+
when 'csv'
|
157
|
+
if r.kind_of?(Array)
|
158
|
+
puts r.map{|v| v}.join("\t")
|
159
|
+
else
|
160
|
+
puts r
|
161
|
+
end
|
162
|
+
|
130
163
|
end
|
131
164
|
end
|
132
165
|
|
@@ -221,5 +254,86 @@ case options[:mode]
|
|
221
254
|
} #File
|
222
255
|
pool.shutdown
|
223
256
|
pool.wait_for_termination
|
257
|
+
when :check_app
|
258
|
+
query = options[:query] || ARGV.join(' ')
|
259
|
+
fofa = Fofa::API.new(options[:email], options[:apikey], {debug:options[:verbose]})
|
260
|
+
if options[:file]
|
261
|
+
File.open(options[:file]){|f|
|
262
|
+
f.each_line{|line|
|
263
|
+
query = line.strip
|
264
|
+
res = fofa.check_app(query, {
|
265
|
+
category:options[:check_app_category],
|
266
|
+
application:options[:check_app_application],
|
267
|
+
all:options[:all],
|
268
|
+
})
|
269
|
+
|
270
|
+
if res && res.size>0
|
271
|
+
res.each{|r|
|
272
|
+
log_record(options, [query, r])
|
273
|
+
}
|
274
|
+
else
|
275
|
+
log_record(options, [query, nil])
|
276
|
+
end
|
277
|
+
|
278
|
+
}
|
279
|
+
}
|
280
|
+
else
|
281
|
+
res = fofa.check_app(query, {
|
282
|
+
category:options[:check_app_category],
|
283
|
+
application:options[:check_app_application],
|
284
|
+
all:options[:all],
|
285
|
+
})
|
286
|
+
|
287
|
+
if res && res.size>0
|
288
|
+
res.each{|r|
|
289
|
+
log_record(options, r)
|
290
|
+
}
|
291
|
+
else
|
292
|
+
$stderr.puts "[WARNING] No result!"
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
when :ip_tags
|
297
|
+
fofa = Fofa::API.new(options[:email], options[:apikey], {debug:options[:verbose]})
|
298
|
+
if options[:task_id]
|
299
|
+
task_id = options[:task_id]
|
300
|
+
else
|
301
|
+
unless options[:file]
|
302
|
+
puts "File not specified.".red
|
303
|
+
puts ARGV.options
|
304
|
+
exit -1
|
305
|
+
end
|
306
|
+
puts "Import ip and get tags from '#{options[:file]}'"
|
307
|
+
result = fofa.ip_tags(options[:file])
|
308
|
+
if result['error']
|
309
|
+
puts result
|
310
|
+
exit -1
|
311
|
+
end
|
312
|
+
puts result
|
313
|
+
task_id = result['task_id']
|
314
|
+
end
|
315
|
+
|
316
|
+
if task_id
|
317
|
+
get_info = -> (fofa, id) { fofa.tag_info(id) }
|
318
|
+
puts "Checking progress!"
|
319
|
+
sleep(2)
|
320
|
+
|
321
|
+
loop do
|
322
|
+
info = get_info.call(fofa, task_id)
|
323
|
+
if info['error']
|
324
|
+
puts info
|
325
|
+
break
|
326
|
+
elsif info['progress'].to_i == 100
|
327
|
+
puts "state: #{info['state']}; progress: #{info['progress']}."
|
328
|
+
puts info['download_url']
|
329
|
+
break
|
330
|
+
else
|
331
|
+
puts "state: #{info['state']}; progress: #{info['progress']}."
|
332
|
+
sleep(10)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
224
338
|
end
|
225
339
|
|
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
|
|
@@ -74,7 +73,7 @@ module Fofa
|
|
74
73
|
res = search(query, {page:page}.merge(options))
|
75
74
|
if !res['error'] && res['results'].size > 0
|
76
75
|
all_res += res['results']
|
77
|
-
yield(res['results'], page) if block_given?
|
76
|
+
yield(res['results'], page, res['size'].to_i) if block_given?
|
78
77
|
|
79
78
|
if all_size && all_res.size > all_size.to_i
|
80
79
|
all_res = all_res[0..all_size-1]
|
@@ -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.3.19
|
2
|
+
# add feature: ip_tags, tag_info
|
3
|
+
#
|
4
|
+
# 0.3.18
|
5
|
+
# add feature: check applications from file
|
6
|
+
#
|
7
|
+
# 0.3.17
|
8
|
+
# add checkapp api call
|
9
|
+
#
|
10
|
+
# 0.3.15
|
11
|
+
# fixed query encode bug of '&&'
|
12
|
+
#
|
13
|
+
# 0.3.14
|
14
|
+
# fixed bug of search_all yield when size reached
|
15
|
+
#
|
16
|
+
# 0.3.13
|
17
|
+
# search_all yield with all size
|
18
|
+
#
|
1
19
|
# 0.3.12
|
2
20
|
# fofacli add -o --output-format option, support csv(defualt) and json
|
3
21
|
#
|
@@ -16,5 +34,5 @@
|
|
16
34
|
# 0.3.6
|
17
35
|
# add fields
|
18
36
|
module Fofa
|
19
|
-
VERSION = "0.3.
|
37
|
+
VERSION = "0.3.19"
|
20
38
|
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.3.
|
4
|
+
version: 0.3.19
|
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: []
|