Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
JSでDoSる/ Shibuya.XSS techtalk #11
Search
Masato Kinugawa
May 16, 2019
Technology
20
7k
JSでDoSる/ Shibuya.XSS techtalk #11
Shibuya.XSS techtalk #11 の発表資料です。
Masato Kinugawa
May 16, 2019
Tweet
Share
More Decks by Masato Kinugawa
See All by Masato Kinugawa
Shadow DOMとセキュリティ - 光と影の境界を探る / Shibuya.XSS techtalk #13
masatokinugawa
0
440
Shadow DOM & Security - Exploring the boundary between light and shadow
masatokinugawa
1
1.3k
ブラウザのレガシー・独自機能を愛でる-Firefoxの脆弱性4選- / Browser Crash Club #1
masatokinugawa
1
800
注目したいクライアントサイドの脆弱性2選/ Security.Tokyo #3
masatokinugawa
8
3.9k
バグハンティングのすゝめ / P3NFEST
masatokinugawa
5
2.4k
Pwn2OwnでMicrosoft Teamsをハッキングして2000万円を獲得した方法/ Shibuya.XSS techtalk #12
masatokinugawa
13
20k
How I Hacked Microsoft Teams and got $150,000 in Pwn2Own
masatokinugawa
1
22k
Electron: Abusing the lack of context isolation - CureCon(en)
masatokinugawa
5
100k
Electron: Context Isolationの欠如を利用した任意コード実行 / Electron: Abusing the lack of context isolation - CureCon(ja)
masatokinugawa
9
27k
Other Decks in Technology
See All in Technology
kintone開発チームの紹介
cybozuinsideout
PRO
0
73k
広島発!スタートアップ開発の裏側
tsankyo
0
190
MySQL HeatWave:サービス概要のご紹介
oracle4engineer
PRO
4
1.6k
S3のライフサイクル設計でハマったポイント
mkumada
0
100
Mackerel in さくらのクラウド
cubicdaiya
1
410
OpenAPIから画面生成に挑戦した話
koinunopochi
0
130
いま、あらためて考えてみるアカウント管理 with IaC / Account management with IaC
kohbis
2
640
結局QUICで通信は速くなるの?
kota_yata
9
7.5k
Devinを使ったモバイルアプリ開発 / Mobile app development with Devin
yanzm
0
150
コミュニティと計画的偶発性理論 - 出会いが人生を変える / Life-Changing Encounters
soudai
PRO
7
1.3k
ZOZOTOWNフロントエンドにおけるディレクトリの分割戦略
zozotech
PRO
13
4.1k
ドキュメントはAIの味方!スタートアップのアジャイルを加速するADR
kawauso
3
110
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
820
Product Roadmaps are Hard
iamctodd
PRO
54
11k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
The Language of Interfaces
destraynor
160
25k
Balancing Empowerment & Direction
lara
2
580
Visualization
eitanlees
146
16k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.8k
The Cost Of JavaScript in 2023
addyosmani
53
8.8k
Scaling GitHub
holman
462
140k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Transcript
for(;;){ alert(` `); } /* 2019/05/16 Shibuya.XSS techtalk #11*/ /*
Masato Kinugawa */
• • •
None
• • • • •
• • • •
• • • • • • • • • •
•
while(1){ alert(` `); }
• •
•
• • > decodeURIComponent("%E3%81%82"); < " " > decodeURIComponent("%FF"); ‣
Uncaught URIError: URI malformed
None
• • • > encodeURIComponent(" "); < "%E3%81%82" > encodeURIComponent("\uDC00");
‣ Uncaught URIError: URI malformed
https://www.ecma-international.org/ecma-262/9.0/index.html#sec-encode
(function a(){ alert(` `); a(); })()
• • • • / \/ • " \" •
\ \\ <script> userInput = "AAA\\\";alert(1)\/\/ <\/script>"; displayContents(); </script>
• <script> userInput = "AAA [ ] BBB"; displayContents(); </script>
• <script> userInput = "AAA BBB"; displayContents(); </script>
• https://www.ecma-international.org/ecma-262/9.0/index.html#table-33
• https://www.ecma-international.org/ecma-262/9.0/index.html#table-33
• <script> userInput = "AAA [U+2028] BBB"; displayContents(); </script>
• • • • •
<script> userInput = "<!--<script>"; displayContents(); </script>
• • <script> userInput = "<!--<script>"; </script> <textarea></script> <img src=x
onerror=alert(1)> </textarea>
• • https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script- elements
• <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>
• • • • •
setInterval(` alert(\` \`) `,1);
• •
•
• • • userInfo = {"name": 123}// name = userInfo.name.toUpperCase()
Uncaught TypeError: userInfo.name.toUpperCase is not a function
siteData = {"url":"https:// ...","title":{"toString":null},...}; url = "url: " + siteData.url;
title = "title: " + siteData.title;
• • • ({toString: function(){alert(1)} })+""; ({valueOf : function(){alert(2)} })+"";
• • • > ({toString:null})+""; ‣ Uncaught TypeError: Cannot convert
object to primitive value
• • • • •
• > typeof "aaa"; < ‣ "string" > typeof 123;
< ‣ "number" > typeof true; < ‣ "boolean" > typeof []; < ‣ "object" > typeof {}; < ‣ "object" > typeof null; < ‣ "object"
• • > Array.isArray([]); < ‣ true > Array.isArray({}); <
‣ false > null === null < ‣ true
• • > 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]"
<style>*{ color:expression( alert(" ") )}
• • • <toString>AAA</toString>
• • •
• • 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"; } }
> 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]"
None
• •
https://qiita.com/howdy39/items/35729490b024ca295d6c
if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return
"I don't know that fruit"; }
if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return
"I don't know that fruit"; }
if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return
"I don't know that fruit"; }
if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return
"I don't know that fruit"; }
if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return
"I don't know that fruit"; }
if(fruits["toString"]){ return "toString" + ": " + fruits["toString"]; }else{ return
"I don't know that fruit"; }
> ({"toString":function(){return "a"}})+""; < " " > ({"prop":"a"})+""; < "[object
Object]"
whiteListTags = { "span":funcForSanitizingSpanElem, "div": funcForSanitizingDivElem, "a":" funcForSanitizingAElem, ... }
// whiteListTags[ ] <toString> whiteListTags["toString"]()
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"]
• • • •
• • 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"; } }
> 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"
• • 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"; } }
• • 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"; } }
({toString: function(){ alert(` `); this+""; } })+"";
• •
• • • 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]); } }
==== 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
• • •
•
• • • • •
for(;;){ alert(` `); } /* */