Bài trước thì chúng ta đã bàn về lỗi stackoverflow, thì bài này sẽ bàn về tấn công format string.
Format string
Format string specifier xuất hiện dưới dạng dấu phần trăm và một chữ cái trong bảng alphabet, ví dụ như: %s, %d,… dùng để định dạng kiểu giá trị của dữ liệu sẽ được xuất ra, đơn giản hãy nói đến hàm printf. Nếu bạn có để ý thì các bài học dạy C cơ bản luôn dạy cách in một chuỗi do người dùng nhập ra màn hình là:
printf(“%s”, buffer);
chứ không phải là:
print(buffer);
Bạn đã bao giờ thắc mắc vì sao lại như thế chưa? trong bài này ta sẽ cùng giải đáp vấn đề đấy.
Đầu tiên viết chương trình giống như này và compile:
Lúc compile thì compiler đã cảnh báo về việc truyền trực tiếp chuỗi input của user vào hàm printf, nhưng mà với một nhà phát triển phần mềm cẩu thả thì “What could go wrong ¯\_(ツ)_/¯ ?”
Ok, vậy thì với những người dùng bình thường họ sẽ nhập tên, họ, hay những câu từ ngẫu nhiên, và chương trình cũng không xảy ra lỗi gì cả:
Vậy với những người dùng “không bình thường” thì sao, thì họ sẽ nhập những thứ cũng bất thường như thế này:
Hmm, những dòng đầu tiên thì chương trình vẫn trả lại output bình thường nhưng sau đó có cái gì sai sai:
Vì chỉ chương trình truyền thằng input của user vào hàm printf mà không cần format specifier nên khi user nhập %x, %d, %c,… hay tương tự vậy thì chương trình sẽ lầm tưởng luôn đó chính là format specifier, và không có tham số truyền thêm cho hàm printf để ứng với format specifier đó nên hàm printf sẽ lấy trực tiếp giá trị trên stack. Vậy thì tác dụng của format specifier attack là để leak dữ liệu hoặc thay đổi bằng %n, nhưng cách thức tấn công ghi đè dữ liệu thì đã quá cũ và hoàn toàn bất khả thi trong các hệ thống hiện đại nên mình sẽ không nhắc đến ở đây, trong bài này mình sẽ chỉ nói đến phần leak dữ liệu kết hợp với stackoverflow để có thể bypass cơ chế Canary stack của hệ thống. Giờ ta sẽ viết chương trình và compile nó mà không tắt lựa chọn canary, vì vậy ta sẽ phải leak canary thì mới stackoverflow được:
Như đã thấy thì chương trình ngay lập tức hủy tiến trình nếu canary bị overwrite, vậy thì ta sẽ leak chương canary và khiến cho canary không bị thay đổi trong quá trình tấn công stackoverflow.
Sử dụng %p để leak con trỏ dạng pointer, sử dụng %<n>$p với <n> là số thứ tự tính từ vị trị bị leak đầu tiên trên stack, như vậy ta có thể đếm khoảng cách từ canary đến stack rồi sử dụng cú pháp trên để leak.
Sau khi disassemble chương trình bằng gdb thì ta thấy canary luôn nằm ở vị trí [rbp-0x8], vậy ta chỉ cần chạy chương trình, tính khoảng cách và leak canary.
Sau khi thử debug chương trình vài lần thì ra đã tìm ra khoảng cách là 11, vậy ta chỉ cần truyền vào %11$p là có thể leak được canary:
Leak được canary thì bây giờ chỉ cần tính khoảng cách giữa địa chỉ nhập input và địa chỉ chứa return pointer nữa là có thể exploit thành công chương trình:
Ở đây thì là 56, địa chỉ hàm secret thì ta có thể xem bằng lệnh trong gdb là:
disassemble secret
Vậy thì mọi thứ đã hoàn tất, canary đã leak, có địa chỉ của hàm ta cần đến, hãy viết exploit:
Và… chương trình đã xuất hiện được dòng chữ Oops… secret! lần nữa, vậy là ta đã bypass thành công cơ chế bảo vệ stack canary của compiler 😀
Views: 2006