main
  1require 'socket'
  2
  3class FakeAgent
  4  include PacketFu
  5  DEFAULT_ENDPOINT='http://localhost:3000'
  6  attr_reader :id, :endpoint
  7
  8  def initialize(endpoint = DEFAULT_ENDPOINT)
  9    @endpoint = endpoint
 10  end
 11
 12  def register
 13    response = Typhoeus.post(registration_url, body: { agent: { hostname: hostname } })
 14    json = JSON.parse(response.body)
 15    @id = json["id"]
 16  end
 17
 18  def watch(directory)
 19    listener = Listen.to(directory, debug: true) do |modified, added, removed|
 20      publish_event(:modified, modified)
 21      publish_event(:added, added)
 22      publish_event(:removed, removed)
 23      (modified + added + removed).flatten.each do |file|
 24        scan_file(file)
 25      end
 26    end
 27
 28    listener.start
 29    sleep
 30  end
 31
 32  def scan(directory)
 33    Dir["**/**/*"].each do |file|
 34      scan_file(file)
 35    end
 36  end
 37
 38  def scan_file(file)
 39    return unless File.file?(file)
 40
 41    case disposition_for(file)
 42    when "malicious"
 43      publish_event(:quarantined, [file])
 44    when "unknown"
 45      puts "file is unknown"
 46    end
 47  rescue StandardError => error
 48    log_error(error)
 49  end
 50
 51  def sniff(interface)
 52    capture = Capture.new(iface: interface, start: true)
 53    capture.stream.each do |p|
 54      packet = Packet.parse(p)
 55      if packet.is_ip?
 56        yield packet if block_given?
 57      end
 58    end
 59  end
 60
 61  def packet_capture(interface)
 62    sniff(interface) do |packet|
 63      if packet.ip_saddr == Utils.ifconfig(interface)[:ip_saddr]
 64      else
 65        packet_info = [packet.ip_saddr, packet.ip_daddr, packet.size, packet.proto.last]
 66        #puts packet.dissect
 67        puts "%-15s -> %-15s %-4d %s" % packet_info
 68      end
 69    end
 70  end
 71
 72  private
 73
 74  def publish_event(event, files)
 75    files.each do |file|
 76      body = {
 77        event: {
 78          agent_id: id,
 79          type: event,
 80          data: {
 81            fingerprint: fingerprint_for(file),
 82            path: file,
 83            hostname: hostname,
 84            ip_addresses: ip_addresses,
 85          }
 86        }
 87      }
 88      Typhoeus.post(event_url, body: body)
 89    end
 90  rescue StandardError => error
 91    log_error(error)
 92  end
 93
 94  def fingerprint_for(file)
 95    return nil unless File.exist?(file)
 96    result = `shasum -a 256 #{file}`
 97    sha, * = result.split(' ')
 98    sha
 99  end
100
101  def hostname
102    @hostname ||= "#{Socket.gethostname}-#{Faker::Internet.slug}"
103  end
104
105  def ip_addresses
106    @ipaddresses ||= Socket.ip_address_list.find_all { |x| x.ipv4? }.map { |x| x.ip_address }
107  end
108
109  def disposition_for(file)
110    fingerprint = fingerprint_for(file)
111    body = {
112      data: {
113        fingerprint: fingerprint,
114        path: File.expand_path(file)
115      }
116    }
117    JSON.parse(Typhoeus.get(file_query_url(fingerprint), body: body).body)["state"]
118  end
119
120  def file_query_url(fingerprint)
121    "#{endpoint}/api/agents/#{id}/files/#{fingerprint}"
122  end
123
124  def event_url
125    "#{endpoint}/api/agents/#{id}/events/"
126  end
127
128  def registration_url
129    "#{endpoint}/api/agents"
130  end
131
132  def log_error(error)
133    puts "#{error.message} #{error.backtrace.join(' ')}"
134  end
135end