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.
Files changed (6) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile.lock +2 -2
  3. data/bin/fofacli +121 -7
  4. data/lib/fofa.rb +100 -11
  5. data/lib/fofa/version.rb +19 -1
  6. metadata +6 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 87d0a961aecc981843e098178b7c3fc2c70c14f7
4
- data.tar.gz: 10df9f621ee857e19eb9a31ea5c488fe71895135
2
+ SHA256:
3
+ metadata.gz: bfc764bb2b5c3d56f6dfd68ac14a74478a7d19c4e14c72bec35b1d3f547fb7aa
4
+ data.tar.gz: 8c52a5488290a45f3c074fcdccca99bef75685e91d42fe554268eb886cad36f3
5
5
  SHA512:
6
- metadata.gz: 4c2eaf481b20f662ecac532f950c866ca7fc11d966e4a8b067ad67faca035e08d305923c6ad3a5c85025f3da7d3afc247b91461d4cbb2590cc126f26f28034b2
7
- data.tar.gz: f639fd08740c4df9bcece0443a4b802d9d8df01de17c5136abe4c9fdf4b1a5b6bb09e7c6f04c3c4bd9ddd6127df39ff5aa67e98de72d550f7cf4aefc81193028
6
+ metadata.gz: 67ba297c2bba208e41d01700549cb396de980fb3937e932e01699ee90ce0185d2e9f6daac48fd9366ac919adbc883cd3377686ec5b5fff15e5b44c2ff594e381
7
+ data.tar.gz: c998095f14e85ceeb262b4f6b3b02c102d3a75dd0d2c0088c6b0402b7e8b968e0311a950261c91c45719d80fb02d3e5910da3106d1c8470dd1ab04eba3eaf03a
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fofa (0.3.11)
4
+ fofa (0.3.19)
5
5
  colorize
6
6
  concurrent-ruby
7
7
 
@@ -38,4 +38,4 @@ DEPENDENCIES
38
38
  rspec (~> 3.0)
39
39
 
40
40
  BUNDLED WITH
41
- 1.14.6
41
+ 1.16.4
@@ -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
- end
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
- when 'csv'
129
- puts r.map{|v| v}.join("\t")
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
 
@@ -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 += "&q=#{URI.escape(query)}" unless options[:post]
33
+ url += "&qbase64=#{Base64.encode64(query)}" unless options[:post]
33
34
  puts url if @options[:debug]
34
35
  uri = URI.parse(url)
35
- http = Net::HTTP.new(uri.host, uri.port)
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 = Net::HTTP.new(uri.host, uri.port)
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
@@ -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.12"
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.12
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: 2017-05-11 00:00:00.000000000 Z
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
- rubyforge_project:
125
- rubygems_version: 2.6.3
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: []