Monday, September 08, 2008

CTF trick: fool replay attack with one time (based) shellcode

Trong võ công (truyện chưởng Kim Dung) có chiêu dùng chính sức ra đòn của đối phương để trả đòn lại gọi là "tá lực đả lực". Chiêu này cũng được sử dụng trong các hack game CTF, gọi chuyên môn là "replay attack": để cho team khác attack mình, bắt (capture) toàn bộ phiên làm việc (session) đó ở lớp mạng, sửa đổi lại địa chỉ nguồn/đích và replay lại. Do server của các team đều được cài đặt giống nhau, chiêu này có thể lấy được điểm dễ dàng mà không phải tốn công sức và không cần quan tâm đến nội dung dữ liệu (mã khai thác lỗi) do capture ở lớp mạng. Tất nhiên phải chờ có người "đánh" trúng mình trước, sau đó "đánh" lại chính họ và những người khác. Do cách tính điểm CTF cho điểm break through (ghi điểm đầu tiên) rất cao, các team đều nỗ lực tập trung thời gian để ghi được điểm này và mặc kệ cho thiên hạ giang hồ sử dụng chiêu của mình để đánh lẫn nhau (đánh lại mình luôn :)).

Giang hồ hiểm ác, biết đâu bọn chúng dùng chiêu của mình mà lại đánh thắng mình, tốt nhất là diệt trừ mọi hậu họa. Tuy nhiên, việc chống replay attack là khá khó khăn do: a) kêt nối mạng client - server không có mã hóa; b) không thể chủ động ở phía server do đối phương nắm giữ. Nếu chiếm được chủ động phía server, có khả năng chống được replay attack. Trong trường hợp đó, một chiến thuật để chống lại chiêu "tá lực đả lực" là: mã khai thác (exploit code) chỉ sử dụng được một lần, không thể replay dựa theo thời gian trên server. Theo cách này mã khai thác lỗi chỉ chạy đúng (valid) trong một khoảng thời gian xác định (ví dụ trong vòng 30 giây kể từ lúc được chạy lần đầu), thời gian này được xác định theo server bị khai thác do đó nếu được capture rồi replay lại sẽ không ra được kết quả. Việc tại tạo lại mã khai thác từ luồng dữ liệu (data stream) bắt được để dò ra lỗi sẽ mất thời gian hơn nhiều.

Mã khai thác lỗi ban đầu:
exploit = [padding] + [shellcode]

Mã khai thác lỗi dùng một lần:
exploit = [new padding] + [time check code] + [shellcode]

Mã giả (pseudo code) phần kiểm tra theo thời gian đơn giản như sau:
t = time(NULL); // predefined time value = when the exploit code is built and run
// shellcode
current_time = time(NULL);
if (current_time > t)
if(current_time < t + 30)
shellcode();

Mã khai thác lỗi ở mỗi lần chạy khác nhau sẽ có giá trị "t" khác nhau theo thời gian. Tuy nhiên phần mã này là tĩnh và có thể bị phát hiện khi so sánh hai lần chạy khác nhau. Một cách để tránh bị phát hiện là mã hóa mã khai thác lỗi theo cách khác nhau qua mỗi lần chạy. Với chiêu này, ta có thể chiếm phần tiện nghi hơn các đối thủ một chút, đôi khiến chúng phải bứt đầu bứt tóc để dò tìm tại sao chiêu "tá lực đả lực" lại vô hiệu :D.

Lưu ý/Hạn chế:
  • Phải có khả năng khai thác lỗi để thực thi được trên server đối phương (khi đó mới gọi time() được)
  • Buffer đủ lớn để thêm phần mã kiểm tra (16+ bytes)
  • Đồng hồ trên server đối phương không chạy sai (kiểm tra được)