JSでDoSる/ Shibuya.XSS techtalk #11

JSでDoSる/ Shibuya.XSS techtalk #11

Shibuya.XSS techtalk #11 の発表資料です。

1a5bce24526a7d6f1ab89678df2d673c?s=128

Masato Kinugawa

May 16, 2019
Tweet

Transcript

  1. for(;;){ alert(` `); } /* 2019/05/16 Shibuya.XSS techtalk #11*/ /*

    Masato Kinugawa */
  2. • • •

  3. None
  4. • • • • •

  5. • • • •

  6. • • • • • • • • • •

  7. while(1){ alert(` `); }

  8. • •

  9. • • > decodeURIComponent("%E3%81%82"); < " " > decodeURIComponent("%FF"); ‣

    Uncaught URIError: URI malformed
  10. None
  11. • • • > encodeURIComponent(" "); < "%E3%81%82" > encodeURIComponent("\uDC00");

    ‣ Uncaught URIError: URI malformed
  12. https://www.ecma-international.org/ecma-262/9.0/index.html#sec-encode

  13. (function a(){ alert(` `); a(); })()

  14. • • • • / \/ • " \" •

    \ \\ <script> userInput = "AAA\\\";alert(1)\/\/ <\/script>"; displayContents(); </script>
  15. • <script> userInput = "AAA [ ] BBB"; displayContents(); </script>

  16. • <script> userInput = "AAA BBB"; displayContents(); </script>

  17. • https://www.ecma-international.org/ecma-262/9.0/index.html#table-33

  18. • https://www.ecma-international.org/ecma-262/9.0/index.html#table-33

  19. • <script> userInput = "AAA [U+2028] BBB"; displayContents(); </script>

  20. • • • • •

  21. <script> userInput = "<!--<script>"; displayContents(); </script>

  22. • • <script> userInput = "<!--<script>"; </script> <textarea></script> <img src=x

    onerror=alert(1)> </textarea>
  23. • • https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script- elements

  24. • <script> userInput = "<%"; </script> <textarea>%></script><img src=x onerror=alert(1)> </textarea>

    https://html5sec.org/#91 <xmp> <% </xmp> <textarea> %></xmp><img src=x onerror=alert(1)> </textarea>
  25. • • • • •

  26. setInterval(` alert(\` \`) `,1);

  27. • •

  28. • • • userInfo = {"name": 123}// name = userInfo.name.toUpperCase()

    Uncaught TypeError: userInfo.name.toUpperCase is not a function
  29. siteData = {"url":"https:// ...","title":{"toString":null},...}; url = "url: " + siteData.url;

    title = "title: " + siteData.title;
  30. • • • ({toString: function(){alert(1)} })+""; ({valueOf : function(){alert(2)} })+"";

  31. • • • > ({toString:null})+""; ‣ Uncaught TypeError: Cannot convert

    object to primitive value
  32. • • • • •

  33. • > typeof "aaa"; < ‣ "string" > typeof 123;

    < ‣ "number" > typeof true; < ‣ "boolean" > typeof []; < ‣ "object" > typeof {}; < ‣ "object" > typeof null; < ‣ "object"
  34. • • > Array.isArray([]); < ‣ true > Array.isArray({}); <

    ‣ false > null === null < ‣ true
  35. • • > Object.prototype.toString.call("aaa"); < ‣ "[object String]" > Object.prototype.toString.call(123);

    < ‣ "[object Number]" > Object.prototype.toString.call(true); < ‣ "[object Boolean]" > Object.prototype.toString.call([]); < ‣ "[object Array]" > Object.prototype.toString.call({}); < ‣ "[object Object]" > Object.prototype.toString.call(null); < ‣ "[object Null]"
  36. <style>*{ color:expression( alert(" ") )}

  37. • • • <toString>AAA</toString>

  38. • • •

  39. • • function tellMeFruitColor(USER_INPUT){ fruits = { "apple":"red", "lemon":"yellow", "peach":"pink"

    }; if(fruits[USER_INPUT]){ return USER_INPUT + ": " + fruits[USER_INPUT]; }else{ return "I don't know that fruit"; } }
  40. > tellMeFruitColor("apple"); < "apple: red" > tellMeFruitColor("lemon"); < "lemon: yellow"

    > tellMeFruitColor("strawberry"); < "I don't know that fruit" > tellMeFruitColor("toString"); < "toString: function toString() { [native code] }" > tellMeFruitColor("constructor"); < "constructor: function Object() { [native code] }" > tellMeFruitColor("__proto__"); < "__proto__: [object Object]"
  41. None
  42. • •

  43. https://qiita.com/howdy39/items/35729490b024ca295d6c

  44. if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return

    "I don't know that fruit"; }
  45. if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return

    "I don't know that fruit"; }
  46. if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return

    "I don't know that fruit"; }
  47. if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return

    "I don't know that fruit"; }
  48. if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return

    "I don't know that fruit"; }
  49. if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return

    "I don't know that fruit"; }
  50. > ({"toString":function(){return "a"}})+""; < " " > ({"prop":"a"})+""; < "[object

    Object]"
  51. whiteListTags = { "span":funcForSanitizingSpanElem, "div": funcForSanitizingDivElem, "a":" funcForSanitizingAElem, ... }

    // whiteListTags[ ] <toString> whiteListTags["toString"]()
  52. fileIcons = { "txt":"https://example.com/img/icon-txt.gif", "png":"https://example.com/img/icon-png.gif", "jpg":" https://example.com/img/icon-jpg.gif ", ... }

    // fileIcons[ ] dos.constructor fileIcons["constructor"]
  53. • • • •

  54. • • function tellMeFruitColor(USER_INPUT){ fruits = { ... }; -

    if(fruits[USER_INPUT]){ + if(Object.prototype.hasOwnProperty.call(fruits,USER_INPUT)){ return USER_INPUT + ": " + fruits[USER_INPUT]; }else{ return "I don't know that fruit"; } }
  55. > tellMeFruitColor("apple"); < "apple: red" > tellMeFruitColor("lemon"); < "lemon: yellow"

    > tellMeFruitColor("strawberry"); < "I don't know that fruit" > tellMeFruitColor("toString"); < "I don't know that fruit" > tellMeFruitColor("constructor"); < "I don't know that fruit" > tellMeFruitColor("__proto__"); < "I don't know that fruit"
  56. • • fruits["toString"] undefined function tellMeFruitColor(USER_INPUT){ - fruits = {

    ... }; + fruits = Object.create(null); + fruits = Object.assign(fruits,{"apple":"red","lemon": ... }) if(fruits[USER_INPUT]){ return USER_INPUT + ": " + fruits[USER_INPUT]; }else{ return "I don't know that fruit"; } }
  57. • • function tellMeFruitColor(USER_INPUT){ - fruits = { ... };

    + fruits = new Map(["apple","red"], + ["lemon","yellow"], + ["peach","pink"]); - if(fruits[USER_INPUT]){ - return USER_INPUT + ": " + fruits[USER_INPUT]; + if(fruits.get(USER_INPUT)){ + return USER_INPUT + ": " + fruits.get(USER_INPUT); }else{ return "I don't know that fruit"; } }
  58. ({toString: function(){ alert(` `); this+""; } })+"";

  59. • •

  60. • • • USER_INPUT = {"length": 1e10,"constructor":{"name":"Array"}}; if(USER_INPUT.constructor.name === "Array"){

    array = []; for (var i = 0; i < USER_INPUT.length; i++) { array.push(USER_INPUT[i]); } }
  61. ==== JS stack trace ========================================= Security context: 00000099763A5549 <JSObject> 1:

    /* anonymous */ [repl:~1] [pc=000000C1A3E8B9B9](this=00000382794865D9 <JSGlobal Object>) 5: /* anonymous */ [vm.js:65] [bytecode=000002EDD76E8421 offset=87](this=0000021A2A00C731 <ContextifyScript map = 00000203C25E1319>,options=0000021A2A00C709 <Object map = 00000203C25E13C9>) 6: defaultEval [repl.js:244] [bytecode=000002EDD76E7089 offset=445](this=0000021A2A00C7A1 <REPLServer ... FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 1: node::DecodeWrite 2: node_module_register 3: v8::internal::FatalProcessOutOfMemory 4: v8::internal::FatalProcessOutOfMemory 5: v8::internal::Factory::NewUninitializedFixedArray 6: v8::internal::WasmDebugInfo::SetupForTesting 7: v8::internal::interpreter::BytecodeArrayRandomIterator::UpdateOffsetFromIndex 8: 000000C1A3D043C1
  62. • • •

  63. • • • • •

  64. for(;;){ alert(` `); } /* */