fbpx
Hàng triệu nội dung hữu ích dành riêng cho bạn đã sẵn sàng. Tìm hiểu thêm
Góc nhìn

Phân tích lỗi lõi Bitcoin CVE-2018–17144

Anh Đức Phạm Level 5
.
23 min read

Thế giới Bitcoin đã rất ngạc nhiên khi tuần trước, 0.16.3 được phát hành ra công chúng và mọi người đều được khuyến khích nâng cấp càng sớm càng tốt. Lý do có thể giả thiết là có một vector từ chối dịch vụ (DoS) được tìm thấy trong 0.14-0.16.2 cần vá. Sau đó , chúng tôi phát hiện ra rằng có khả năng lạm phát do cùng một lỗi trong 0.15-0.16.2.

Trong bài viết này, tôi tìm cách làm rõ những gì đã xảy ra, mối nguy hiểm là gì, nó được khai thác như thế nào và những gì có thể xảy ra.

Hai cách để tăng gấp đôi chi tiêu

Trước khi chúng ta gặp lỗi thực sự, một số giải thích là cần thiết. Chúng tôi cần xác định chi tiêu gấp đôi trước tiên vì lỗi là với chi tiêu gấp đôi.

Chi tiêu gấp đôi là trường hợp ai đó, nói Alice, dành tiền xu cho Bob và cùng một đồng xu cho Charlie. Alice chủ yếu cố gắng viết hai tờ séc, một trong số đó cô ấy biết sẽ bị trả lại. Tất nhiên, khi chúng tôi đang suy nghĩ trong kiểm tra, có một số tài khoản mà Alice đã có được overdrawn bằng cách viết hai kiểm tra. Đó là gần, nhưng không hoàn toàn chính xác trong cách Bitcoin hoạt động.

Bitcoin không hoạt động trên tài khoản nhưng với UTXO, hoặc kết quả giao dịch chưa thanh toán. Các kết quả đầu ra của một giao dịch về bản chất có một địa chỉ và một số tiền. Khi đầu ra đó đã được chi tiêu, nó không thể được chi tiêu một lần nữa. Hãy suy nghĩ về một UTXO như một đồng xu duy nhất được gửi đến cho bạn có thể là bất kỳ số tiền nào, ví dụ, một đồng xu BTC 0,413.

Chi tiêu gấp đôi có nghĩa là một đồng xu duy nhất (UTXO) đang được chi tiêu hai lần. Thông thường, điều này có nghĩa là Alice đang gửi 0,413 BTC của cô ấy cho Bob trong một giao dịch và đến Charlie trong một giao dịch khác. Cách thức này được giải quyết bằng Bitcoin là một trong những giao dịch đó làm cho nó thành một khối và xác định ai thực sự được trả tiền. Nếu cả hai giao dịch bằng cách nào đó đi qua trong nhiều khối, khối thứ hai bị từ chối bởi phần mềm. Nếu cả hai giao dịch đi qua trong một khối, khối đó cũng bị phần mềm từ chối. Về cơ bản, phần mềm phát hiện chi tiêu gấp đôi và nếu có hai chi tiêu một khối nên bị từ chối.

Tuy nhiên, việc gửi cùng một UTXO trong hai giao dịch khác nhau không phải là cách duy nhất để chi tiêu gấp đôi. Có một trường hợp bệnh lý hơn của cùng một UTXO được chi tiêu hai lần trong cùng một giao dịch . Trong trường hợp này, Alice đang gửi một đồng xu hai lần cho Bob. Vì vậy, Alice đang chi tiêu 0,413 BTC đồng xu hai lần để gửi 0.826 BTC cho Bob. Đây rõ ràng không phải là một giao dịch hợp lệ vì chỉ có 1 UTXO trị giá 0.413 BTC được gửi đi. Điều này sẽ tương đương với việc Alice trả Bob cho cùng một hóa đơn 10 đô la hai lần và Bob nghĩ rằng anh ta nhận được 20 đô la.

Xác định lỗi

Vì vậy, để tóm tắt những gì chúng tôi đã xác định cho đến nay, có hai loại nỗ lực chi tiêu gấp đôi:

  1. Sử dụng hai hoặc nhiều giao dịch để chi tiêu cùng một UTXO.
  2. Sử dụng một giao dịch để chi tiêu cùng một UTXO nhiều lần.

Nó chỉ ra rằng (1) được xử lý một cách chính xác bởi phần mềm Bitcoin Core. Đó là (2) đó là mối quan tâm với chúng tôi ở đây. Bất cứ ai cũng có thể xây dựng một giao dịch mà đôi chi tiêu như thế này, nhưng nhận được các nút để chấp nhận loại giao dịch là một vấn đề khác. Có hai cách để có được một giao dịch thành một khối.

A. Phát sóng giao dịch lên mạng với đủ lệ phí để có được một thợ mỏ để bao gồm các giao dịch trong một khối.

B. Bao gồm các giao dịch trong một khối như một thợ mỏ.

(A) không yêu cầu nhiều hơn là tạo giao dịch và phát nó tới một nút trên mạng. (B) yêu cầu bạn tìm đủ bằng chứng về công việc. Nó chỉ ra rằng đối với các lỗi, (A) không phải là một vector tấn công có thể là những giao dịch được ngay lập tức đánh dấu là không hợp lệ và bị từ chối bởi các nút trên mạng. Không có cách nào để giao dịch nhận được vào mempool của thợ mỏ mà không có sự hợp tác của thợ mỏ vì họ sẽ không được tuyên truyền. (B) là trường hợp duy nhất trong đó lỗi hiển thị. Nói cách khác, để khai thác lỗi này, bạn cần bằng chứng về công việc, hoặc đủ thiết bị khai thác và điện.

Để rõ ràng, có 4 trường hợp cần được xử lý để chi tiêu gấp đôi:

1A – Nhiều giao dịch mempool chi tiêu cùng một UTXO

1B – Giao dịch nhiều khối chi tiêu cùng một UTXO

2A – Giao dịch mempool đơn chi tiêu cùng một UTXO nhiều lần

2B – Giao dịch khối đơn chi tiêu cùng một UTXO nhiều lần

Lỗi này có hai biểu hiện. Trong 0.14.x, có lỗ hổng Từ chối dịch vụ và trong 0.15.x đến 0.16.2, có lỗi lạm phát. Chúng tôi quay sang những người tiếp theo.

Từ chối dịch vụ dễ bị tổn thương

Câu chuyện bắt đầu vào năm 2009 với Bitcoin 0.1, trong đó bit mã này thực thi sự đồng thuận bằng cách từ chối các trường hợp 1B và 2B (kiểm tra các khối không tăng gấp đôi chi tiêu):

Tôi đã xóa rất nhiều mã ở giữa để rõ ràng

Bạn có thể xem nhận xét “Kiểm tra xung đột” để kiểm tra xem mọi đầu vào chưa được chi tiêu chưa. Mã bên dưới nhận xét “Đánh dấu điểm ngoài là chi tiêu” đánh dấu UTXO là đã chi tiêu. Nếu bất kỳ UTXO nào được chi tiêu nhiều lần, điều này sẽ gây ra lỗi.

Năm 2011, PR 443 đã được sáp nhập. Sự thay đổi này có nghĩa là để chăm sóc trường hợp một chi tiêu gấp đôi một lần được truyền qua mempool (Case 2A ở trên). Nhận xét Pull Request này làm cho mục đích rõ ràng (nhấn mạnh của tôi):

Ngoài ra, không có giao dịch với các đầu vào trùng lặp được đặt trong các khối … ai đó đã thử nó một vài tuần trước, nhưng txes không bao giờ kết thúc trong khối. Im giả định có một kiểm tra một nơi nào đó sau này mà ngăn cản họ nhận được thêm vào một khối, mặc dù tôi đã không thực hiện bất kỳ đào về vấn đề này. Điều này thực sự để ngăn chặn các giao dịch rõ ràng không hợp lệ như vậy từ việc chuyển tiếp.

Việc thay đổi mã thực tế nhiều hơn hoặc ít hơn cũng giống như mã bên dưới các chú thích “Kiểm tra các xung đột” trong ConnectInputs ở trên, nhưng ở một nơi khác. Sự thay đổi mã là trong CheckTransaction , được chạy cho tất cả 4 trường hợp trên (1A, 1B, 2A, 2B). Kết quả là, bây giờ chúng ta có một số dự phòng trong mã đồng thuận chi tiêu hai lần khi các trường hợp 1B và 2B được kiểm tra hai lần, một lần trong CheckTransaction và một lần trong ConnectInputs .

Vào năm 2013, PR 2224 đã được sáp nhập. Mục tiêu của thay đổi này là phân biệt giữa các lỗi đồng thuận (như chi tiêu gấp đôi) và các lỗi hệ thống (như hết dung lượng đĩa) vì nhận xét PR này làm rõ: (nhấn mạnh mỏ)

Nó giới thiệu CValidationState, lưu trữ siêu dữ liệu về một khối hoặc xác thực giao dịch được thực hiện. Nó được sử dụng để phân biệt lỗi xác thực (không đáp ứng các quy tắc mạng), với lỗi thời gian chạy (như không gian đĩa), như trước đây có thể bị nhầm lẫn, dẫn đến các khối bị đánh dấu không hợp lệ vì không gian đĩa bị hết. Ngoài ra, CValidationState cũng đảm nhiệm vai trò theo dõi các cấp DoS (vì vậy nó không cần phải được lưu trữ bên trong các giao dịch hoặc các khối…).

Thay đổi mã có liên quan thực tế là ở đây:

Vào thời điểm này, ConnectInputs đã được mô đun hóa thành nhiều phương thức và chức năng này trở thành một trong những kiểm tra cho chi tiêu gấp đôi. Thay đổi quan trọng ở đây là những gì đã từng là một error đã được thay đổi thành một assert .

Một assert làm gì trong C ++? Nó tạm dừng chương trình hoàn toàn. Tại sao một lập trình viên muốn dừng chương trình ở đây? Vâng, đây là nơi mục đích của Yêu cầu kéo đến. Đây là đoạn mã có liên quan từ thời điểm đó.

Đây là xử lý trường hợp 1B và 2B như trước đây. Tên hàm đã thay đổi từ ConnectInputs thành ConnectBlock , nhưng sự thừa trong việc kiểm tra các trường hợp 1B và 2B vẫn còn từ PR 443. Như chúng ta đã thấy, UpdateCoins thực hiện kiểm tra chi tiêu kép lần thứ hai. CheckBlock thực hiện kiểm tra chi tiêu gấp đôi bằng cách gọi CheckTransaction :

Vì đây là lần thứ hai kiểm tra cùng một thứ, cách duy nhất để kiểm tra chi tiêu kép trong UpdateCoins là không thành công nếu có một số loại cơ sở dữ liệu UTXO hoặc tham nhũng bộ nhớ. Quả thực đó có vẻ là lý do cho sự thay đổi thành một assert . Chúng tôi đã biết các giao dịch không phải là chi tiêu gấp đôi như CheckBlock thông qua CheckTransaction hiện rằng kiểm tra trước UpdateCoins . Do đó, PR 2224 đã phỏng đoán chính xác rằng việc tới trạng thái này trong UpdateCoins phải là một lỗi hệ thống, không phải là một lỗi đồng thuận. Trong trường hợp đó, để ngăn chặn sự tham nhũng dữ liệu hơn nữa, điều đúng đắn cần làm là tạm dừng chương trình.

Vào năm 2017, PR 9049 được giới thiệu như một phần của Bitcoin 0.14. Như Segwit sẽ làm cho khối lớn hơn, đây là một trong nhiều thay đổi để tăng tốc thời gian xác nhận khối. Sự thay đổi mã là khá nhỏ:

Bạn có thể thấy ở đây rằng boolean fCheckDuplicateInputs được thêm vào để tăng tốc độ kiểm tra Block. Điều này được cho là một kiểm tra dư thừa như chúng ta sẽ thấy bên dưới. Thật không may, mã trong UpdateCoins đã được thay đổi trong PR 2224 để kiểm tra tham nhũng hệ thống và không có nghĩa là kiểm tra sự đồng thuận. Bởi 0.14.0, mã đã được mô đun hóa nhiều hơn và assert trông hơi khác một chút:

Những gì đã từng một lần kiểm tra dư thừa hiện chịu trách nhiệm cho một chi tiêu đơn-tx đôi chi tiêu (Trường hợp 2B) và tạm dừng chương trình. Điều này vẫn thực thi các quy tắc đồng thuận về mặt kỹ thuật, rất nghiêm trọng, bằng cách tạm dừng chương trình.

PR 9049 vượt qua như thế nào? Greg Maxwell đã giới thiệu tôi đến cuộc trò chuyện này trên IRC:

Các đạo cụ chính cho Greg Maxwell, người đã giúp tôi giải thích cho những gì đã xảy ra

TL, DR, các nhà phát triển, khi thảo luận về PR 9049, có thể nghĩ rằng một khoản chi tiêu hai lần một lần (trường hợp 2B) đã được kiểm tra ở đâu đó từ PR 443 mà không tính đến PR 2224. Điều này khiến các nhà phát triển không xem xét chặt chẽ tại PR 9049.

Tóm lại:

  1. PR 443 đã được giới thiệu vào năm 2011 để ngăn chặn chuyển tiếp các giao dịch chi tiêu kép (Trường hợp 2A). Điều này có một tác dụng phụ của việc tạo ra một kiểm tra dư thừa các quy tắc đồng thuận để chi tiêu gấp đôi trong các khối (Trường hợp 1B và 2B).
  2. PR 2224 đã được giới thiệu vào năm 2013 và như là một tác dụng phụ, nâng cấp mã trong (1) để xác nhận khối từ dư thừa để đồng thuận quan trọng.
  3. PR 9049 đã được giới thiệu vào năm 2017 và bỏ qua đoạn mã trong (1) cho trường hợp đơn-tx-double-in-a-block (Trường hợp 1B). Các nhà phát triển đã sai khi tin rằng mã sẽ không cần thiết vì họ không tính đến (2). Trong thực tế, thay đổi này bỏ qua một phần quan trọng nhất trí.

Đó là công bằng để nói rằng đây là một sự hợp lưu kỳ lạ của các sự kiện dẫn đến lỗi.

Mức độ nghiêm trọng của lỗ hổng DoS

Điều này có nghĩa là phần mềm Core 0.14.x có thể gặp sự cố với một khối đủ lạ. Vì nơi mã được đặt, gây ra sự cố, kẻ tấn công sẽ phải:

  1. Tạo giao dịch chi tiêu cùng một UTXO hai lần
  2. Bao gồm giao dịch từ (1) vào một khối có đủ chứng minh công việc
  3. Phát sóng chặn tới các nút 0.14.x

(1) và (3) không phải là rất tốn kém. (2) chi phí ở mức tối thiểu là 12,5 BTC vì lượng băm cần thiết để tạo ra một khối có đủ bằng chứng về công việc đòi hỏi cùng một lượng năng lượng / thiết bị khai thác như tìm một khối hợp lệ.

Nếu bạn tin rằng việc tách mạng không phải là tuyệt vời từ góc độ lý thuyết trò chơi, thì những ưu đãi để khai thác lỗ hổng này là khá thấp. Tốt nhất, với tư cách là kẻ tấn công, bạn lấy xuống một phần nhỏ các nút đầy đủ với chi phí 12,5 BTC. Với triển vọng không có lợi nhuận của một mạng lưới phân chia, đòi hỏi nhiều hơn là chỉ có thể sụp đổ một số các nút theo ý muốn, không có nhiều để đạt được như kẻ tấn công không thể dễ dàng bù đắp chi phí của cuộc tấn công.

Nếu đây là lỗ hổng duy nhất, kẻ tấn công có thể gây bất tiện cho nhiều người, nhưng nó không phải là một sự bất tiện duy trì vì các nút đó có thể khởi động lại và kết nối với các nút khác với các nút cho chúng. Một khi có một chuỗi dài hơn, đòn tấn công khối xấu này sẽ mất hoàn toàn răng. Trừ khi kẻ tấn công tiếp tục tạo ra các khối với chi phí 12,5 BTC cho mỗi khối và cấp chúng cho các nút 0.14.x trên mạng, cuộc tấn công sẽ ít nhiều kết thúc ở đó.

Nói cách khác, trong khi lỗ hổng chắc chắn là ở đó, các ưu đãi kinh tế cho DoS là khá thấp.

Lỗi lạm phát

Bắt đầu từ 0.15.0, đã có một tính năng được giới thiệu để tìm kiếm và lưu trữ UTXO nhanh hơn và giới thiệu lần lặp tiếp theo của lỗi. Thay vì gặp sự cố khi một khối có một chi tiêu hai lần giao dịch đến, phần mềm đã thấy khối đó là hợp lệ.

Điều này có nghĩa là một giao dịch bệnh lý (cùng một UTXO được chi tiêu nhiều lần trong cùng một giao dịch hoặc 2B ở trên) mà các lỗ 0,14 nút bây giờ được xem là hợp lệ trong 0,15 nút, về cơ bản tạo BTC ra khỏi không khí mỏng.

Đây là cách mà nó đến. Được giới thiệu trong 0,15, PR 10195 bao gồm rất nhiều thứ, nhưng ý chính chính của nó là cách mà các UTXO được lưu trữ thay đổi để làm cho chúng hiệu quả hơn để tìm kiếm. Kết quả là, đã có nhiều thay đổi, bao gồm một thay đổi đối với hàm UpdateCoins từ trước đó:

Lưu ý cách mã xung quanh assert(false) đã được lấy ra hoàn toàn. Nhận thấy điều này, PR 10537 , cũng trong 0.15.0 thay đổi mã để khẳng định đã được đưa trở lại.

Các điều kiện mà theo đó khẳng định không thành công bây giờ phụ thuộc vào inputs.SpendCoin trông giống như sau:

Về cơ bản, cách duy nhất để SpendCoin trả về false là nếu đồng xu không tồn tại trong tập UTXO. Nhưng như bạn có thể thấy rằng đòi hỏi các đồng tiền để được FRESH và không DIRTY . Đây không phải là điều khoản rõ ràng, nhưng may mắn thay, nhà phát triển cốt lõi Andrew Chow giải thích ở đây :

Vì vậy, bây giờ câu hỏi là, khi nào là UTXO được đánh dấu là FRESH ? Chúng được đánh dấu FRESH khi chúng được thêm vào cơ sở dữ liệu UTXO. Nhưng cơ sở dữ liệu UTXO vẫn chỉ trong bộ nhớ (như một bộ nhớ đệm). Khi nó được lưu vào đĩa, các mục trong bộ nhớ sẽ không còn được đánh dấu là FRESH nữa. Điều này tiết kiệm cho đĩa xảy ra sau mỗi khối (cũng như tại các thời điểm khác, nhưng đó không phải là quan trọng).

Đồng tiền FRESH là những đồng tiền được nhập vào bộ nhớ. Một thợ mỏ tấn công có thể phá vỡ các nút thông qua câu lệnh khẳng định đó trong UpdateCoins . Nhưng tệ hơn, nếu tiền xu là DIRTY (chủ yếu là đọc từ đĩa), thì điều này có thể gây ra lạm phát.

Do đó, có thể lừa phần mềm lõi từ 0,15 đến 0,16,2 để chấp nhận một khối không hợp lệ, kỳ quặc làm tăng nguồn cung cấp.

Mức độ nghiêm trọng của lỗ hổng lạm phát

Kinh tế của cuộc tấn công này có vẻ tốt hơn đáng kể so với trường hợp từ chối dịch vụ vì kẻ tấn công có khả năng tạo BTC ra khỏi không khí mỏng. Bạn vẫn cần thiết bị khai thác để thực hiện cuộc tấn công, nhưng tiềm năng lạm phát có thể làm cho điều này đáng giá, hoặc có vẻ như vậy.

Đây là những gì các cuộc tấn công ngây thơ trên Bitcoin bằng cách sử dụng lỗi này sẽ giống như:

  1. Tạo một khối với một giao dịch chi tiêu một số lượng BTC trở lại cho chính bạn hai lần. Nói 50 BTC → 100 BTC.
  2. Phát sóng chặn cho mọi người trên 0,15 / 0,16

Đây là những gì đã xảy ra:

  • Các nút 0.14.x sẽ bị lỗi
  • Các nút cũ hơn và nhiều khách hàng thay thế sẽ từ chối khối đó
  • Nhiều nhà thám hiểm khối chạy trên phần mềm tùy chỉnh và không phải lõi, do đó ít nhất một số người đã từ chối chặn và sẽ không hiển thị bất kỳ giao dịch nào từ khối đó
  • Tùy thuộc vào các thợ mỏ phần mềm đang chạy chúng tôi có thể đã kết thúc với một chuỗi chia.

Có thể tất cả các thợ mỏ đang chạy Bitcoin Core 0.15+ trong trường hợp khách hàng không dễ bị tổn thương sẽ bị đình trệ. Nó cũng có thể một thợ mỏ sẽ chạy một cái gì đó khác trong trường hợp một ngã ba chuỗi sẽ xảy ra ngay sau khi họ tìm thấy một khối.

Bởi vì những bất thường này, mọi người trên mạng sẽ sớm theo dõi điều này, có lẽ đã cảnh báo một số nhà phát triển và các nhà phát triển cốt lõi đã có thể sửa nó. Nếu có một ngã ba, sự đồng thuận xã hội vào thời điểm đó là chuỗi quyền sẽ bắt đầu được thảo luận và chuỗi tạo ra lạm phát bất ngờ có thể sẽ mất đi. Nếu có một gian hàng, có khả năng sẽ là một sự quay vòng tự nguyện để trừng phạt kẻ tấn công.

Vì vậy, đối với kẻ tấn công, điều này sẽ không dẫn đến +50 BTC, nhưng nhiều khả năng -12.5 BTC. Nếu kẻ tấn công tăng gấp đôi số tiền lớn hơn, nói 200 BTC, sẽ có ít cơ hội hơn nữa mà khối lạm phát sẽ dính quanh khi cuộc tấn công sẽ trắng trợn hơn nhiều.

Vì vậy, từ quan điểm của một kẻ tấn công, đây sẽ không phải là một lợi tức đầu tư rất tốt.

Một cách khác mà kẻ tấn công có thể có được lợi nhuận là bằng cách rút ngắn BTC và sau đó thực hiện một cuộc tấn công. Điều này cũng quá rủi ro vì không đảm bảo rằng giá của BTC sẽ giảm, đặc biệt nếu khủng hoảng được xử lý nhanh chóng và dứt khoát. Hơn nữa, với AML / KYC xung quanh hầu hết các giao dịch cung cấp margin, điều này có thể dẫn đến kẻ tấn công nhận được doxxed theo thứ tự khá ngắn.

Không chỉ một kẻ tấn công có một số lượng đáng kể rủi ro tiền tệ, mà còn rủi ro về thể chất. ROI không thực sự ở đó và từ góc độ kinh tế, đây không phải là một cách dễ dàng để khai thác lợi nhuận.

Tuy nhiên, một diễn viên cấp bang có thể đã sử dụng điều này như một cách để dọa các Bitcoin. ROI sẽ trừu tượng hơn, do đó, về lý thuyết, điều này có thể đã hoàn thành mục đích của một diễn viên cấp tiểu bang.

Phần kết luận

Chắc chắn, đây là một lỗi khá nghiêm trọng. Và bất chấp sự khác biệt của tôi với Awemany , tôi rất biết ơn vì người này đã chọn tiết lộ một cách có trách nhiệm. Điều đó nói rằng, với lý thuyết trò chơi kinh tế về khai thác, tôi không tin rằng lỗi này gần như là nghiêm trọng như những người như anh ta đã làm cho nó ra được.

Ngay cả khi lỗi đã được biết đến với những người xấu trước khi nó được tìm thấy, có khả năng đây sẽ không phải là thứ mà kẻ tấn công sẽ chọn để khai thác khi kinh tế học không thực sự có ý nghĩa. Để chắc chắn, phần kỹ thuật cần được cố định và làm tốt hơn, nhưng nhóm người khai thác này thực sự hữu ích để thực sự rất nhỏ (các diễn viên cấp nhà nước muốn cố gắng tiêu diệt Bitcoin, về cơ bản).

Các bài học cho Bitcoin Core rất nhiều:

  1. Bất kỳ thay đổi đồng thuận nào (thậm chí những thay đổi nhỏ bé như 9049) cần phải được nhiều người xem xét hơn.
  2. Cần kiểm tra thêm các trường hợp bệnh lý.
  3. Rõ ràng hơn trong codebase về việc kiểm tra nào là thừa và cái nào là không và mã thực tế có ý nghĩa gì.

Đã có lỗi trong quá khứ, sẽ có lỗi trong tương lai. Điều quan trọng bây giờ là học và kết hợp những bài học này.

Chào mừng trở lại.

Đăng nhập sẽ giúp cá nhân hoá nội dung trang chủ của bạn, theo dõi các chủ đề yêu thích và tương tác với các bài viết bạn yêu thích.


Chào mừng trở lại.

Đăng nhập sẽ giúp cá nhân hoá nội dung trang chủ của bạn, theo dõi các chủ đề yêu thích và tương tác với các bài viết bạn yêu thích.


Chào mừng tham gia.

Đăng nhập sẽ giúp cá nhân hoá nội dung trang chủ của bạn, theo dõi các chủ đề yêu thích và tương tác với các bài viết bạn yêu thích.


Nhấp vào “Đăng ký” để chấp nhận Điều khoản dịch vụ và chính sách bảo mật của Toppick.