Lỗi tràn bộ đệm thường xảy ra đối với loại dữ liệu mảng, khi dữ liệu nhập vào vượt quá kích thước mảng. Ví dụ chương trình sau:
void checkserial() { char sn[16]; scanf(“%s”, sn); } int main() { checkserial(); int i= 7; return 0; }
Khi hàm main() gọi hàm checkserial(), trước tiên địa chỉ của lệnh i= 7 sẽ được push vào stack để sau khi hàm checkserial thực hiện xong thì máy tính có thể thi hành tiếp lệnh i= 7. Sau đó, máy tính dành tiếp 16 byte trong stack cho mảng sn. Hình sau minh họa tình trạng bộ nhớ.
160
Sau khi hàm checkserial thực hiện xong, lệnh RET sẽ nạp lại giá trị 128 tại địa chỉ 401 trong stack vào con trỏ lệnh IP để quay về lại lệnh i= 7.
Nếu trong hàm checkserial, người sử dụng nhập vào chuỗi ít hơn 16 ký tự thì chương trình hoạt động bình thường, tuy nhiên nếu người sử dụng nhập vào chuỗi 16 ký tự trở lên thì lúc này ô nhớ 401 sẽ bị đè bởi ký tự thứ 16, tình trạng tràn bộ đệm xảy rạ Lúc này khi lệnh RET của hàm checkserial thực hiện, con trỏ lệnh IP sẽ có 1 giá trị khác chứ không phải là 128, do đó lệnh i= 7 sẽ không được thực hiện. Hacker có thể lợi dụng điều này để tiến hành các hoạt động phá hoạị Xét chương trình cụ thể sau:
void checkserial() { char sn[16];
printf(“\nEnter a serial number\n”); scanf(“%s”, sn);
if (!strncmp(sn, “S123N456”, 8)) { printf(“Serial number is correct”); } } int main() { checkserial(); int i=7; return 0; }
Mục đích của chương trình trên là khi người dùng nhập vào chuỗi “S123N456” thì chương trình sẽ in ra câu “Serial number is correct”, nếu không thì không in gì cả.
checkserial() i=7 ret … scanf(“%s”,sn) ret 128 120 128 132 200 300 … 3F0 … 400 401 hàm main() hàm checkserial() Code segment Stack segment Vùng nhớ cho biến sn IP SP P
161 Lợi dụng lỗi tràn bộ đệm hacker sẽ tìm cách nhập vào một chuỗi gì đó (khác “S123N456”) mà chương trình vẫn in ra câu “Serial number is correct”. Chúng ta sẽ minh họa cách thức thực hiện bằng chương trình OllyDebugger.
Hình trên minh họa hàm main được nạp vào bộ nhớ. Tại địa chỉ 0040130C là lệnh gọi hàm checkserial, tại địa chỉ 00401311 là lệnh để thực hiện lệnh i= 7. Khi thực hiện lệnh gọi hàm checkserial thì tình trạng của Stack segment như sau:
162
Địa chỉ quay về hàm main (tại lệnh i=7) 00401311 được đưa vào stack tại địa chỉ
0022FF2C. Mảng sn được cấp 16 byte bắt đầu tại địa chỉ 0022FF10 đến địa chỉ 0022FF1F
(từ ô 0022FF20 đến 0022FF2B , gồm 12 byte, bỏ trống). Do khi thực hiện hàm scanf, nếu người dùng nhập vào 32 ký tự, thì các ký tự thứ 29, 30, 31, 32 sẽ đè lên địa chỉ quay về
00401311 tạo thành một địa chỉ quay về mớị Hacker có thể lựa chọn giá trị nhập vào sao cho địa chỉ quay về là theo ý của hacker. Giả sử hacker muốn in ra câu “Serial number is correct”, hacker có thể chọn giá trị nhập vào sao cho địa chỉ quay về là 004012D4 (nếu biểu diễn bằng ký tự ASCII, 40: @; D4: Ⱡ;12: Ctrl+R). Do đó hacker sẽ nhập vào chuỗi sau:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAⱠ^R@
Lúc này tình trạng bộ nhớ stack sẽ là:
(41 là mã ASCII của ký tự A)
Ô nhớ 0022FF2C trong stack bây giờ có giá trị 004012D4. Do đó, sau khi hàm checkserial thực hiện xong thì lệnh RETN (tại ô nhớ 004012E1) sẽ không nhảy đến lệnh i= 7 của hàm main nữa mà nhảy đến lệnh in câu “Serial number is correct” tại ô nhớ
163
Lưu ý: Có thể thực hiện kết quả như trên mà không cần biết source code, chỉ cần dùng chương trình debug. Source code phần trên mang tính chất minh họạ
Nếu sn là một mảng dài vài trăm ký tự thì hacker có thể chèn vào một đoạn lệnh phá hoại (shell code - trong ví dụ trên ta đơn giản chỉ nhập các ký tự A) và sau đó thi hành đoạn lệnh phá hoại nàỵ Đây chính là cách thức mà sâu Code Red vào năm 2001 đã sử dụng để lây nhiễm vào hơn 750.000 máy tính trên khắp thế giới, dựa vào một lỗi buffer overflow trong phần mềm Microsoft IIS.