Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
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
7.1k
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
640
Shadow DOM & Security - Exploring the boundary between light and shadow
masatokinugawa
1
1.8k
ブラウザのレガシー・独自機能を愛でる-Firefoxの脆弱性4選- / Browser Crash Club #1
masatokinugawa
1
990
注目したいクライアントサイドの脆弱性2選/ Security.Tokyo #3
masatokinugawa
8
4.1k
バグハンティングのすゝめ / P3NFEST
masatokinugawa
5
2.6k
Pwn2OwnでMicrosoft Teamsをハッキングして2000万円を獲得した方法/ Shibuya.XSS techtalk #12
masatokinugawa
13
20k
How I Hacked Microsoft Teams and got $150,000 in Pwn2Own
masatokinugawa
1
23k
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
28k
Other Decks in Technology
See All in Technology
regrowth_tokyo_2025_securityagent
hiashisan
0
230
re:Invent 2025 ふりかえり 生成AI版
takaakikakei
1
200
【AWS re:Invent 2025速報】AIビルダー向けアップデートをまとめて解説!
minorun365
4
510
EM歴1年10ヶ月のぼくがぶち当たった苦悩とこれからへ向けて
maaaato
0
280
Edge AI Performance on Zephyr Pico vs. Pico 2
iotengineer22
0
140
AI駆動開発における設計思想 認知負荷を下げるフロントエンドアーキテクチャ/ 20251211 Teppei Hanai
shift_evolve
PRO
2
360
寫了幾年 Code,然後呢?軟體工程師必須重新認識的 DevOps
cheng_wei_chen
1
1.4k
多様なデジタルアイデンティティを攻撃からどうやって守るのか / 20251212
ayokura
0
430
Debugging Edge AI on Zephyr and Lessons Learned
iotengineer22
0
180
生成AI活用の型ハンズオン〜顧客課題起点で設計する7つのステップ
yushin_n
0
140
re:Inventで気になったサービスを10分でいけるところまでお話しします
yama3133
1
120
プロンプトやエージェントを自動的に作る方法
shibuiwilliam
0
900
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
54
7.9k
The Language of Interfaces
destraynor
162
25k
Music & Morning Musume
bryan
46
7k
How to train your dragon (web standard)
notwaldorf
97
6.4k
Done Done
chrislema
186
16k
How STYLIGHT went responsive
nonsquared
100
6k
Imperfection Machines: The Place of Print at Facebook
scottboms
269
13k
RailsConf 2023
tenderlove
30
1.3k
The Cult of Friendly URLs
andyhume
79
6.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.4k
Embracing the Ebb and Flow
colly
88
4.9k
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.2k
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(` `); } /* */