Vì BSH được đề cập, shellcode của bạn không chứa byte tin nhắn. Nhảy tới nhãn MESSAGE
và gọi phương thức GOBACK
ngay trước khi xác định byte msg
là một động thái tốt vì địa chỉ của thư sẽ nằm ở trên cùng của ngăn xếp làm địa chỉ trả lại có thể được xuất hiện thành ecx
, nơi địa chỉ của thư được lưu trữ .
Nhưng cả mã của bạn và mã của BSH đều có giới hạn nhỏ. Nó chứa NULL bytes (\x00)
sẽ được coi là kết thúc chuỗi khi được trỏ bởi con trỏ hàm.
Có một cách thông minh xung quanh việc này. Các giá trị bạn lưu trữ vào eax, ebx and edx
đủ nhỏ để được ghi trực tiếp vào các nibbles thấp hơn của thanh ghi tương ứng trong một lần truy cập bằng cách truy cập al, bl and dl
tương ứng. Nibble phía trên có thể chứa giá trị rác vì vậy nó có thể được xored.
b8 04 00 00 00 ------ mov $0x4,%eax
trở thành
b0 04 ------ mov $0x4,%al
31 c0 ------ xor %eax,%eax
Không giống như các tập lệnh trước đó, các tập lệnh mới không chứa bất kỳ byte NULL.
Vì vậy, chương trình cuối cùng trông như thế này:
global _start
section .text
_start:
jmp message
proc:
xor eax, eax
mov al, 0x04
xor ebx, ebx
mov bl, 0x01
pop ecx
xor edx, edx
mov dl, 0x16
int 0x80
xor eax, eax
mov al, 0x01
xor ebx, ebx
mov bl, 0x01 ; return 1
int 0x80
message:
call proc
msg db " y0u sp34k 1337 ? "
section .data
Lắp ráp và liên kết:
$ nasm -f elf hello.asm -o hello.o
$ ld -s -m elf_i386 hello.o -o hello
$ ./hello
y0u sp34k 1337 ? $
Bây giờ trích xuất các shellcode từ nhị phân hello:
$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done
đầu ra:
\xeb\x19\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x12\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xb3\x01\xcd\x80\xe8\xe2\xff\xff\xff\x20\x79\x30\x75\x20\x73\x70\x33\x34\x6b\x20\x31\x33\x33\x37\x20\x3f\x20
Bây giờ chúng tôi có thể có chương trình trình điều khiển để khởi chạy shellcode.
#include <stdio.h>
char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb"
"\xb3\x01\x59\x31\xd2\xb2\x12\xcd"
"\x80\x31\xc0\xb0\x01\x31\xdb\xb3"
"\x01\xcd\x80\xe8\xe2\xff\xff\xff"
"\x20\x79\x30\x75\x20\x73\x70\x33"
"\x34\x6b\x20\x31\x33\x33\x37\x20"
"\x3f\x20";
int main(int argc, char **argv) {
(*(void(*)())shellcode)();
return 0;
}
Có một số tính năng bảo mật nhất định trong trình biên dịch hiện đại như NX protection ngăn chặn việc thực thi mã trong phân đoạn dữ liệu hoặc ngăn xếp. Vì vậy, chúng ta nên xác định rõ ràng trình biên dịch để vô hiệu hóa chúng.
$ gcc -g -Wall -fno-stack-protector -z execstack launcher.c -o launcher
Bây giờ, launcher
có thể được gọi để khởi chạy shellcode.
$ ./launcher
y0u sp34k 1337 ? $
Đối với các mã shell phức tạp hơn, sẽ có một trở ngại khác. Hạt nhân Linux hiện đại có ASLR hoặc Address Space Layout Randomization
Bạn có thể cần vô hiệu hóa điều này trước khi tiêm shellcode, đặc biệt là khi nó tràn qua bộ đệm.
[email protected]:~# echo 0 > /proc/sys/kernel/randomize_va_space
Không chắc chắn tại sao bạn không nhận được bất kỳ upvotes nào, nhưng đây là một câu trả lời tuyệt vời. Cảm ơn đã giúp đỡ. –
null byte cần được loại bỏ để thực thi một shellcode tho – REALFREE
@REALFREE Null byte sẽ là một vấn đề nếu bạn làm việc với một hàm yêu cầu null chấm dứt chuỗi như chuỗi chức năng như 'strcpy', nó sẽ không đọc toàn bộ shellcode, chuỗi. Nếu không thì OK. –