#
#   Copyright (C) Stonesoft Corporation 2010 - 2013.
#   All rights reserved.
#
#   The StoneGate software, manuals, and technical
#   literature may not be reproduced in any form or
#   by any means except by permission in writing from
#   Stonesoft Corporation.
#

# Predator4 webGUI

require 'rubygems'
require 'sinatra'
require 'sinatra/base'
require 'haml'

module P4WebGUI
  @@exploits_html_file = nil
  @@network_configs_html_file = nil
  @@presets_html_file = nil
  @@evasions_html_file = nil
  @@right_table_html_file = nil
  @@network_config_js_file = nil
  @@evasions_js_file = nil
  @@presets_js_file = nil
  @@exploits_js_file = nil
  @@log_reader_html_file = nil
  @@shell_reader_html_file = nil
  @@exploit_options_html_file = nil
  @@web_log = []
      
  @@mutex = Mutex.new()     # Hold when doing anything that changes our state
  @@exploit_inst = nil      # Current exploit instance

  @@log_mutex = Mutex.new() # Hold while changing log offset table
  @@log_offsets = {}
   
    
  class HTTPHandler < Sinatra::Base
    set :logging, false
    #set :logging, true
    set :sessions, true
    set :public_folder, "#{$webgui_root}/webgui/public"
    set :views, "#{$webgui_root}/webgui/views"
    set :environment, :production
    set :server, %w[ thin webrick ]
    set :bind, "0.0.0.0"
    mime_type :pcap, 'application/pcap'
    
    # Define handlers for various URLs

    get '/' do
      haml :index
    end

    # Actions
    get '/exploit/run' do
      # Params is a hash 'name'=>'value', suspiciously usable.
      # Check that all required parameters exist
      P4WebGUI::exploit_run( params )
      return ""
    end

    get '/exploit/stop' do
      # Params is a hash 'name'=>'value', suspiciously usable.
      # Check that all required parameters exist
      P4WebGUI::exploit_stop( params )
      return ""
    end

    # Scripts
    get '/script/network_config.js' do
      content_type 'text/javascript', :charset => 'utf-8'
      return P4WebGUI::get_network_config_js()
    end

    get '/script/exploits.js' do
      content_type 'text/javascript', :charset => 'utf-8'
      return P4WebGUI::get_exploits_js()
    end

    get '/script/evasions.js' do
      content_type 'text/javascript', :charset => 'utf-8'
      return P4WebGUI::get_evasions_js()
    end

    get '/script/presets.js' do
      content_type 'text/javascript', :charset => 'utf-8'
      return P4WebGUI::get_presets_js()
    end

    # Log related
    get '/log' do
      return P4WebGUI::generate_log_html( params )
    end

    # Shell related
    get '/shell/read' do
      return P4WebGUI::shell_read( params )
    end

    get '/shell/write' do
      return P4WebGUI::shell_write( params )
    end

    get '/shell/close' do
      return P4WebGUI::shell_close( params )
    end

    get '/shell/reader_html' do
      return P4WebGUI::get_shell_reader_html()
    end
  end

  def P4WebGUI::shell_read( params )
    @@command_shell_mutex.synchronize do
      if @@command_shell_inst.nil?
        return "No shell instance!"
      else
        return @@command_shell_inst.get_content_html( params )
      end
    end
  end

  def P4WebGUI::shell_write( params )
    @@command_shell_mutex.synchronize do
      if @@command_shell_inst.nil?
        puts "Shell write called without shell instance!"
        return "No shell instance!"
      else
        return @@command_shell_inst.write_content( params )
      end
    end
  end

  def P4WebGUI::shell_close( params )
    @@command_shell_mutex.synchronize do
      if @@command_shell_inst.nil?
        log_web_info( "No shell instance to close!" )
        return ""
      else
        @@command_shell_inst.close()
        @@command_shell_inst = nil
        #log_web_info( "Shell closed via GUI" )
        return ""
      end
    end
  end
  
  def P4WebGUI::exploit_run( params )
    puts "Exploit url: #{params.inspect()}"

    net_cfg_type = params[ "net_cfg_type" ]
    host_cfg = network_cfg = nil
    cfg_iface = cfg_src_ip = cfg_src_port = cfg_src_mask = cfg_dst_ip = cfg_dst_port = cfg_dst_mask = cfg_gw_if = nil
    network_cfg_str = ""
    mode_cfg_str = nil
    tool_name = nil

    cfg = DataStore::get_config()
    p4 = DataStore::get_predator4()
    
    # Work with network configuration
    if net_cfg_type == "preset"
      if cfg.net_cfg_type != P4Config::NET_CFG_PRESET
        log_web_error( "Invalid exploit URL - net_cfg_type = preset, server configuration differs" )
        return
      end

      network_cfg_index = params[ "network_config" ]
      host_cfg_index = params[ "host_config" ]
      
      if network_cfg_index.nil? or host_cfg_index.nil?
        log_web_error( "Invalid exploit URL - net_cfg_type = preset, network_config = #{network_cfg_index.inspect}, host_config = #{host_config_index.inspect}" )
        return
      end
      network_cfg_index = network_cfg_index.to_i()
      host_cfg_index = host_cfg_index.to_i()
      if network_cfg_index >= cfg.networks.size() or host_cfg_index > cfg.hosts.size()
        log_web_error( "Invalid exploit URL - net_cfg_type = preset, configuration indices too large" )
        return
      end

      network_cfg = cfg.networks[ network_cfg_index ]
      host_cfg = cfg.hosts[ host_cfg_index ]

      if network_cfg.nil? or host_cfg.nil?
        log_web_error( "Invalid exploit URL - network_cfg or host_cfg nil: #{network_cfg.inspect}, #{host_cfg.inspect}" )
        return
      end

      # Extract used configurations
      cfg_iface = network_cfg.iface
      cfg_src_ip = network_cfg.src_ip
      cfg_src_mask = network_cfg.src_mask
      
      if network_cfg.dst_ip.instance_of? IPv4Address
        cfg_dst_ip = IPv4Address.new( network_cfg.dst_ip.to_i() + host_cfg.ip_end )
      elsif network_cfg.dst_ip.instance_of? IPv6Address
        cfg_dst_ip = IPv6Address.new( network_cfg.dst_ip ) + host_cfg.ipv6_end 
      end
      cfg_gw = network_cfg.gw
    elsif net_cfg_type == "writable"
      cfg_iface = params[ "netconfig_iface" ]
      cfg_src_ip = params[ "netconfig_src_ip" ]
      cfg_src_mask = nil
      cfg_dst_ip = params[ "netconfig_dst_ip" ]
      cfg_gw = params[ "netconfig_gateway" ]
    else
      log_web_error( "Invalid exploit URL - net_cfg_type = #{net_cfg_type}" )
      return
    end
        
    
    # Work with attack
    cfg_attack = params[ "attack" ]
    attack_cfg_str = ""
    if cfg_attack.nil?
      log_web_error( "Invalid exploit URL - attack missing" )
      return
    end

    attack_info = p4.attacks_by_name[ cfg_attack ]
    if attack_info.nil?
      log_web_error( "Invalid exploit URL - attack \"#{cfg_attack}\" not found" )
      return
    end
    attack_cfg_str << "--attack=#{cfg_attack}"
    
    # Work with payload
    attack_payload_str = ""
    attack_payload = params[ "payload" ]
    if not attack_payload.nil?
    	attack_payload_str << "--payload=#{attack_payload}"
	end

    # Check mode
    mode = params[ "mode" ]
    if mode == "mongbat"
      # Run predator through mongbat
      tool_name = "ruby mongbat.rb --uid=#{$uid}"

      network_cfg_str << "--iface=#{cfg_iface} " if not cfg_iface.nil?
      network_cfg_str << "--attacker=#{cfg_src_ip} " if not cfg_src_ip.nil?
      network_cfg_str << "--victim=#{cfg_dst_ip} " if not cfg_dst_ip.nil?
      network_cfg_str << "--gw=#{cfg_gw} " if not cfg_gw.nil?
      network_cfg_str << "--mask=#{cfg_src_mask} " if not cfg_src_mask.nil?
      network_cfg_str.strip!

      # Work with configuration
      mongbat_cfg_str = ""
      if( params[ "mongbat_time" ].nil? or
          params[ "mongbat_workers" ].nil? or
          params[ "mongbat_minev"].nil? or
          params[ "mongbat_maxev"].nil? or
          params[ "mongbat_stop"].nil? or
          params[ "mongbat_obfuscate"].nil? or
          params[ "mongbat_check_victim"].nil? )

        log_web_error( "Mongbat configuration entries missing!" )
        return
      end
      
      extra_str = ""
      if( params[ "mongbat_stop" ] == "true" )
      	extra_str << "--stop_on_success "
 	  end
 	  if( params[ "mongbat_obfuscate"] != "true" )
 	    extra_str << "--disable_payload_obfuscation "
      end
      if( params[ "mongbat_check_victim"] == "true" )
 	    extra_str << "--check_victim=true "
 	  else
 	    extra_str << "--check_victim=false "
      end
            
      mongbat_cfg_str = "--mode=random --time=#{params['mongbat_time']} --workers=#{params['mongbat_workers']}" +
                        " --min_evasions=#{params['mongbat_minev']} --max_evasions=#{params['mongbat_maxev']} #{extra_str}" + 
                        " --passthrough";
      mode_cfg_str = mongbat_cfg_str
    elsif mode == "presets"
      # Run predator through preset.rb
      tool_name = "ruby preset.rb "

      network_cfg_str << "--if=#{cfg_iface} " if not cfg_iface.nil?
      network_cfg_str << "--src_ip=#{cfg_src_ip} " if not cfg_src_ip.nil?
      network_cfg_str << "--src_port=#{cfg_src_port} " if not cfg_src_port.nil?
      network_cfg_str << "--src_prefix=#{cfg_src_mask} " if not cfg_src_mask.nil?
      network_cfg_str << "--dst_ip=#{cfg_dst_ip} " if not cfg_dst_ip.nil?
      network_cfg_str << "--dst_port=#{cfg_dst_port} " if not cfg_dst_port.nil?
      network_cfg_str << "--dst_mask=#{cfg_dst_mask} " if not cfg_dst_mask.nil?
      network_cfg_str << "--gw=#{cfg_gw} " if not cfg_gw.nil?
      network_cfg_str.strip!

      # Parse
      if( params[ "preset_name" ].nil? )
        log_web_error( "Preset name missing!" )
        return
      end

      preset_cfg_str = "--preset=#{params[ "preset_name" ]}"

      # Remove configured attack, as the preset contains the exploit to use
      attack_cfg_str = ""

      mode_cfg_str = preset_cfg_str
    elsif mode == "evasions"
      # Run predator directly
      tool_name = p4.p4_bin_path

      network_cfg_str << "--if=#{cfg_iface} " if not cfg_iface.nil?
      network_cfg_str << "--src_ip=#{cfg_src_ip} " if not cfg_src_ip.nil?
      network_cfg_str << "--src_port=#{cfg_src_port} " if not cfg_src_port.nil?
      network_cfg_str << "--src_prefix=#{cfg_src_mask} " if not cfg_src_mask.nil?
      network_cfg_str << "--dst_ip=#{cfg_dst_ip} " if not cfg_dst_ip.nil?
      network_cfg_str << "--dst_port=#{cfg_dst_port} " if not cfg_dst_port.nil?
      network_cfg_str << "--dst_mask=#{cfg_dst_mask} " if not cfg_dst_mask.nil?
      network_cfg_str << "--gw=#{cfg_gw} " if not cfg_gw.nil?
      network_cfg_str.strip!

      # Work with evasions
      evasion_cfg_str = ""
      evasions = params[ "evasions" ]
      evasions.split( "___" ).each do |evasion_cfg_string|
        # example: tcp_chaff->tcp_chaff::Probability=100%,tcp_chaff::Chaff type=true,tcp_chaff::Type of urgent data=true
        evasion_name, evasion_cfg = evasion_cfg_string.split( "->", 2 )

        evasion_config = Predator4Module::Evasion.new("", "")

        evasion_info = attack_info.evasions_by_name[ evasion_name ]
        if evasion_info.nil?
          log_web_error( "Invalid exploit URL - attack \"#{cfg_attack}\" does not have an evasion called \"#{evasion_name}\"" )
          return
        end

        evasion_cfg_str << "--evasion=#{evasion_name}"

        option_value_by_name = {}
        evasion_cfg.split( "," ).each do |evasion_opt_cfg|
          evasion_opt_name, evasion_opt_value = evasion_opt_cfg.split( "=", 2 )

          evasion_opt_evname, evasion_opt_optname = evasion_opt_name.split( "::", 2 )
          if( evasion_opt_evname != evasion_name )
            log_web_error( "Invalid exploit URL - evasion configuration \"#{evasion_opt_cfg}\" broken" )
            return
          end

          choice_info = evasion_info.options_by_name[ evasion_opt_optname ]

          if choice_info.nil?
            log_web_error( "Invalid exploit URL - evasion \"#{evasion_name}\" does not have an option called \"#{evasion_opt_optname}\"" )
            return
          end

          opt_index = evasion_info.option_index( choice_info )
          if opt_index.nil?
            log_web_error( "Invalid exploit URL - evasion \"#{evasion_name}\" option \"#{choice_info.name}\" does not have an index" )
            return
          end

          if not option_value_by_name.has_key?(choice_info)
            if opt_index != evasion_config.options.size()
              log_web_error( "Invalid evasion configuration - evasion \"#{evasion_name}\" missing option with index #{evasion_config.options.size()} (#{opt_index})" )
              log_web_error( "Tried to configure opt_index #{opt_index} - #{choice_info.inspect}" )
              return
            end
            evasion_config.options.push choice_info
            option_value_by_name[choice_info] = [evasion_opt_value]
          else
            option_value_by_name[choice_info].push evasion_opt_value
          end
        end
        evasion_config.options.each do |choice_info|
          evasion_cfg_str << ',"' + option_value_by_name[choice_info].join("|") + '"'
        end

        if evasion_config.options.size() != evasion_info.options.size()
          log_web_error( "Invalid evasion configuration - evasion \"#{evasion_info.comment}\" not configured correctly ( expected #{evasion_info.options.size()} options, got #{evasion_config.options.size()})" )
          return
        end

        evasion_cfg_str << " "
        mode_cfg_str = evasion_cfg_str
      end
    else
      log_web_error( "Invalid mode #{params['mode']}!" )
      return
    end

    # Handle exploit extra options
    exploit_extra_str = ""
    exploit_extra_opt = params[ "extra_options" ]

    if not exploit_extra_opt.nil?
      exploit_extra_opt.split( "___" ).each do |extra_opt|
        opt_name, opt_val= extra_opt.split( "=", 2 )
        exploit_extra_str += "--extra=#{opt_name}=#{opt_val} "
      end
    end

    # Handle other configuration options
    other_opt_cfg_str = ""
    auto_close_shell = params[ "auto_close_shell" ]
    if not auto_close_shell.nil?
      if auto_close_shell == "true"
        cfg_auto_close_shell = true
        other_opt_cfg_str << "--autoclose "
      elsif auto_close_shell != "false"
        log_web_error( "Invalid exploit URL - auto_close_shell value \"#{auto_close_shell}\" invalid" )
        return
      end
    end

    clean_set = params[ "clean" ]
    if not clean_set.nil?
      if clean_set == "true"
        attack_payload_str = "--payload=clean"
        cfg_clean = true
      elsif clean_set != "false"
        log_web_error( "Invalid exploit URL - auto_close_shell value \"#{clean_set}\" invalid" )
      end
    end

    if mode == "evasions"
      other_opt_cfg_str << "--shell_tcp "
      other_opt_cfg_str << "--record=#{$webgui_tmp_pcap} "
    end
   
    other_opt_cfg_str.strip!
    
    tail_opt_cfg_str = "--verifydelay=#{$p4_verifydelay} "

    # Build command line command
    cmd = "#{tool_name} #{attack_cfg_str} #{attack_payload_str} #{network_cfg_str} #{other_opt_cfg_str} #{mode_cfg_str} #{exploit_extra_str} #{tail_opt_cfg_str}"
    cmd.strip!

    # Construct log destination path
    log_path= "log/"
    if cfg.net_cfg_type == P4Config::NET_CFG_PRESET
      # Use <network_name>_<host_name> as key
      log_path += network_cfg.name + "_" + host_cfg.name + "/"
    elsif net_cfg_type == "writable"
      log_path += "writable/"
    else
      log_web_error( "Invalid network configuration type" )
      return
    end
      

    # Run!
    @@mutex.synchronize do
      if not @@exploit_inst.nil?
        log_web_error( "Already running an exploit!" )
        return
      end

      # Generate an unique ID for this attack run - current time should be unique enough as we are in a mutex
      # This is used for the packet capture and log file
      unique_id = Time.new().strftime( "%C%y%m%d_%k%M%S_%3N") # <year><month><day>_<hour><minute><second>_<milliseconds>
      register_exploit( P4Exploit.new( cmd, log_path, unique_id ) )
    end

    puts "Started exploit with command #{cmd}"
  end

  def P4WebGUI::exploit_stop( params )
    @@mutex.synchronize do
      if @@exploit_inst.nil?
        log_web_info( "No exploit to stop" )
      else
        @@exploit_inst.close()
        log_web_info( "Exploit stopped" )
        @@exploit_inst = nil
      end
    end
  end

  def P4WebGUI::generate_log_html( params )
    session_id = params[ "session_id" ]
    if session_id.nil?
      log_error( "generate_log_html() - params does not include session_id!" )
      return ""
    end
    
    @@log_mutex.synchronize do
      if @@log_offsets[ session_id ].nil?
        @@log_offsets[ session_id ] = 0
      end
      curr_offset = @@log_offsets[ session_id ]
      if curr_offset > @@web_log.size()
        curr_offset = @@log_offsets[ session_id ] = @@web_log.size()
      end

      output_str = @@web_log[ curr_offset..-1 ]
      @@log_offsets[ session_id ] += output_str.size()
      return output_str
    end
  end
  
  def P4WebGUI::get_network_config_js()
    if @@network_config_js_file.nil?
      @@mutex.synchronize do
        generate_network_config_js_file()
      end
    end
    return @@network_config_js_file
  end

  def P4WebGUI::get_exploits_js()
    if @@exploits_js_file.nil?
      @@mutex.synchronize do
        generate_exploits_js_file()
      end
    end
    return @@exploits_js_file
  end

  def P4WebGUI::get_evasions_js()
    if @@evasions_js_file.nil?
      @@mutex.synchronize do
        generate_evasions_js_file()
      end
    end
    return @@evasions_js_file
  end

  def P4WebGUI::get_presets_js()
    if @@presets_js_file.nil?
      @@mutex.synchronize do
        generate_presets_js_file()
      end
    end
    return @@presets_js_file
  end

  # Return HTML for exploit selector
  def P4WebGUI::exploits_html()
    if @@exploits_html_file.nil?
      @@mutex.synchronize do
        generate_exploits_html()
      end
    end
    return @@exploits_html_file
  end

  def P4WebGUI::right_table_html()
    if @@right_table_html_file.nil?
      @@mutex.synchronize do
        generate_right_table_html()
      end
    end
    return @@right_table_html_file
  end

  def P4WebGUI::generate_right_table_html()
    arr = []

    # This is different based on our binary
    p4 = DataStore::get_predator4()
    
    # Selector between single evasions & mongbat
    arr.push "Mode: "
    arr.push "<select size=\"1\" id=\"mode\" onchange=\"ModeChanged()\">"
    arr.push "\t<option value=\"mode_evasions\"> Evasions </option>"
    arr.push "\t<option value=\"mode_mongbat\"> Mongbat </option>"
    if not p4.presets.nil?
      arr.push "\t<option value=\"mode_presets\"> Presets </option>"
    end
    arr.push "</select>"

    arr.push "<br><br>"

    # Mongbat
    arr.push "<div id=\"mongbat_bg\" class=\"evasion_bg\" style=\"display:none\" >"
    arr.push "<table>"
    arr.push "<tr><td><p>Workers:</p></td><td> <input type=\"text\" id=\"mongbat_workers\" value=\"16\"></input></td></tr>"
    arr.push "<tr><td><p>Time:</p></td><td> <input type=\"text\" id=\"mongbat_time\" value=\"60\"></input></td></tr>"
    arr.push "<tr><td><p>Min evasions:</p></td><td> <input type=\"text\" id=\"mongbat_min_evasions\" value=\"2\"></input></td></tr>"
    arr.push "<tr><td><p>Max evasions:</p></td><td> <input type=\"text\" id=\"mongbat_max_evasions\" value=\"4\"></input></td></tr>"
    arr.push "<tr><td><p><input id='mongbat_stop_on_success' type=\"checkbox\" checked> Stop on success </input>"
    arr.push "<tr><td><p><input id='mongbat_obfuscate' type=\"checkbox\" checked> Obfuscate payload </input>"
    arr.push "<tr><td><p><input id='mongbat_check_victim' type=\"checkbox\" checked> Check victim status </input>"
    arr.push "</table>"
    arr.push "</div>"
    arr.push "</div>"

    # Presets
    if not p4.presets.nil?
      arr.push "<div id=\"preset_bg\" class=\"evasion_bg\" style=\"display:none\">"
      arr.push presets_html()
      arr.push "</div>"
    end

    # Evasions
    arr.push "<div id=\"evasion_bg\" class=\"evasion_bg\">"
    arr.push evasions_html()
    arr.push "</div>"
   

    @@right_table_html_file = arr.join( "\r\n" )

  end
  
  # Generate exploits_html content
  def P4WebGUI::generate_exploits_html()
    arr = []
    arr.push "<select id=\"exploits\" onchange=\"ExploitChanged()\">\n"

    p4 = DataStore::get_predator4()
    p4.attacks.each do |attack|
      arr.push "<option value=\"#{attack.short_name}\" id=\"#{attack.short_name}\"> #{attack.name} </option>"
    end

    arr.push "</select>"
    @@exploits_html_file = arr.join( "\r\n" )
  end

  # Return HTML for network configuration
  def P4WebGUI::network_configs_html()
    if @@network_configs_html_file.nil?
      generate_network_configs_html_file()
    end

    return @@network_configs_html_file
  end

  def P4WebGUI::generate_network_configs_html_file()
    cfg = DataStore::get_config()
    if cfg.net_cfg_type == P4Config::NET_CFG_WRITABLE
      # Generate input fields
      arr = []
      arr.push "<table>"
      arr.push "<tr><td><p>Interface:</p></td><td><input type=\"text\" id=\"netconfig_iface\"></input></td></tr>"
      arr.push "<tr><td><p>Source IP:</p></td><td><input type=\"text\" id=\"netconfig_src_ip\"></input></td></tr>"
      arr.push "<tr><td><p>Destination IP:</p></td><td><input type=\"text\" id=\"netconfig_dst_ip\"></input></td></tr>"
      arr.push "<tr><td><p>Gateway IP:</p></td><td><input type=\"text\" id=\"netconfig_gateway\"></input></td></tr>"
      arr.push "</table>"

      @@network_configs_html_file = arr.join( "\r\n" )
    elsif cfg.net_cfg_type == P4Config::NET_CFG_PRESET
      # Generate two dropdown menus
      arr = []
      arr.push "<select id=\"network_config\" onchange=\"NetworkConfigChanged()\">\n"
      cfg.networks.each do |net|
        arr.push "\t" + net.to_html()
      end
      arr.push "</select>"

      arr.push "<select id=\"host_config\" onchange=\"NetworkConfigChanged()\">\n"
      cfg.hosts.each do |host|
        arr.push "\t" + host.to_html()
      end
      arr.push "</select>"

      arr.push "<table>"
      arr.push "<tr><td><p>Name:</p></td><td><p id=\"netconfig_name\">a</p></td></tr>"
      arr.push "<tr><td><p>Interface:</p></td><td><p id=\"netconfig_iface\">a</p></td></tr>"
      arr.push "<tr><td><p>Gateway IP:</p></td><td><p id=\"netconfig_gateway\">a</p></td></tr>"
      arr.push "<tr><td><p>Source IP:</p></td><td><p id=\"netconfig_src_ip\">a</p></td></tr>"
      arr.push "<tr><td><p>Source mask:</p></td><td><p id=\"netconfig_src_mask\">a</p></td></tr>"
      arr.push "<tr><td><p>Source MAC:</p></td><td><p id=\"netconfig_src_mac\">a</p></td></tr>"
      arr.push "<tr><td><p>Destination IP:</p></td><td><p id=\"netconfig_dst_ip\">a</p></td></tr>"
      arr.push "<tr><td><p>Destination mask:</p></td><td><p id=\"netconfig_dst_mask\">a</p></td></tr>"
      arr.push "</table>"

      @@network_configs_html_file = arr.join( "\r\n" )
    else
      return ""
    end
    
  end
  
  def P4WebGUI::generate_exploits_js_file()
    arr = []
    arr.push "var exploit_arr = new Array();"

    evasion_hash = {}

    p4 = DataStore::get_predator4()
    p4.attacks.each do |attack|
      preamble = "exploit_arr[ \"#{attack.short_name}\" ]"

      arr.push preamble + " = new Array();"
      arr.push preamble + "[ \"name\" ] = \"#{attack.name}\";"
      arr.push preamble + "[ \"short_name\" ] = \"#{attack.short_name}\";"
      arr.push preamble + "[ \"cve\" ] = \"#{attack.cve}\";"
      arr.push preamble + "[ \"description\" ] = \"#{escape_log_web( attack.desc )}\";"
      arr.push preamble + "[ \"payloads\" ] = new Array();"
      arr.push preamble + "[ \"payload_name\" ] = new Array();"
      arr.push preamble + "[ \"extra_options\" ] = new Array();"
      arr.push preamble + "[ \"evasions\" ] = new Array();"
      arr.push preamble + "[ \"evasion_ifaces\" ] = new Array();"
     
      preamble = preamble + "[ \"evasions\" ]"
      uniq_ifaces = {}
      attack.evasions.size.times do |i|
        arr.push preamble + "[ #{i} ] = \"#{attack.evasions[ i ]}\";"

        iface_name, ev_name = attack.evasions[ i ].name.split( "_", 2 )
        if uniq_ifaces[ iface_name ].nil?
          uniq_ifaces[ iface_name ] = true


          if evasion_hash[ attack.short_name ].nil?
            evasion_hash[ attack.short_name ] = 0
          else
            evasion_hash[ attack.short_name ] = evasion_hash[ attack.short_name ] + 1
          end
          arr.push "exploit_arr[ \"#{attack.short_name}\" ][ \"evasion_ifaces\" ][ #{evasion_hash[ attack.short_name ]} ] = \"#{iface_name}\";"
        end
      end

      preamble = "exploit_arr[ \"#{attack.short_name}\" ][ \"extra_options\" ]"
      attack.extra_options.size.times do |i|
        opt = attack.extra_options[ i ]
        arr.push preamble + "[#{i}] = \"#{opt.name}\";"
      end
      
      preamble = "exploit_arr[ \"#{attack.short_name}\" ]"
      attack.payloads.size.times do |i|
      	arr.push preamble + "[ \"payloads\" ][ #{i} ] = \"#{attack.payloads[ i ]}\";"
      	arr.push preamble + "[ \"payload_name\" ][ #{i} ] = \"#{attack.payload_to_guiname[ attack.payloads[ i ] ]}\";"
      end
    end

    @@exploits_js_file = arr.join( "\r\n" )
  end

  def P4WebGUI::generate_evasions_js_file()
    arr = []
    arr.push "var evasion_arr = new Array();"
    arr.push "var evasion_opt_arr = new Array();"
    arr.push "var evasion_iface_arr = new Array();"

    # Each attack can have its own set of evasions - find all unique evasions
    uniq_evasions = {}
    uniq_ifaces = {}
    preamble = nil

    p4 = DataStore::get_predator4()
    p4.attacks.each do |attack|
      attack.evasions.each do |ev|
        if uniq_evasions[ ev.name ].nil?
          uniq_evasions[ ev.name ] = ev

          proto, ev_name = ev.name.split( "_", 2 )
          if uniq_ifaces[ proto ].nil?
            uniq_ifaces[ proto ] = proto
          end
        end
      end
    end

    # Add unique interfaces
    uniq_ifaces.each_key do |key|
      arr.push "evasion_iface_arr[ \"#{key}\" ] = \"#{key}\";"
    end

    # Add each unique evasion
    uniq_evasions.each_key do |key|
      evasion = uniq_evasions[ key ]

      # Evasion name is in the form <protocol>_<evasion>
      # Use <protocol> as a key to evasion_iface_arr

      arr.push "evasion_arr[ \"#{key}\" ] = \"#{key}\";"
      
      preamble = "evasion_opt_arr[ \"#{key}\" ]"
      arr.push preamble + " = new Array();"

      evasion.options.size.times do |i|
        opt = evasion.options[ i ]

        arr.push preamble + "[ #{i} ] = new Array();"
        arr.push preamble + "[ #{i} ][ \"name\" ] = \"#{opt.name}\";"

        if opt.instance_of? Predator4Module::IntegerOption
          arr.push preamble + "[ #{i} ][ 0 ] = \"integer\";"
          arr.push preamble + "[ #{i} ][ \"min\" ] = #{opt.min};"
          arr.push preamble + "[ #{i} ][ \"max\" ] = #{opt.max};"
          arr.push preamble + "[ #{i} ][ \"step\" ] = #{opt.step};"
        elsif opt.instance_of? Predator4Module::PropabilityOption
          arr.push preamble + "[ #{i} ][ 0 ] = \"probability\";"
        elsif opt.instance_of? Predator4Module::ChoiceOption
          arr.push preamble + "[ #{i} ][ 0 ] = \"choice\";"

          if opt.single_valid
            arr.push preamble + "[ #{i} ][ \"single\" ] = true;"
          else
            arr.push preamble + "[ #{i} ][ \"single\" ] = false;"
          end
          
          choice_names = opt.choices.keys()
          choice_names.size.times do |j|
            choice_name = choice_names[ j ]
            choice_desc = opt.choices[ choice_name ]

            arr.push preamble + "[ #{i} ][ #{j+1} ] = new Array();"
            arr.push preamble + "[ #{i} ][ #{j+1} ][ \"name\" ] = \"#{choice_name}\";"
            arr.push preamble + "[ #{i} ][ #{j+1} ][ \"desc\" ] = \"#{choice_desc}\";"
          end
        end
      end
    end

    @@evasions_js_file = arr.join( "\r\n" )
  end

  def P4WebGUI::generate_network_config_js_file()
    arr = []
    
    cfg = DataStore::get_config()
    if cfg.net_cfg_type == P4Config::NET_CFG_PRESET
      arr.push "var host_config_arr = new Array();"

      cfg.hosts.each do |host|
        preamble = "host_config_arr[ #{host.id} ]"

        arr.push preamble + " = new Array();"
        arr.push preamble + "[ \"name\" ] = \"#{host.name}\";"
        arr.push preamble + "[ \"ipv4_end\" ] = \"#{host.ip_end.to_s(10)}\";" if not host.ip_end.nil?
        arr.push preamble + "[ \"ipv6_end\" ] = \"#{host.ipv6_end.to_s(16)}\";" if not host.ipv6_end.nil?                
      end

      arr.push "var network_config_arr = new Array();"

      cfg.networks.each do |network|
        preamble = "network_config_arr[ \"#{network.id}\" ]"

        arr.push preamble + " = new Array();"
        arr.push preamble + "[\"name\"] = \"#{network.name}\";"   if not network.name.nil?
        arr.push preamble + "[\"iface\"] = \"#{network.iface}\";"   if not network.iface.nil?
        arr.push preamble + "[\"gw\"] = \"#{network.gw}\";"   if not network.gw.nil?
        
        if not network.src_ip.nil?
          if network.src_ip.instance_of? IPv4Address
            arr.push preamble + "[\"src_ipv4\"] = \"#{network.src_ip}\";"   if not network.src_ip.nil?
          elsif network.src_ip.instance_of? IPv6Address
            arr.push preamble + "[\"src_ipv6\"] = \"#{network.src_ip}\";"   if not network.src_ip.nil?
          end
        end

        arr.push preamble + "[\"src_mask\"] = \"#{network.src_mask}\";"   if not network.src_mask.nil?
        
        if not network.dst_ip.nil?
          if network.dst_ip.instance_of? IPv4Address
            arr.push preamble + "[\"dst_ipv4\"] = \"#{network.dst_ip}\";"
          elsif network.dst_ip.instance_of? IPv6Address
            arr.push preamble + "[\"dst_ipv6\"] = \"#{network.dst_ip}\";"
          end
        end
      end

      @@network_config_js_file = arr.join( "\r\n" )
    elsif cfg.net_cfg_type == P4Config::NET_CFG_WRITABLE
      @@network_config_js_file = ""
    end
  end

  def P4WebGUI::generate_presets_js_file()
    arr = []
    arr.push "var preset_arr = new Array();"

    p4 = DataStore::get_predator4()
    if not p4.presets.nil?
      p4.presets.each do |preset|
        preamble = "preset_arr[ \"#{preset.name}\" ]"
  
        arr.push preamble + " = new Array();"
        arr.push preamble + "[ \"name\" ] = \"#{preset.name}\";"
        arr.push preamble + "[ \"desc\" ] = \"#{preset.desc}\";"
        arr.push preamble + "[ \"size\" ] = \"#{preset.size}\";"
        arr.push preamble + "[ \"attack\" ] = \"#{preset.attack}\";"
      end
    end

    @@presets_js_file = arr.join( "\r\n" )
  end

  # Return HTML for exploit options
  def P4WebGUI::exploit_options_html()
    if @@exploit_options_html_file.nil?
      generate_exploit_options_html_file()
    end
    return @@exploit_options_html_file
  end

  def P4WebGUI::generate_exploit_options_html_file()
    arr = []

    p4 = DataStore::get_predator4()
    p4.attacks.each do |attack|
      arr.push "<div id=\"opt_#{attack.short_name}_div\" class=\"opt_hidden\">"
      
      # Generate payload options
      pl_base = "opt_#{attack.short_name}_payloads";
      checked = "checked"
      attack.payloads.size.times do |i|
        pl = attack.payloads[ i ]
      	input_id = "#{attack.short_name+"_"+pl}"
      	arr.push "<input type='radio' name='#{pl_base}' id='#{input_id}' class='evtree-select' value='1' #{checked}> #{attack.payload_to_guiname[ pl ]} </input><br>"
      	checked = ""
  	  end      	
      
      # Generate extra options      
      attack.extra_options.each do |opt|
        input_id = "#{attack.short_name+"_"+opt.name}"
        if opt.type == "int"
          arr.push "<input id='#{input_id}' class=\"evtree-select\" value=\"\" size=5>"
          arr.push "<label for='#{input_id}'> #{opt.comment} </label>"
          arr.push "<br>"
        elsif opt.type == "string"
          arr.push "<input id='#{input_id}' class=\"evtree-select\" value=\"\" size=5>"
          arr.push "<label for='#{input_id}'> #{opt.comment} </label>"
          arr.push "<br>"
        elsif opt.type == "bool"
          arr.push "<input id='#{input_id}' type=\"checkbox\"> #{opt.comment} </input>"
          arr.push "<br>"
        else
          raise "Unknown option type: #{opt.type}"
        end
      end         
      arr.push "</div>"
    end

    @@exploit_options_html_file = arr.join( "\r\n" )
  end

  # Return HTML for evasion presets
  def P4WebGUI::presets_html()
    if @@presets_html_file.nil?
        generate_presets_html_file()
    end
    return @@presets_html_file
  end

  def P4WebGUI::generate_presets_html_file()
    arr = []
    arr.push "<table>"
    arr.push "<tr><td>Preset:</td><td><select id=\"evasion_presets\" onchange=\"EvasionPresetChanged()\">"
    p4 = DataStore::get_predator4()
    p4.presets.each do |preset|
      arr.push "<option value=\"#{preset.name}\"> #{preset.name} </option>"
    end
    arr.push "</select>"
    arr.push "<tr><td>Desc:</td><td><p id=\"preset_desc\">a</p></td></tr>"
    arr.push "<tr><td>Size:</td><td><p id=\"preset_size\">a</p></td></tr>"
    arr.push "</table>"

    @@presets_html_file = arr.join( "\r\n" )
  end
  
  # Return HTML for single evasions
  def P4WebGUI::evasions_html()
    if @@evasions_html_file.nil?
      generate_evasions_html_file()
    end
    return @@evasions_html_file
  end

  # Generate a handmade <ul> tree with all our features as all available
  # javascript trees seem to have issues.
  def P4WebGUI::generate_evasions_html_file()
    arr = []

    #
    # Define a static order for protocols for sanity
    iface_order = [ "eth",
                    "ipv4", "ipv6",
                    "tcp", "udp",
                    "netbios",
                    "smb",
                    "msrpc",
                    "http" ]

    # Define a tidy output
    iface_tidy_name = {}
    iface_tidy_name[ "eth" ] = "Ethernet"
    iface_tidy_name[ "ipv4" ] = "IPv4"
    iface_tidy_name[ "ipv6" ] = "IPv6"
    iface_tidy_name[ "tcp" ] = "TCP"
    iface_tidy_name[ "udp" ] = "UDP"
    iface_tidy_name[ "netbios" ] = "NetBIOS"
    iface_tidy_name[ "smb" ] = "SMB"
    iface_tidy_name[ "msrpc" ] = "MSRPC"
    iface_tidy_name[ "http" ] = "HTTP"

    ## Extract all unique evasions from all attacks
    uniq_evasions = {}
    uniq_ifaces = {}

    p4 = DataStore::get_predator4()
    p4.attacks.each do |attack|
      attack.evasions.each do |ev|
        if uniq_evasions[ ev.name ].nil?
          uniq_evasions[ ev.name ] = ev

          proto, ev_name = ev.name.split( "_", 2 )
          if uniq_ifaces[ proto ].nil?
            uniq_ifaces[ proto ] = []
          end
          uniq_ifaces[ proto ].push ev
        end
      end
    end

    arr.push << "<div id=\"evasions_evtree\" class=\"evasions_evtree\">"
    arr.push << "<ul>"

    # Option names may overlap - create a hash and use running numbers to keep track
    option_names = {}
    input_type = nil
    field_width = 0
    
    # Traverse evasions by interface
    iface_order.each do |iface_name|
      if uniq_ifaces[ iface_name ].nil?
        next
      end

      li_id = "#{iface_name}_li"
      arr.push "<li id=\"#{li_id}\" class=\"evtree-open\">"  # Cant close top levels
      arr.push "<input type=\"checkbox\" id=\"#{iface_name}_checkbox\" +
                  onchange=\"javascript:EVTreeCheckboxClicked('#{iface_name}_checkbox')\" + 
                  disabled=\"true\"></input>"
      arr.push "<a href=\"javascript:EVTreeToggle('#{iface_name}');\" class=\"evtree_li_a\"> + </a>"
      arr.push "<a href=\"javascript:EVTreeToggle('#{iface_name}');\" class=\"evtree_li_a\"> #{iface_tidy_name[ iface_name ]} </a>"

      arr.push "<ul>"
      uniq_ifaces[ iface_name ].each do |evasion|
        evasion_name = evasion.comment
        evasion_sname = evasion.name
        li_id = "#{evasion_sname}_li"

        arr.push "<li id=\"#{li_id}\" class=\"evtree-closed\">"
        arr.push "<input type=\"checkbox\" id=\"#{evasion_sname}_checkbox\" +
                  onchange=\"javascript:EVTreeCheckboxClicked('#{evasion_sname}_checkbox')\"></input>"

        if evasion.options.empty?
          # No options - just add the evasion itself
          arr.push "&nbsp;&nbsp;&nbsp;#{evasion_name}"
        else
          # Got options, add each
          arr.push "<a href=\"javascript:EVTreeToggle('#{evasion_sname}');\" class=\"evtree_li_a\"> + </a>"
          arr.push "<a href=\"javascript:EVTreeToggle('#{evasion_sname}');\" class=\"evtree_li_a\"> #{evasion_name} </a>"
          arr.push "<ul>"

          evasion.options.each do |opt|
            li_id = "#{opt.name}_li"

            if option_names[ li_id ].nil?
              option_names[ li_id ] = 1
            else
              num = option_names[ li_id ]
              option_names[ li_id ] = num + 1
              li_id << "__#{num.to_s()}"
            end

            arr.push "<li id=\"#{li_id}\" class=\"evtree-leaf-closed\">"
            opt_id = "#{evasion_sname}::#{opt.name}"
            arr.push "#{opt.name}<br>"
            if opt.instance_of? Predator4Module::IntegerOption
              field_width = [ opt.min.to_s().size(), opt.max.to_s().size() ].max + 1
              arr.push "<input id='#{evasion_sname}::#{opt.name}' class=\"evtree-select\" value=\"#{opt.max}\" size=#{field_width}/>"
              arr.push "<label for='#{opt_id}'> Int, [#{opt.min}-#{opt.max},#{opt.step}]"
              arr.push "<br>"
            elsif opt.instance_of? Predator4Module::PropabilityOption
              arr.push "<input id='#{evasion_sname}::#{opt.name}' class=\"evtree-select\" value='100%' size=4/>"
              arr.push "<br>"
            elsif opt.instance_of? Predator4Module::ChoiceOption
              arr.push "<ul>"
              opt.choices.each_key do |key|
                choice_name = key
                choice_id = "#{evasion_sname}::#{opt.name}::#{choice_name}"

                if opt.single_valid
                  input_type = "radio"
                else
                  input_type = "checkbox"
                end

                arr.push "<li id=\"#{choice_id}\" class=\"evtree-leaf-closed\">"
                arr.push "<input type=\"#{input_type}\" name=\"#{opt_id}\" id=\"#{choice_id}_checkbox\"> #{opt.choices[ key ]} </input>"
                arr.push "</li>"
              end
              arr.push "</ul>"
            end

            arr.push "</li>"
          end
          arr.push "</ul>"
        end
        arr.push "</li>"
      end
      arr.push "</ul>"
      arr.push "</li>"
    end

    arr.push << "</ul>"

    @@evasions_html_file = arr.join( "\r\n" )

  end

  # Return HTML for log reader
  def P4WebGUI::log_reader_html()
    if @@log_reader_html_file.nil?
      @@mutex.synchronize do
        generate_log_reader_html_file()
      end
    end
    return @@log_reader_html_file
  end

  def P4WebGUI::generate_log_reader_html_file()
    arr = []
    arr.push "<div class=\"log\" id=\"log\"></div>"
    arr.push "<script language=\"javascript\" type=\"text/javascript\">"
    arr.push "$( '.log' ).html( '' );"
    arr.push "var refreshId = setInterval( function()
          {
          	$.ajax({
          		url: '/log?session_id=' + session_id,
          		data: '',
          		success: function( data ) 
          		{
                  if( data.length > 0 )
                  {
                    var new_log = $( '.log' ).html() + data;
                    $( '.log' ).html( new_log );
                  }
                },
				cache: false
			});                
          }, 250 );"
    arr.push "</script>"
    @@log_reader_html_file = arr.join( "\r\n" )
  end
    
  # Return HTML for shell reader
  def P4WebGUI::get_shell_reader_html()

    # Cannot be autogenerated as session id's change
    if @@shell_reader_html_file.nil?
      generate_shell_reader_html_file()
    end

    return @@shell_reader_html_file
  end

  # Generate shell reader HTML
  def P4WebGUI::generate_shell_reader_html_file()
    arr = []
    arr.push "<div class=\"command_shell\">"
    arr.push "</div>"
    arr.push "<script type='text/javascript'>"
    arr.push "command_shell_refresh_id = setInterval( function()
              {
                $.ajax( { url: \"shell/read?session_id=\" + session_id,
                          data: '',
                          success: function( data )
                            {
                              if( data.length > 0 )
                              {
                                var curr_data = $(\".command_shell\").html()
                                curr_data += data
                                $(\".command_shell\").html( curr_data );
                              }
                            },
                            cache: false
                        });
              }, 100 );"
    arr.push "</script>"
    @@shell_reader_html_file = arr.join( "\r\n" )
  end

  # Return HTML for version
  def P4WebGUI::version_html()
    p4 = DataStore::get_predator4()
    return p4.version
  end

  def P4WebGUI::escape_log_web( str )
    escaped = str.chomp
    escaped.gsub!( "<", "&lt;" )
    escaped.gsub!( ">", "&gt;" )
    escaped.gsub!( /(\r\n|\r|\n)/, "<br>" )
    return escaped
  end

  def P4WebGUI::log_web( str, escape=true )
    use_mutex = true

    begin
      @@mutex.lock()
    rescue ThreadError
      use_mutex = false
    end

    if escape
      final_str = escape_log_web( str )
    else
      final_str = str
    end

    # Make http://<ip address>:<port>/ -strings into links
    if final_str =~ /(http:\/\/\d+\.\d+\.\d+\.\d+(:(\d+))?\/([^\x20\x09])*)/
      url = $1
      final_str.gsub!( url, "<a class=\"log_link\" href=\"#{url}\">#{url}</a>" )
    end
    
    @@web_log.push final_str
    @@mutex.unlock if use_mutex
  end

  def P4WebGUI::log_web_info( str, escape=true )
    use_mutex = true

    begin
      @@mutex.lock()
    rescue ThreadError
      use_mutex = false
    end

    if escape
      final_str = escape_log_web( str ) + "<br>"
    else
      final_str = str
    end
    
    @@web_log.push "Info: #{final_str}"
    @@mutex.unlock if use_mutex
  end

  def P4WebGUI::log_web_error( str, escape=true )
    use_mutex = true
   
    begin
      @@mutex.lock()
    rescue ThreadError
      use_mutex = false
    end

    if escape
      final_str = escape_log_web( str ) + "<br>"
    else
      final_str = str
    end
    
    @@web_log.push "Error: #{final_str}"
    @@mutex.unlock if use_mutex
  end

  def P4WebGUI::register_exploit( expl_inst )
    use_mutex = true

    begin
      @@mutex.lock()
    rescue ThreadError
      use_mutex = false
    end

    if not @@exploit_inst.nil?
      raise "Exploit not nil!"
    end
    @@exploit_inst = expl_inst

    @@mutex.unlock if use_mutex
  end
  
  def P4WebGUI::unregister_exploit( expl_inst )
    use_mutex = true

    begin
      @@mutex.lock()
    rescue ThreadError
      use_mutex = false
    end

    if @@exploit_inst.nil?
      puts " P4WebGUI::unregister_exploit( expl_inst ) - Exploit nil!"
      return
    elsif @@exploit_inst != expl_inst
      raise "Exploit not correct!"
    end
    @@exploit_inst = nil

    @@mutex.unlock if use_mutex
  end
  
  def P4WebGUI::page_title()
    if $is_evader
      return "Evader"
    else
      return "Predator4"
    end
  end

  log_web_info( "WebGUI started on #{Time.new()}" )

end
