1. Trang chủ
  2. » Công Nghệ Thông Tin

Tấn công tràn bộ đệm Buffer Over flow và demo.docx

21 22 2

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 21
Dung lượng 633,38 KB

Nội dung

MỤC LỤC DANH MỤC CÁC HÌNH VẼ CHƯƠNG TỔNG QUAN VỀ LỖI TRÀN BỘ ĐỆM .1 1.1 Khái niệm đệm 1.2 Lỗi tràn đệm 1.2.1 Tràn đệm heap (Head over flow) 1.2.2 Tràn đệm stack (Stack over flow) CHƯƠNG MỘT SỐ PHƯƠNG PHÁP KHAI THÁC VÀ PHÒNG CHỐNG LỖI TRÀN BỘ ĐỆM 2.1 Một số phương pháp khai thác lỗi tràn đệm .2 2.1.1 Thay đổi giá trị biến cục 2.1.2 Ghi đè địa trả hàm 2.1.3 Quay thư viện chuẩn (Return-to-libc) 2.1.4 Kỹ thuật ROP (Return Oriented Program) 2.2 Các chế bảo vệ, chống khai thác lỗi tràn đệm 11 2.2.1 Buffer Security Check -/GS 11 2.2.2 SafeSEH .13 2.2.3 DEP .13 2.2.4 ASLR .14 CHƯƠNG DEMO KHAI THÁC LỖI TRÀN BỘ ĐỆM .15 3.1 Môi trường thử nghiệm 15 3.2 Kết thử nghiệm 18 DANH MỤC CÁC HÌNH Hình 2.1 Vị trí cookie buf Hình 2.2 Quá trình tràn biến buf trạng thái cần đạt Hình 2.3 Cách đặt địa hàm đối số stack Hình 2.4 Cách đặt hàm system() exit() stack .7 Hình 2.5 Tìm kiếm gadgets thủ công .9 Hình 2.6 Tìm kiếm modules nạp lên nhớ chương trình 10 Hình 2.7 Tìm kiếm tất gadgets có modules kernel32.dll 10 Hình 2.8 Các gadgets tập tin rop.txt 10 Hình 2.9 Windows bảo vệ - /GS Visul Studio 2008 .11 Hình 2.10 Mơ tả tùy chọn “/DYNAMICBASE” thiết lập Visual Studio 2013 14Y Hình 3.1 Tiến hành chạy thử file biên dịch 14 Hình 3.2 Nhập thử vài ký tự 14 Hình 3.3 Tận dụng thành công lỗi tràn đệm head 16 CHƯƠNG TỔNG QUAN VỀ LỖI TRÀN BỘ ĐỆM 1.1 Khái niệm đệm Bộ đệm vùng nhớ hệ điều hành cấp phát sẵn cho chương trình chương trình nạp lên nhớ Chương trình sử dụng vùng nhớ để chứa biến tạm liệu trình thực thi chương trình 1.2 Lỗi tràn đệm Tràn đệm lỗi xảy liệu xử lý, thường liệu đầu vào, dài giới hạn vùng nhớ đệm cấp phát để chứa Nếu phía sau vùng nhớ chứa liệu quan trọng tới trình thực thi chương trình liệu dư thừa làm hỏng liệu quan trọng 1.2.1 Tràn đệm heap (Head over flow) Heap sử dụng cho việc cấp phát nhớ động heap sử dụng để lưu trữ liệu, không sử dụng để lưu giá trị địa trả hàm stack nên việc khai thác lỗi tràn đệm heap khó so với khai thác stack Tuy vậy, khai thác thành công lỗi tràn đệm heap cách sau: Sửa liệu: Kẻ công khai thác lỗ hổng cách ghi đè liệu quan trọng Điều làm hỏng chương trình làm thay đổi giá trị sử dụng sau Sửa đối tượng: Trong ngôn ngữ lập trình C++, Objective C, đối tượng đặt heap bao gồm bảng trỏ hàm liệu, thay liệu khác chí thay phương thức thể lớp đối tượng Quản lý heap: Tuy việc cài đặt nhớ heap khác tương đối nhiều vài tính chất chung cài đặt hầu hết thuật toán Về bản, lời gọi tới hàm malloc() đoạn chương trình cấp phát tương tự tạo ra, số ô nhớ lấy từ nhớ heap trả cho người dùng 1.2.2 Tràn đệm stack (Stack over flow) Lỗi tràn đệm stack xuất đệm lưu trữ liệu nhớ khơng kiểm sốt việc ghi giá trị dẫn đến tràn stack việc tràn stack làm cho biến cục địa trở hàm bị ghi đè Trong thực tế, biến cục thường cấp phát liên tiếp stack có lỗi xảy cho phép liệu ghi thêm vào ô nhớ stack, liệu ghi đè lên biến cục bộ, thơng tin trạng thái chương trình, tham số hàm địa trở hàm CHƯƠNG MỘT SỐ PHƯƠNG PHÁP KHAI THÁC VÀ PHÒNG CHỐNG LỖI TRÀN BỘ ĐỆM 2.1 Một số phương pháp khai thác lỗi tràn đệm 2.1.1 Thay đổi giá trị biến cục Ví dụ 1: Int main () { int cookie; char buf [16]; printf (“&buf:_%p,_&cookie:_%p\n”, buf, &cookie); if (cookie == 0x41424344) { printf (“You_Win!\n”); } } Ví dụ ví dụ Để biên dịch ví dụ tương tự ta dùng cú pháp lệnh gcc –o sau: Bạn đọc dễ dàng nhận GCC cảnh báo nguy hiểm việc sử dụng hàm gets Chúng ta bỏ qua cahr báo hàm gây lỗi tràn đệm, đối tượng mà bàn đến chương trình Để tận dụng lỗi thành công, người tận ụng lõi phải hiểu rõ chương trình hoạt động Ví dụ nhận chuỗi từ nhập chuẩn (Stdin) thông qua hàm gets Nếu giá trị biến nội cookie 41424344 in cuất chuẩn (Stdout) dịng chữ “You_Win!” Biến cookie đóng vai trị liệu quan trọng trình hoạt động chương trình Hình 2.1 Vị trí cookie buf Thông qua việc hiểu cách hoạt động chương trình, thấy than chương trình chưa mã thực tác vụ mong muốn (in hình dịng chữ “You_win!” Do đường để dạt mục tiêu gán giá trị cookie với giá trị 41424344 Ngồi việc hiểu cách hoạt động chương trình, người tận dụng lỗi dĩ nhiên phải tìm nơi phát sinh lỗi Chúng ta may mắn GCC thông báo lỗi nằm hàm gets Vấn đề trở thành để tận dụng lỗi hàm gets để gán giá trị cookie 41424344 Hàm gets thực việc nhận chuỗi từ nhập chuẩn đưa vào đệm Ký tự kết thúc chuỗi (mã ASCII 00) hàm gets tự động thêm vào cuối Hàm khơng kiểm tra kích thước vùng nhớ dùng để chứa liệu nhập xảy tràn đệm liệu nhập dài kích thước đệm Vùng nhớ truyền vào hàm gets để chứa liệu nhập biến nội buf Trên nhớ, cấu trúc biến nội hàm main xác định Hình 2.1 Vì biến cookie khai báo trước nên biến cookie phân phát nhớ ngăn xếp trước, đồng nghĩa với việc biến cookie nằm địa cao biến buf, nằm phía sau buf nhớ Hình 2.2 Quá trình tràn biến buf trạng thái cần đạt Nếu ta nhập vào ký tự “abcdef” trạng thái nhớ Hình 3.2a, 10 ký tự “0123456789abcdef” byte cookie bị viết đè với ký tự kết thúc chuỗi, 14 ký “0123456789abcdefghij” tự tồn biến cookie bị ta kiểm sốt Để cookie có giá trị 41424344 nhớ biến cookie phải có giá trị 44, 43, 42, 41 theo quy ước kết thúc nhỏ vi xử lý Intel x86 Hình 3.2d minh họa trạng thái nhớ cần đạt tới để dòng chữ “You win!” in hình Ví dụ 2: int main () { int cookie; char buf[16]; printf (“&buf:_%p,_&cookie:_%p\n”, buf, &cookie); if (cookie == 0x0102030405) { printf (“You_Win!\n”); } } Như vậy, liệu mà cần nhập vào chương trình 10 ký tự để lấp đầy biến buf, theo sau ký tự có mã ASCII 44, 43, 42, 41 Bốn ký tự D, C, B, A Hình chụp sau kết ta nhập vào 10 ký tự “a” “DCBA” Chúng ta tận dụng thành công lỗi tràn đệm chương trình để ghi đè biến nội quan trọng Kết đạt ví dụ chủ yếu câu trả lời cho câu hỏi quan trọng: cần nhập vào liệu Ở ví dụ sau, gặp câu hỏi tổng quát tương tự mà trình tận dụng lỗi phải có câu trả lời 2.1.2 Ghi đè địa trả hàm Một người dùng thạo kỹ thuật có ý đồ xấu khai thác lỗi tràn đệm stack để thao túng chương trình theo cách sau: Ghi đè biến địa phương nằm gần nhớ đệm stack để thay đổi hành vi chương trình nhằm tạo thuận lợi cho kẻ cơng Ghi đè địa trả khung stack (stack frame) Khi hàm trả về, thực thi tiếp tục địa mà kẻ công rõ, thường đệm chứa liệu vào người dùng Nếu địa phần liệu người dùng cung cấp, biết địa lưu ghi, ghi đè lên địa trả giá trị địa opcode mà opcode có tác dụng làm cho thực thi nhảy đến phần liệu người dùng 2.1.3 Quay thư viện chuẩn (Return-to-libc) Quay trở thư viện chuẩn kỹ thuật khai thác lỗi phần mềm chống lại chế DEP, chế ngăn chặn việc thực thi vùng nhớ đánh dấu đọc ghi Thay ghi đề địa trả hàm thành địa shellcode kỹ thuật ghi đè địa trả thành địa hàm thư viện nạp lên nhớ Dữ liệu đưa vào chương trình kiểm sốt vùng nhớ stack sử dụng tham số đầu vào hàm[Error: Reference source not found] Hình 2.3 mơ tả cách đặt địa hàm đối số cho hàm địa hàm stack Hình 2.3 Cách đặt địa hàm đối số stack Ta xét ví dụ sau: #include #include main(int argc, char **argv) { char buffer[80]; getchar(); strcpy(buffer, argv[1]); return 1; } Trong ví dụ trên, hàm strcpy() copy giá trị từ tham số chương trình vào biến không kiểm tra xem liệu có vượt q kích thước biến lưu trữ buffer hay không, cụ thể biến buffer lưu trữ 80 byte, liệu đưa vào chương trình lớn 80 byte lỗi tràn đệm xảy hàm strcpy() Để minh họa việc khai thác chương trình sử dụng kỹ thuật return-to-libc, ta truyền chuỗi “calc” vào hàm system() để gọi chương trình calculator Windows, sau hàm exit() gọi để kết thúc chương trình Hàm system() hàm exit() hai hàm nằm thư viện chuẩn nạp lên nhớ chương trình Hình 2.4 minh họa cách đặt địa hàm system() exit() stack để thực khai thác lỗi Theo Hình 2.4, ta cần 80 byte để ghi đè biến buffer byte để ghi đè giá trị EBP, giá trị Addr1 địa hàm system() ghi đè địa trả hàm main() Addr2 giá trị stack, Addr2 giá trị trả sau hàm system() kết thúc, nghĩa hàm system() kết thúc, hàm exit() gọi Addr3 tham số hàm system(), giá trị trỏ đến vùng nhớ lưu trữ chuỗi truyền vào hàm system(), trường hợp trỏ đến chuỗi “calc” Sau tham số “calc” truyền vào, hàm system() gọi chương trình Calculator Windows Hình 2.4 Cách đặt hàm system() exit() stack 2.1.4 Kỹ thuật ROP (Return Oriented Program) ROP – Return Oriented Programing: Là kỹ thuật khai thác lỗi tràn đệm chương trình bảo vệ chế DEP, kỹ thuật gần giống kỹ thuật quay trở thư viện chuẩn (return to libc), thay quay trở trực tiếp lời gọi hàm thư viện chuẩn ROP sử dụng đoạn code nhỏ có sẵn module chương trình thư viện nạp lên nhớ xếp đoạn code stack theo thứ tự định để thực việc khai thác lỗi, đoạn code nhỏ gọi “Gadgets” Gadgets nhóm nhỏ tập lệnh kết thúc lệnh RET Ví dụ mov eax, 0x10; ret gadgets cho phép thiết lập giá trị ghi eax thành 0x10 sau lệnh RET lấy giá trị đỉnh stack gán cho ghi trỏ lệnh EIP chương trình tiếp tục thực mã lệnh địa mà ghi EIP trỏ đến Các gadgets kết hợp với tạo thành chuỗi gadgets, chuỗi gadgets cịn gọi “ROP chain” Tìm kiếm gadgets thủ cơng - Sử dụng chương trình gỡ lỗi IDA, OllyDbg, Immunity Debugger để tìm kiếm tất lệnh “retn” byte “C3” chương trình module thư viện sử dụng chương trình - Từ lệnh “ret” tìm được, thực tìm kiếm số byte phía so với lệnh “ret” để mã lệnh hợp lệ mà theo sau “ret” - Thực việc ghi lại tất mã lệnh theo sau “ret” Như ta thấy Hình 2.5, gadgets tìm thấy nằm khung vẽ hình chữ nhật Ta có tất gadgets: 0x00401473: 0x00401474: 0x00401492: 0x00401494: #POP #POP #XOR #POP EDI #POP ESI #RETN ESI #RETN EAX, EAX #POP EBP #RETN EBP #RETN Hình 2.5 Tìm kiếm gadgets thủ cơng Tìm kiếm gadgets tự động Có thể thực tìm kiếm tất gadgets chương trình module thư viện sử dụng chương trình cách tự động việc sử dụng mona.py [Error: Reference source not found] Đây PyCommands trình gỡ lỗi Immunity Debugger, chương trình viết Python viết corelanc0de3r Chỉ cần copy tập tin mona.py vào thư mục “PyCommands” thư mục cài đặt Immunity Debugger sử dụng Hình 2.5 mơ tả việc sử dụng lệnh “!mona modules” để tìm kiếm tất modules nạp lên nhớ với chương trình “test.exe” Immunity Debugger Như ta thấy có module ntdll.dll, kernel32.dll, msvcr100.dll chương trình test.exe Hình 2.6 mơ tả việc sử dụng lệnh “!mona rop –m kernel32” để tìm kiếm tất gadgets có module kernel32.dll, tất gadgets lưu vào tập tin “rop.txt” tập tin lưu thư mục cài đặt Immunity Debugger Hình 2.6 Tìm kiếm modules nạp lên nhớ chương trình Hình 2.7 Tìm kiếm tất gadgets có modules kernel32.dll Nội dung tập tin rop.txt minh họa Hình 2.8 Hình 2.8 Các gadgets tập tin rop.txt 10 2.2 Các chế bảo vệ, chống khai thác lỗi tràn đệm 2.2.1 Buffer Security Check -/GS Chúng ta phân tích cờ / GS Visual Studio C / C ++ Tùy chọn cố gắng để ngăn chặn chồng BOF dựa vào thời gian chạy thêm số dòng mã đoạn mở đầu kết thúc thủ tục / GS thực hai chế để đánh bại công Thứ giá trị ngẫu nhiên , gọi cookie canary , lưu trữ stack , thứ hai loại xếp lại biến thực Sau chương trình khởi động, cookie lưu phần liệu, sau , cần thiết , phần mở thủ tục di chuyển stack biến cục địa ret, giá trị bảo vệ Đồ họa stack nhìn chung giống sau: Var1 Buf1 Buf2 Var2 Cookie SFP RET Bây xem làm để kích hoạt vơ hiệu hóa ag fl Visual Studio 08, xảy đoạn mở đầu thủ tục: Hình 2.9 Windows bảo vệ - /GS Visul Studio 2008 vuln!main: 00411260 55 push ebp 00411261 8bec mov ebp,esp 00411263 83ec4c sub esp,4Ch 00411266 a100604100 mov EAX,dword ptr [vuln! security_cookie 11 (00416000)] 0041126b 33c5 xor EAX,ebp 0041126d 8945fc mov dword ptr [ebp4],EAX Đây đoạn mở đầu sử dụng cờ / GS , bạn thấy, giá trị cookie lưu trữ EAX đăng ký sau XORed với trỏ sở đặt stack Từ dịng mã dọn dẹp ngăn xếp giống Hình vẽ ngăn xếp (sau trỏ khung hình lưu lại) Bây xem phần kết : 0041128b 8b4dfc mov ECX, dword ptr [ebp-4] 0041128e 33cd xor ECX, ebp 00411290 e87ffdffff call vuln!ILT+15( security_check_cookie (00411014) 00411295 8be5 mov esp,ebp 00411297 5d pop ebp Trước hết , nhận cookie từ stack lưu trữ sổ đăng ký ECX , thứ hai xor với EBP cuối gọi để thường xuyên kiểm tra Chúng ta xem làm kiểm tra thực hiện: vuln! security_check_cookie: 004112b0 3b0d00604100 cmp ECX,dword ptr[vuln! security_cookie(00416000)]004112b67502jne vuln! security_check_cookie+0xa (004112ba) 004112b8 f3c3 rep ret 004112ba e991fdffff jmp vuln!ILT+75( _report_gsfailure) (00411050) Giá trị ECX, cookie stack, so sánh với thực thể chúng khơng nhảy vào báo cáo để khỏi trình, thực tế sau nhiều hướng dẫn gọi : vuln! report_gsfailure: 00411800 8bff mov edi,edi 00411802 55 push ebp 00411904 ff1578714100 call dword ptr [vuln! _imp TerminateProcess (00417178) Do đó, kẻ cơng ghi đè nhớ đệm ghi đè lên tập tin cookie tốt, thực tế cookie giao sau trỏ sở lưu Như , trình kiểm tra, báo cáo gọi gọi TerminateProcess Một chế sử dụng cờ / GS để giảm thiểu loại công dựa xếp lại biến Ý tưởng đơn giản: muốn giảm thiểu hiệu ứng suốt bất ngờ tràn đệm, đặc biệt muốn tránh việc ghi đè biến cục đối số truyền cho hàm Bất đối số dễ bị tổn thương có nghĩa là buffer trỏ tìm thấy xếp lại địa cao ( nhớ bố trí stack) : cách này, buffer flow xảy lưu biến cục hàm 12 2.2.2 SafeSEH SafeSEH chế giúp ngăn chặn việc khai thác chương trình dựa vào SEH (Structured Exception Handler) Khi chế bật, chương trình biên dịch với cờ /safeSEH Thay bảo vệ stack chế Buffer Security Check, chương trình biên dịch với cờ /safeSEH bao gồm danh sách chứa tất địa biết mà sử dụng hàm xử lý ngoại lệ Nếu có ngoại lệ xảy ra, chương trình kiểm tra xem địa chuỗi ghi SEH có nằm danh sách hàm xử lý ngoại lệ biết hay không Nếu địa không nằm danh sách hàm xử lý ngoại lệ chương trình bị kết thúc mà không xử lý ngoại lệ xảy 2.2.3 DEP DEP – Data Execution Prevention chế bảo vệ chương trình thơng qua việc ngăn chặn đoạn mã thực thi vùng nhớ đánh dấu đọc ghi Cụ thể DEP ngăn chặn khai thác lỗi tràn đệm chương trình cách không cho đoạn mã thực thi vùng nhớ stack Đối với vi xử lý tương thích với DEP có bit quy định chế độ mà DEP thực hiện, với dòng vi xử lý AMD có bit NX (No Execute), với dịng vi xử lý Intel có bit XD (Execute Disable) Mặc định vùng nhớ chứa liệu stack, heap, nhớ dùng chung đánh dấu vùng nhớ thực thi Khi mã lệnh cố gắng thực thi vùng nhớ bảo vệ DEP, lỗi truy cập vùng nhớ bất hợp lệ đưa với mã lỗi 0xC0000005 (STATUS_ACCESS_VIOLATION) Cơ chế bảo vệ DEP lần đưa vào hệ điều hành Windows XP SP2 Windows Server 2003 SP1 phiên sau hai phiên hệ điều hành hỗ trợ DEP DEP thường cấu hình với giá trị sau: - OptIn: Chỉ số tập tin hệ thống Windows bảo vệ DEP - OptOut: Tất chương trình, tiến trình, dịch vụ Windows bảo vệ DEP, ngoại trừ số chương trình có danh sách ngoại lệ - AlwaysOn: Tất chương trình, tiến trình, dịch vụ chạy Windows bảo vệ khơng có ngoại lệ - AlwaysOff: Cơ chế DEP không bật 13 2.2.4 ASLR ASLR – Address Space Layout Randomization: Là chế ngẫu nhiên hóa khơng gian địa nhằm bảo vệ chương trình, làm cho việc khai thác lỗi chương trình gặp khó khăn Cơ chế ASLR bắt đầu đưa vào Windows Vista, Windows Server 2008 phiên sau Windows Cơ chế ASLR thực việc tính toán ngẫu nhiên địa sở tập tin thực thi (.exe), tập tin liên kết động (.dll), stack heap khơng gian địa tiến trình Địa sở thay đổi sau lần chương trình nạp lại lên nhớ ASLR mặc định thiết lập cho tập tin hệ thống, với chương trình mà liên kết với tùy chọn “/DYNAMICBASE” Tùy chọn “/DYNAMICBASE” hỗ trợ Visual Studio 2005 SP1 phiên cao Hình 2.10 Mơ tả tùy chọn “/DYNAMICBASE” thiết lập Visual Studio 2013 14 CHƯƠNG DEMO KHAI THÁC LỖI TRÀN BỘ ĐỆM 3.1 Môi trường thử nghiệm - Môi trường thực demo môi trường Linux, mơi trường khác khơng cho kết trình bày báo cáo - Đoạn mã chứa lỗi tràn đệm #include int main() { char *name; char *command; name=(char *)malloc(10); command=(char *)malloc(128); printf("Dia chi ten: %p, Dia chi lenh: %p\ n",name,command); sprintf(command,"echo %s","Xin chao"); gets(name); system(command); } Để ý thấy đoạn mã biến name, command cấp phát nhớ động sử dụng hàm malloc Cú pháp: void* malloc(size_t size); Ý nghĩa: Cấp phát vùng nhớ động có kích thức size byte Chúng ta tiến hành biên dịch file gcc Linux 15 Hình 3.1 Tiến hành chạy thử file biên dịch Hình 3.2 Nhập thử vài ký tự Như mục tiêu ta tận dụng lỗi khơng kiểm tra liệu nhập vào thông qua hàm gets để làm phần liệu ta nhập vào tràn sang biến command hàm system() thực thi câu lệnh bên trong.Vấn đề cần xác định byte nhập vào để gây tràn head Chúng ta thử load chương trình lên gdb, gdb trình gỡ rối Linux 16 Để ý chương trình cấp phát nhớ động nên không tận dụng giá trị trả hàm để thay đổi luồng thực thi chương trình Một lưu ý khác kiến trúc Intelx32 u cầu cấp phát nhớ ln nhớ cấp phát cho bội số Biến name thông qua hàm malloc cấp phát nhớ 10byte thực tế hệ thống hiểu cấp phát cho biến name không gian nhớ 16byte Do hàm gets không thực kiểm tra liệu nhập vào nên phần liệu 16byte bị tràn sang biến command thực thi thông qua hàm system() Chúng ta thử truyền liệu vào chương trình thơng qua câu lệnh sau Python –c ‘print “a”*16+”ls”’ | /bof 17 Hình 3.3 Tận dụng thành công lỗi tràn đệm head 3.2 Kết thử nghiệm Chúng ta dễ dàng thực thi command cách bất hợp pháp việc ghi đè 16byte liệu 18 ... dịch 14 Hình 3.2 Nhập thử vài ký tự 14 Hình 3.3 Tận dụng thành công lỗi tràn đệm head 16 CHƯƠNG TỔNG QUAN VỀ LỖI TRÀN BỘ ĐỆM 1.1 Khái niệm đệm Bộ đệm vùng nhớ hệ điều hành cấp... người dùng 1.2.2 Tràn đệm stack (Stack over flow) Lỗi tràn đệm stack xuất đệm lưu trữ liệu nhớ khơng kiểm sốt việc ghi giá trị dẫn đến tràn stack việc tràn stack làm cho biến cục địa trở hàm... trọng 1.2.1 Tràn đệm heap (Head over flow) Heap sử dụng cho việc cấp phát nhớ động heap sử dụng để lưu trữ liệu, không sử dụng để lưu giá trị địa trả hàm stack nên việc khai thác lỗi tràn đệm heap

Ngày đăng: 17/11/2022, 15:10

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w