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
610
Shadow DOM & Security - Exploring the boundary between light and shadow
masatokinugawa
1
1.8k
ブラウザのレガシー・独自機能を愛でる-Firefoxの脆弱性4選- / Browser Crash Club #1
masatokinugawa
1
970
注目したいクライアントサイドの脆弱性2選/ Security.Tokyo #3
masatokinugawa
8
4.1k
バグハンティングのすゝめ / P3NFEST
masatokinugawa
5
2.5k
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
【保存版】「ガチャ」からの脱却:Gemini × Veoで作る、意図を反映するAI動画制作ワークフロー
nekoailab
0
120
段階的に進める、 挫折しない自宅サーバ入門
yu_kod
5
2.1k
TypeScript 6.0で非推奨化されるオプションたち
uhyo
15
5.7k
GitHub を組織的に使いこなすために ソニーが実践した全社展開のプラクティス
sony
19
9.9k
小規模チームによる衛星管制システムの開発とスケーラビリティの実現
sankichi92
0
170
Dify on AWS の選択肢
ysekiy
0
120
Modern Data Stack大好きマンが語るSnowflakeの魅力
sagara
0
180
LangChain v1.0にトライ~ AIエージェントアプリの移行(v0.3 → v1.0) ~
happysamurai294
0
140
Active Directory 勉強会 第 6 回目 Active Directory セキュリティについて学ぶ回
eurekaberry
14
5.1k
研究開発部メンバーの働き⽅ / Sansan R&D Profile
sansan33
PRO
3
21k
Design System Documentation Tooling 2025
takanorip
0
720
Master Dataグループ紹介資料
sansan33
PRO
1
4k
Featured
See All Featured
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Designing Experiences People Love
moore
142
24k
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
Music & Morning Musume
bryan
46
7k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.8k
Facilitating Awesome Meetings
lara
57
6.6k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
4 Signs Your Business is Dying
shpigford
186
22k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.3k
Embracing the Ebb and Flow
colly
88
4.9k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.1k
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(` `); } /* */