fofa 0.3.17 → 0.4.21
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 +103 -22
- data/lib/fofa/version.rb +13 -1
- data/lib/fofa.rb +59 -23
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4ba6286e4654e1e55b8b07ba1996edfb64b61139eb9957f03a7e73a35ae93e4a
|
|
4
|
+
data.tar.gz: 0b0c0daa6a59f9c602b5e72c19cf35f539cef73d0a0609d8090d73dd9ecc1676
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 137d9c7252fd91dff2f6ac7d61f01fa43bca086bb716912c8e694aebaca9817970051708e29726f8c0c16920b7bf11e9b4b66334758ee826b24f5d907b2008fa
|
|
7
|
+
data.tar.gz: 0716e3e28ce190378a25aae007308d395ee651fa4ac02dd1ba29d36482f084f69b1a298d362dd4180bc7d6d34b7618db49efc2f598c683287977f45ccc9cad27
|
data/Gemfile.lock
CHANGED
data/bin/fofacli
CHANGED
|
@@ -21,7 +21,8 @@ options = {
|
|
|
21
21
|
format: 'csv',
|
|
22
22
|
check_app_category: nil,
|
|
23
23
|
check_app_application: nil,
|
|
24
|
-
check_app_all: false
|
|
24
|
+
check_app_all: false,
|
|
25
|
+
task_id: nil
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
ARGV.options do |opts|
|
|
@@ -42,12 +43,16 @@ ARGV.options do |opts|
|
|
|
42
43
|
options[:page] = val.to_i
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
opts.on('-m', '--mode=MODE', String, 'Mode, default to [search], -m should be specified when [import_service, query_ip_list, check_app] ') 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|
|
|
46
47
|
options[:mode] = val.to_sym
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
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|
|
|
50
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
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
opts.on('-s', '--limit=SIZE', Integer, "Limit size to fetch, default to #{options[:limit]}") do |val|
|
|
@@ -80,7 +85,7 @@ ARGV.options do |opts|
|
|
|
80
85
|
opts.on('-g', "--category=CATEGORY", String, "Category to check, only used in check_app mode." ) do |val|
|
|
81
86
|
options[:check_app_category] = val
|
|
82
87
|
options[:mode] = :check_app
|
|
83
|
-
|
|
88
|
+
end
|
|
84
89
|
|
|
85
90
|
opts.separator "Common Options:"
|
|
86
91
|
|
|
@@ -97,9 +102,14 @@ ARGV.options do |opts|
|
|
|
97
102
|
options[:verbose] = true
|
|
98
103
|
end
|
|
99
104
|
|
|
105
|
+
opts.on( "-V", "--version", "Display version" ) do
|
|
106
|
+
puts "Version: #{Fofa::VERSION}"
|
|
107
|
+
exit(0)
|
|
108
|
+
end
|
|
109
|
+
|
|
100
110
|
opts.on( nil, "--check_app_all", "Check all applications, only used in check_app mode." ) do
|
|
101
111
|
options[:check_app_all] = true
|
|
102
|
-
|
|
112
|
+
end
|
|
103
113
|
|
|
104
114
|
|
|
105
115
|
|
|
@@ -110,6 +120,9 @@ ARGV.options do |opts|
|
|
|
110
120
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx --query_file /tmp/fofaquery"
|
|
111
121
|
opts.separator "\t fofacli -e aaa@bbb.com -a xxx -d ip,domain,title,port,protocol -m query_ip_list -f ip.txt"
|
|
112
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"' -- {}@
|
|
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"
|
|
113
126
|
|
|
114
127
|
begin
|
|
115
128
|
opts.parse!
|
|
@@ -139,17 +152,17 @@ def log_record(options, r)
|
|
|
139
152
|
case options[:format]
|
|
140
153
|
when 'json'
|
|
141
154
|
if r.kind_of?(Array)
|
|
142
|
-
puts Hash[options[:fields].split(',').zip r].to_json
|
|
155
|
+
STDOUT.puts Hash[options[:fields].split(',').zip r].to_json
|
|
143
156
|
elsif r.kind_of?(Hash)
|
|
144
|
-
puts r.to_json
|
|
157
|
+
STDOUT.puts r.to_json
|
|
145
158
|
else
|
|
146
|
-
puts %Q|{"id":"#{r}"}|
|
|
159
|
+
STDOUT.puts %Q|{"id":"#{r}"}|
|
|
147
160
|
end
|
|
148
161
|
when 'csv'
|
|
149
162
|
if r.kind_of?(Array)
|
|
150
|
-
|
|
163
|
+
STDOUT.puts r.map{|v| v}.join("\t")
|
|
151
164
|
else
|
|
152
|
-
|
|
165
|
+
STDOUT.puts r
|
|
153
166
|
end
|
|
154
167
|
|
|
155
168
|
end
|
|
@@ -163,7 +176,7 @@ case options[:mode]
|
|
|
163
176
|
exit -1
|
|
164
177
|
end
|
|
165
178
|
query = options[:query] || ARGV.join(' ')
|
|
166
|
-
puts "Query: '#{query}'"
|
|
179
|
+
STDERR.puts "Query: '#{query}'"
|
|
167
180
|
if options[:page] #search one page
|
|
168
181
|
Fofa::API.new(options[:email], options[:apikey], {debug:options[:verbose]})
|
|
169
182
|
.search(query, {
|
|
@@ -205,7 +218,7 @@ case options[:mode]
|
|
|
205
218
|
require 'concurrent'
|
|
206
219
|
semaphore = Concurrent::Semaphore.new(1)
|
|
207
220
|
pool = Concurrent::FixedThreadPool.new(10)
|
|
208
|
-
$
|
|
221
|
+
$STDOUT.sync = true
|
|
209
222
|
File.open(options[:file]){|f|
|
|
210
223
|
fields = options[:fields].split(',')
|
|
211
224
|
f.each_line{|line|
|
|
@@ -248,16 +261,84 @@ case options[:mode]
|
|
|
248
261
|
pool.wait_for_termination
|
|
249
262
|
when :check_app
|
|
250
263
|
query = options[:query] || ARGV.join(' ')
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
|
261
342
|
|
|
262
343
|
end
|
|
263
344
|
|
data/lib/fofa/version.rb
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# 0.4.21
|
|
2
|
+
# split result to stdout
|
|
3
|
+
#
|
|
4
|
+
# 0.4.20
|
|
5
|
+
# add -V option, and ip_tags method need to upgrade major version
|
|
6
|
+
#
|
|
7
|
+
# 0.3.19
|
|
8
|
+
# add feature: ip_tags, tag_info
|
|
9
|
+
#
|
|
10
|
+
# 0.3.18
|
|
11
|
+
# add feature: check applications from file
|
|
12
|
+
#
|
|
1
13
|
# 0.3.17
|
|
2
14
|
# add checkapp api call
|
|
3
15
|
#
|
|
@@ -28,5 +40,5 @@
|
|
|
28
40
|
# 0.3.6
|
|
29
41
|
# add fields
|
|
30
42
|
module Fofa
|
|
31
|
-
VERSION = "0.
|
|
43
|
+
VERSION = "0.4.21"
|
|
32
44
|
end
|
data/lib/fofa.rb
CHANGED
|
@@ -153,31 +153,67 @@ module Fofa
|
|
|
153
153
|
req = Net::HTTP::Get.new(uri.request_uri)
|
|
154
154
|
resp = http.request(req)
|
|
155
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)
|
|
156
212
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
# f.each_line.lazy.each_with_index do |line, i|
|
|
160
|
-
#
|
|
161
|
-
# line = line.strip
|
|
162
|
-
# if m = /Discovered open port (?<port>.*?)\/tcp on (?<host>.*?)$/.match(line)
|
|
163
|
-
# hostinfo = "#{m[:host]}:#{m[:port]}"
|
|
164
|
-
# elsif line.include?(':')
|
|
165
|
-
# hostinfo = line
|
|
166
|
-
# else
|
|
167
|
-
# hostinfo = "#{line}:#{options[:port]}"
|
|
168
|
-
# end
|
|
169
|
-
#
|
|
170
|
-
# results << line
|
|
171
|
-
# if i % split_size == 0
|
|
172
|
-
# req = Net::HTTP::Post.new(uri.request_uri)
|
|
173
|
-
# req.body = results.join("\n")
|
|
174
|
-
# resp = http.request(req)
|
|
175
|
-
# puts resp if @options[:debug]
|
|
176
|
-
# results = []
|
|
177
|
-
# end
|
|
178
|
-
# end
|
|
179
|
-
# end
|
|
213
|
+
resp = http.request(req)
|
|
214
|
+
JSON.parse(resp.body)
|
|
180
215
|
rescue => e
|
|
216
|
+
$stderr.puts "[WARNING]: #{e.to_s}"
|
|
181
217
|
{"error"=>"Error: #{e.to_s}"}
|
|
182
218
|
end
|
|
183
219
|
|
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.21
|
|
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: 2021-09-18 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,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
121
121
|
- !ruby/object:Gem::Version
|
|
122
122
|
version: '0'
|
|
123
123
|
requirements: []
|
|
124
|
-
rubyforge_project:
|
|
125
|
-
rubygems_version: 2.
|
|
126
|
-
signing_key:
|
|
124
|
+
rubyforge_project:
|
|
125
|
+
rubygems_version: 2.7.7
|
|
126
|
+
signing_key:
|
|
127
127
|
specification_version: 4
|
|
128
128
|
summary: A Ruby library to interact with the FOFA API. https://fofa.so
|
|
129
129
|
test_files: []
|