Analyzing Web Application Test Data with WASEQuery

In a previous article I introduced WASE with ElasticBurp and shown queries that might be useful in web application security tests. Kibana, the ElasticSearch frontend used in the examples has some issues in handling of nested documents that were used in WASE to represent headers and parameters from HTTP requests and responses. Further, the output is often not suitable for simple copy&pasting into test documentation. This was the reason for developing another tool for performing queries and aggregations I regularly use in web application tests: WASEQuery.

One example from my previous article was the search for missing security headers in HTTP responses. WASEQuery implements a subcommand missingheader for this purpose:

$ ./WASEQuery.py missingheader x-content-type-options
https://www.google.de:443/search?q=test&biw=1920&bih=957&source=lnms&tbm=isch&sa=X&ved=0ahUKEwiNquek7rLOAhUDshQKHWb1B5EQ_AUIBigB
https://www.instagram.com:443/ajax/bz
http://instagram.com:80/
http://www.google.de:80/
https://aus5.mozilla.org:443/update/3/GMP/48.0/20160805135620/Linux_x86_64-gcc3/null/release-cck-%20%C3%A2%C2%80%C2%9Cmint%C3%A2%C2%80%C2%9D/Linux%203.19.0-32-generic%20(GTK%203.10.8%2Clibpulse%204.0.0)/mint/1.0/update.xml
https://aus5.mozilla.org:443/update/3/SystemAddons/48.0/20160805135620/Linux_x86_64-gcc3/null/release-cck-%20%C3%A2%C2%80%C2%9Cmint%C3%A2%C2%80%C2%9D/Linux%203.19.0-32-generic%20(GTK%203.10.8%2Clibpulse%204.0.0)/mint/1.0/update.xml
https://facebook.com:443/
https://fonts.googleapis.com:443/css?family=Open+Sans:300,400&lang=de
https://fonts.googleapis.com:443/css?family=Roboto:300,400,500&lang=de
https://instagramstatic-a.akamaihd.net:443/h1/bundles/en_US_Commons.js/2497f0ddce89.js
https://instagramstatic-a.akamaihd.net:443/h1/bundles/en_US_LandingPage.js/a645674e355c.js
[...]

This lists all URLs where the response lacks the X-Content-Type-Options header. Usually the index is polluted with other requests like third-party content or Browser-originated requests. The --domain parameter (shortcut -d) allows to filter for domains. This parameter may contain wildcards and can be set multiple times to specify a list of domains that should be displayed:

$ ./WASEQuery.py -d '*.instagram.*' -d 'facebook.com' missingheader x-content-type-options
https://www.instagram.com:443/ajax/bz
https://facebook.com:443/
https://www.instagram.com:443/

The --invert (-i) switch inverts the results and shows, which URLs contain the header:

./WASEQuery.py -d '*.facebook.com' missingheader -i x-content-type-options
https://staticxx.facebook.com:443/connect/xd_arbiter/r/Lcj5EtQ5qmD.js?version=42
https://www.facebook.com:443/
https://www.facebook.com:443/impression.php/f1e067c67af358c/?api_key=124024574287414&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D
[...]

The subcommand missingparameter works simmilar and matches missing request parameters, like missing CSRF tokens. The search can be restricted to request of given HTTP methods by the --method (-m) parameter.

Security headers are not so simple that the presence of a header implies a binary yes/no answer regarding potential vulnerabilities. This applies especially to complex headers like Content-Security-Policy. The subcommand headervalues extracts all values of the given HTTP response headers and prints it optionally with an URL list. This command shows all Content Security Policies that appear in the searched index:

$ ./WASEQuery.py headervalues content-security-policy
default-src * data: blob:;script-src *.facebook.com *.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* 'unsafe-inline' 'unsafe-eval' fbstatic-a.akamaihd.net fbcdn-static-b-a.akamaihd.net *.atlassolutions.com blob: data:;style-src * 'unsafe-inline' data:;connect-src *.facebook.com *.fbcdn.net *.facebook.net *.spotilocal.com:* *.akamaihd.net wss://*.facebook.com:* https://fb.scanandcleanlocal.com:* *.atlassolutions.com attachment.fbsbx.com ws://localhost:* blob:;
default-src * data: blob:;script-src *.facebook.com *.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* 'unsafe-inline' 'unsafe-eval' fbstatic-a.akamaihd.net fbcdn-static-b-a.akamaihd.net *.atlassolutions.com blob: data:;style-src * 'unsafe-inline' data:;connect-src *.facebook.com *.fbcdn.net *.facebook.net *.spotilocal.com:* *.akamaihd.net wss://*.facebook.com:* https://fb.scanandcleanlocal.com:* *.atlassolutions.com attachment.fbsbx.com ws://localhost:* blob: chrome-extension://boadgeojelhgndaghljhdicfkmllpafd;
report-uri /_/ConsentHttp/cspreport;script-src 'unsafe-inline' 'self' 'unsafe-eval' https://apis.google.com https://ssl.gstatic.com https://www.google.com https://www.gstatic.com
script-src 'self' https://addons.mozilla.org https://www.paypalobjects.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://ssl.google-analytics.com https://addons.cdn.mozilla.net; default-src 'self'; img-src 'self' data: blob: https://www.paypal.com https://ssl.google-analytics.com https://addons.cdn.mozilla.net https://static.addons.mozilla.net https://sentry.prod.mozaws.net; media-src https://videos.cdn.mozilla.net; style-src 'self' 'unsafe-inline' https://addons.cdn.mozilla.net; frame-src 'self' https://ic.paypal.com https://paypal.com https://www.google.com/recaptcha/ https://www.paypal.com; object-src 'none'; connect-src 'self' https://sentry.prod.mozaws.net; font-src 'self' https://addons.cdn.mozilla.net; report-uri /__cspreport__
default-src 'self'; connect-src 'self'; font-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com data:; frame-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; frame-ancestors 'self'; img-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com data:; media-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; object-src 'none'; script-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; style-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; report-uri https://twitter.com/i/csp_report?a=NVQWGYLXFVRXG4A%3D&ro=false;
script-src https://connect.facebook.net https://cm.g.doubleclick.net https://ssl.google-analytics.com https://graph.facebook.com https://twitter.com 'unsafe-eval' https://*.twimg.com https://api.twitter.com https://analytics.twitter.com https://publish.twitter.com https://ton.twitter.com https://syndication.twitter.com https://www.google.com https://t.tellapart.com https://platform.twitter.com 'nonce-EsKk+GaYa2fM615jt4iymg==' https://www.google-analytics.com 'self'; frame-ancestors 'self'; font-src https://twitter.com https://*.twimg.com data: https://ton.twitter.com https://fonts.gstatic.com https://maxcdn.bootstrapcdn.com https://netdna.bootstrapcdn.com 'self'; media-src https://twitter.com https://*.twimg.com https://ton.twitter.com blob: 'self'; connect-src https://graph.facebook.com https://*.giphy.com https://*.twimg.com https://api.twitter.com https://pay.twitter.com https://analytics.twitter.com https://media.riffsy.com https://upload.twitter.com https://api.mapbox.com 'self'; style-src https://fonts.googleapis.com https://twitter.com https://*.twimg.com https://translate.googleapis.com https://ton.twitter.com 'unsafe-inline' https://platform.twitter.com https://maxcdn.bootstrapcdn.com https://netdna.bootstrapcdn.com 'self'; object-src https://twitter.com https://pbs.twimg.com; default-src 'self'; frame-src https://staticxx.facebook.com https://twitter.com https://*.twimg.com https://player.vimeo.com https://pay.twitter.com https://www.facebook.com https://ton.twitter.com https://syndication.twitter.com https://vine.co twitter: https://www.youtube.com https://platform.twitter.com https://upload.twitter.com https://s-static.ak.facebook.com 'self' https://donate.twitter.com; img-src https://graph.facebook.com https://*.giphy.com https://twitter.com https://*.twimg.com data: https://lumiere-a.akamaihd.net https://fbcdn-profile-a.akamaihd.net https://www.facebook.com https://ton.twitter.com https://*.fbcdn.net https://syndication.twitter.com https://media.riffsy.com https://www.google.com https://stats.g.doubleclick.net https://*.tiles.mapbox.com https://www.google-analytics.com blob: 'self'; report-uri https://twitter.com/i/csp_report?a=NVQWGYLXFVZXO2LGOQ%3D%3D%3D%3D%3D%3D&ro=false;

The parameter -v allows to filter for values that match the given pattern. This example shows all Content Security Policies that contain the word unsafe, a good indicator for easily bypassable policies:

./WASEQuery.py headervalues -v '*unsafe*' content-security-policy
default-src * data: blob:;script-src *.facebook.com *.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* 'unsafe-inline' 'unsafe-eval' fbstatic-a.akamaihd.net fbcdn-static-b-a.akamaihd.net *.atlassolutions.com blob: data:;style-src * 'unsafe-inline' data:;connect-src *.facebook.com *.fbcdn.net *.facebook.net *.spotilocal.com:* *.akamaihd.net wss://*.facebook.com:* https://fb.scanandcleanlocal.com:* *.atlassolutions.com attachment.fbsbx.com ws://localhost:* blob:;
default-src * data: blob:;script-src *.facebook.com *.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:* 'unsafe-inline' 'unsafe-eval' fbstatic-a.akamaihd.net fbcdn-static-b-a.akamaihd.net *.atlassolutions.com blob: data:;style-src * 'unsafe-inline' data:;connect-src *.facebook.com *.fbcdn.net *.facebook.net *.spotilocal.com:* *.akamaihd.net wss://*.facebook.com:* https://fb.scanandcleanlocal.com:* *.atlassolutions.com attachment.fbsbx.com ws://localhost:* blob: chrome-extension://boadgeojelhgndaghljhdicfkmllpafd;
report-uri /_/ConsentHttp/cspreport;script-src 'unsafe-inline' 'self' 'unsafe-eval' https://apis.google.com https://ssl.gstatic.com https://www.google.com https://www.gstatic.com
script-src 'self' https://addons.mozilla.org https://www.paypalobjects.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://ssl.google-analytics.com https://addons.cdn.mozilla.net; default-src 'self'; img-src 'self' data: blob: https://www.paypal.com https://ssl.google-analytics.com https://addons.cdn.mozilla.net https://static.addons.mozilla.net https://sentry.prod.mozaws.net; media-src https://videos.cdn.mozilla.net; style-src 'self' 'unsafe-inline' https://addons.cdn.mozilla.net; frame-src 'self' https://ic.paypal.com https://paypal.com https://www.google.com/recaptcha/ https://www.paypal.com; object-src 'none'; connect-src 'self' https://sentry.prod.mozaws.net; font-src 'self' https://addons.cdn.mozilla.net; report-uri /__cspreport__
script-src https://connect.facebook.net https://cm.g.doubleclick.net https://ssl.google-analytics.com https://graph.facebook.com https://twitter.com 'unsafe-eval' https://*.twimg.com https://api.twitter.com https://analytics.twitter.com https://publish.twitter.com https://ton.twitter.com https://syndication.twitter.com https://www.google.com https://t.tellapart.com https://platform.twitter.com 'nonce-EsKk+GaYa2fM615jt4iymg==' https://www.google-analytics.com 'self'; frame-ancestors 'self'; font-src https://twitter.com https://*.twimg.com data: https://ton.twitter.com https://fonts.gstatic.com https://maxcdn.bootstrapcdn.com https://netdna.bootstrapcdn.com 'self'; media-src https://twitter.com https://*.twimg.com https://ton.twitter.com blob: 'self'; connect-src https://graph.facebook.com https://*.giphy.com https://*.twimg.com https://api.twitter.com https://pay.twitter.com https://analytics.twitter.com https://media.riffsy.com https://upload.twitter.com https://api.mapbox.com 'self'; style-src https://fonts.googleapis.com https://twitter.com https://*.twimg.com https://translate.googleapis.com https://ton.twitter.com 'unsafe-inline' https://platform.twitter.com https://maxcdn.bootstrapcdn.com https://netdna.bootstrapcdn.com 'self'; object-src https://twitter.com https://pbs.twimg.com; default-src 'self'; frame-src https://staticxx.facebook.com https://twitter.com https://*.twimg.com https://player.vimeo.com https://pay.twitter.com https://www.facebook.com https://ton.twitter.com https://syndication.twitter.com https://vine.co twitter: https://www.youtube.com https://platform.twitter.com https://upload.twitter.com https://s-static.ak.facebook.com 'self' https://donate.twitter.com; img-src https://graph.facebook.com https://*.giphy.com https://twitter.com https://*.twimg.com data: https://lumiere-a.akamaihd.net https://fbcdn-profile-a.akamaihd.net https://www.facebook.com https://ton.twitter.com https://*.fbcdn.net https://syndication.twitter.com https://media.riffsy.com https://www.google.com https://stats.g.doubleclick.net https://*.tiles.mapbox.com https://www.google-analytics.com blob: 'self'; report-uri https://twitter.com/i/csp_report?a=NVQWGYLXFVZXO2LGOQ%3D%3D%3D%3D%3D%3D&ro=false;

Or the opposite, CSPs without unsafe directives by inverting the result with --invert (-i):

./WASEQuery.py headervalues -v '*unsafe*' content-security-policy --invert --urls
default-src 'self'; connect-src 'self'; font-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com data:; frame-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; frame-ancestors 'self'; img-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com data:; media-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; object-src 'none'; script-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; style-src 'self' https://*.twimg.com https://twitter.com https://ton.twitter.com; report-uri https://twitter.com/i/csp_report?a=NVQWGYLXFVRXG4A%3D&ro=false;
https://twitter.com:443/i/csp_report?a=NVQWGYLXFVZXO2LGOQ%3D%3D%3D%3D%3D%3D&ro=false

Analogous, the subcommand parametervalues extracts all values of a given request parameter, e.g. CSRF tokens for further statistical analysis:

./WASEQuery.py parametervalues csrftoken
pk3CR9VCNyJnEA3O5tnudeJeXJsgSor4