class Fofa::API

Public Class Methods

new(email, apikey, options={}) click to toggle source
# File lib/fofa.rb, line 9
def initialize(email, apikey, options={})
        @options = {debug:false}.merge options
        @api_server = ENV['FOFA_API_SERVER'] || 'https://fofa.so'
        @email = email || ENV['FOFA_EMAIL']
        @apikey = apikey || ENV['FOFA_KEY']
end

Public Instance Methods

check_app(host, options={}) click to toggle source

Check applications of asset

Example:

>> Fofa::API.new(email,apikey).checkapp("mail.tsinghua.edu.cn", category:"邮件系统")
=> ["Coremail"]

Arguments:

host: (String) Category name
options: (Hash) category: Category name, application: Application name, all: return all applications or break when match first
# File lib/fofa.rb, line 144
def check_app(host, options={})
  options = {all:false}.merge(options)
  url = "#{@api_server}/api/v1/search/checkapp?key=#{@apikey}&email=#{@email}&host=#{host}"
  url += "&all=#{options[:all]}" if options[:all]
  url += "&application=#{URI.escape(options[:application])}" if options[:application]
  url += "&category=#{URI.escape(options[:category])}" if options[:category]
  puts url if @options[:debug]
  uri = URI.parse(url)
  http = http_new(uri)
  req = Net::HTTP::Get.new(uri.request_uri)
  resp = http.request(req)
  JSON.parse(resp.body)
rescue => e
  {"error"=>"Error: #{e.to_s}"}
end
import_service(file, options={}) click to toggle source

Import asset into fofa

Example:

>> Fofa::API.new(email,apikey).import("./http80.txt")
=> {size:1, results:['1.1.1.1:80']}

Arguments:

file: (String) assets file
options: (Hash) page
# File lib/fofa.rb, line 101
def import_service(file, options={})
  options = {port:80, split_size:100}.merge(options)
  url = "#{@api_server}/api/v1/import/services?key=#{@apikey}&email=#{@email}&port=#{options[:port]}"
  puts url if @options[:debug]
  uri = URI.parse(url)
  http = http_new(uri)

  File.open(file) do |f|
    results = [] 
    f.each_line.lazy.each_with_index do |line, i|

      line = line.strip
      if m = /Discovered open port (?<port>.*?)\/tcp on (?<host>.*?)$/.match(line)
        hostinfo = "#{m[:host]}:#{m[:port]}"
      elsif line.include?(':')
        hostinfo = line
      else
        hostinfo = "#{line}:#{options[:port]}"
      end

      results << line 
      if i % split_size == 0
        req = Net::HTTP::Post.new(uri.request_uri)
        req.body = results.join("\n")
        resp = http.request(req)
        puts resp if @options[:debug]
        results = [] 
      end
    end
  end
rescue => e
  {"error"=>"Error: #{e.to_s}"}
end
ip_tags(file) click to toggle source

Import ip and get tags

Example:

>> Fofa::API.new(email,apikey).ip_tags('./ips.txt')
=> {"task_id"=>1}

Arguments:

file: (String) ip file
# File lib/fofa.rb, line 168
def ip_tags(file)
  url = "#{@api_server}/api/v1/ip_tags?key=#{@apikey}&email=#{@email}"
  puts url if @options[:debug]

  # Token used to terminate the file in the post body. Make sure it is not
  # present in the file you're uploading.
  # You might want to use `SecureRandom` class to generate this random strings
  boundary = "AaB03x"
  uri = URI.parse(url)

  post_body = []
  post_body << "--#{boundary}\r\n"
  post_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{File.basename(file)}\"\r\n"
  post_body << "Content-Type: text/plain\r\n"
  post_body << "\r\n"
  post_body << File.read(file)
  post_body << "\r\n--#{boundary}--\r\n"

  http = http_new(uri)
  req = Net::HTTP::Post.new(uri.request_uri)
  req.body = post_body.join
  req["Content-Type"] = "multipart/form-data, boundary=#{boundary}"

  resp = http.request(req)
  puts resp if @options[:debug]
  JSON.parse(resp.body)
rescue => e
  {"error"=>"Error: #{e.to_s}"}
end
search_all(query, options={}) { |res, page, to_i| ... } click to toggle source

Search all results from fofa

Example:

>> Fofa::API.new(email,apikey).search_all("domain==baidu.com") {|results, page| ... }
=> {size:1, results:['1.1.1.1:80']}

Example:

>> Fofa::API.new(email,apikey).search_all("domain==baidu.com", fields:'host,title,ip') {|results, page| ... }
=> {size:1, results:[['1.1.1.1:81', 'title', '1.1.1.1']]}

Arguments:

query: (String) fofa query string
# File lib/fofa.rb, line 64
def search_all(query, options={})
  all_size = options.delete :size if options.has_key?(:size)# do not pass to search
  if options.has_key?(:page_size)
    options[:size] = options.delete :page_size
  end
  all_res = []
  page = 0
  loop do
    page += 1
    res = search(query, {page:page}.merge(options))
    if !res['error'] && res['results'].size > 0
      all_res += res['results']
      yield(res['results'], page, res['size'].to_i) if block_given?

      if all_size && all_res.size > all_size.to_i
        all_res = all_res[0..all_size-1]
        break
      end

      break if all_res.size >= res['size'].to_i
    else
      raise res['errmsg'] if res['errmsg']
      break
    end
  end
  all_res
end
tag_info(task_id) click to toggle source

Check ip_tags's task state, progress, and download_url

Example:

>> Fofa::API.new(email,apikey).tag_info(1)
=> {"state"=>"success", "progress"=>100, "download_url"=>"https://host/xxx/56af409c1c55762a7b9e9a39a801f80d.json"}

Arguments:

task_id: (Integer) task id
# File lib/fofa.rb, line 206
def tag_info(task_id)
  url = "#{@api_server}/api/v1/ip_tags/info?key=#{@apikey}&email=#{@email}&task_id=#{task_id}"
  puts url if @options[:debug]
  uri = URI.parse(url)
  http = http_new(uri)
  req = Net::HTTP::Get.new(uri.request_uri)

  resp = http.request(req)
  JSON.parse(resp.body)
rescue => e
  $stderr.puts "[WARNING]: #{e.to_s}"
  {"error"=>"Error: #{e.to_s}"}
end

Private Instance Methods

http_new(uri) click to toggle source
# File lib/fofa.rb, line 221
def http_new(uri)
  http = Net::HTTP.new(uri.host, uri.port)
  if uri.scheme == 'https'
    http.use_ssl = true
  end
  http.set_debug_output $stderr if @options[:debug]
  http
end