Assembly 如何重新编程外壳代码片段以避免空字节?
我已经编写了一个x64linux程序集。它所做的只是打印一行“你好,世界”,仅此而已。然而,我想做的是通过objdump从它的目标文件复制字节,这样我就可以为缓冲区溢出攻击生成自己的外壳代码 我面临的问题是外壳代码包含大量空字节,这将终止外壳代码的执行Assembly 如何重新编程外壳代码片段以避免空字节?,assembly,x86-64,nasm,shellcode,Assembly,X86 64,Nasm,Shellcode,我已经编写了一个x64linux程序集。它所做的只是打印一行“你好,世界”,仅此而已。然而,我想做的是通过objdump从它的目标文件复制字节,这样我就可以为缓冲区溢出攻击生成自己的外壳代码 我面临的问题是外壳代码包含大量空字节,这将终止外壳代码的执行 root@kali:~/C scripts/shellcode/Assembly Based Shellcode# cat print.asm section .text global _start _start: mov r
root@kali:~/C scripts/shellcode/Assembly Based Shellcode# cat print.asm
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, 12
syscall
mov rax, 60
xor rdi, rdi
syscall
message:
db "Hello world", 10
root@kali:~/C scripts/shellcode/Assembly Based Shellcode# nasm -f elf64 print.asm && ld print.o -o print && ./print
Hello world
root@kali:~/C scripts/shellcode/Assembly Based Shellcode# objdump -D print.o
print.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <_start>:
0: b8 01 00 00 00 mov $0x1,%eax
5: bf 01 00 00 00 mov $0x1,%edi
a: 48 be 00 00 00 00 00 movabs $0x0,%rsi
11: 00 00 00
14: ba 0c 00 00 00 mov $0xc,%edx
19: 0f 05 syscall
1b: b8 3c 00 00 00 mov $0x3c,%eax
20: 48 31 ff xor %rdi,%rdi
23: 0f 05 syscall
0000000000000025 <message>:
25: 48 rex.W
26: 65 6c gs insb (%dx),%es:(%rdi)
28: 6c insb (%dx),%es:(%rdi)
29: 6f outsl %ds:(%rsi),(%dx)
2a: 20 77 6f and %dh,0x6f(%rdi)
2d: 72 6c jb 9b <message+0x76>
2f: 64 fs
30: 0a .byte 0xa
root@kali:~/C scripts/shellcode/Assembly Based Shellcode#
root@kali:~/C scripts/shell代码/基于程序集的shell代码#cat print.asm
第节.案文
全球启动
_开始:
莫夫·拉克斯,1
mov rdi,1
移动rsi,消息
mov rdx,12
系统调用
莫夫·拉克斯,60岁
异或rdi,rdi
系统调用
信息:
db“你好,世界”,10
root@kali:~/C scripts/shellcode/Assembly-Based外壳代码#nasm-f elf64 print.asm和ld print.o-o print和&./print
你好,世界
root@kali:~/C scripts/shellcode/Assembly-Based外壳代码#objdump-D print.o
print.o:文件格式elf64-x86-64
第节的分解。正文:
0000000000000000 :
0:b8 01 00 mov$0x1,%eax
5:bf 01 00 mov$0x1,%edi
a:48 be 00 movabs$0x0,%rsi
11: 00 00 00
14:ba 0c 00 mov$0xc,%edx
19:0f 05系统调用
1b:b8 3c 00 mov$0x3c,%eax
20:48 31 ff异或%rdi,%rdi
23:0f 05系统调用
0000000000000025 :
25:48雷克斯西
26:65 6c gs insb(%dx),%es:(%rdi)
28:6c insb(%dx),%es:(%rdi)
29:6f输出%ds:(%rsi),(%dx)
2a:2077 6f和%dh,0x6f(%rdi)
2d:72 6c jb 9b
2f:64英尺
30:0a.字节0xa
root@kali:~/C脚本/外壳代码/基于程序集的外壳代码#
我希望外壳代码没有空字节。但事实并非如此。
有人能帮我更正我的代码吗?您似乎对程序集和缓冲区溢出感到困惑 我对程序集文件进行了如下重新编程:
section .text
GLOBAL _start
_start:
xor rax, rax ; Clear the RAX register
push rax ; Push the NULL byte [ string terminator ]
add al, 0x1 ; RAX = 1, to put the system in sys_write mode
mov rdi, rax ; RDI = 1, to setup the fist parameter for write ( file descriptor to write to ). The integral value for 'stdout' is 1.
lea rsi, [rel msg+0x41414141] ; Move the relative RIP address of msg to RSI to prepare the string buffer for writing to the stdout. Also add a large 4-byte offset to evade NULL bytes.
sub rsi, 0x41414141 ; Subtract that large offset to make the RSI point correctly.
xor rdx, rdx ; Empty the 3rd argument for write
mov dl, 0xc ; RDX = 12, 12 ==> string length of msg
syscall ; system call
msg db "Hello world", 0xa
root@kali:~/Desktop/assembly# nasm -f elf64 main.asm; ld main.o -o main.elf; ./main.elf
Hello world
Segmentation fault
编辑:根据评论部分的讨论,我删除了终止的空字节
然后我把程序编译成这样:
section .text
GLOBAL _start
_start:
xor rax, rax ; Clear the RAX register
push rax ; Push the NULL byte [ string terminator ]
add al, 0x1 ; RAX = 1, to put the system in sys_write mode
mov rdi, rax ; RDI = 1, to setup the fist parameter for write ( file descriptor to write to ). The integral value for 'stdout' is 1.
lea rsi, [rel msg+0x41414141] ; Move the relative RIP address of msg to RSI to prepare the string buffer for writing to the stdout. Also add a large 4-byte offset to evade NULL bytes.
sub rsi, 0x41414141 ; Subtract that large offset to make the RSI point correctly.
xor rdx, rdx ; Empty the 3rd argument for write
mov dl, 0xc ; RDX = 12, 12 ==> string length of msg
syscall ; system call
msg db "Hello world", 0xa
root@kali:~/Desktop/assembly# nasm -f elf64 main.asm; ld main.o -o main.elf; ./main.elf
Hello world
Segmentation fault
seg故障实际上并不重要,因为您希望将其用作缓冲区溢出攻击的外壳代码,因此无论如何都存在seg故障
现在,从目标代码中提取字节:
root@kali:~/Desktop/assembly# for i in $(objdump -D main.o | grep "^ " | cut -f2); do echo -n "\x$i"; done; echo
\x48\x31\xc0\x50\x04\x01\x48\x89\xc7\x48\x8d\x35\x4f\x41\x41\x41\x48\x81\xee\x41\x41\x41\x41\x48\x31\xd2\xb2\x0c\x0f\x05\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x0a
[选项]:您可以在内存损坏攻击中执行外壳代码之前测试外壳代码
为此,只需复制上述命令中的字节,并创建一个新的C文件[似乎您对C脚本也感到困惑]
#include <stdio.h>
int main(void) {
char shellcode[] = "\x48\x31\xc0\x50\x04\x01\x48\x89\xc7\x48\x8d\x35\x4f\x41\x41\x41\x48\x81\xee\x41\x41\x41\x41\x48\x31\xd2\xb2\x0c\x0f\x05\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x0a";
int (*ret)() = (int (*)())shellcode;
// The above line will create an integer pointer ret make it point to a function which doesn't require parameter [ indicated by the () ]. Then it will type casting to cast the shellcode to a function pointer of the same type.
// So this will essentially cast your shellcode array address to a function pointer which you can later use to call it as a function and execute the code.
ret(); // Execute the shellcode
}
从上面的代码来看,外壳代码似乎工作得很好
我已经在一个基本的应用程序上尝试过了,它很有效,所以你的问题应该得到解决
需要提及的另一点是,只有当您的可执行应用程序[您将要利用的应用程序]使用停止在空字节(如strcpy()
)上的输入方法时,才需要删除空字节
如果您的可执行文件使用诸如gets()
和fgets()
之类的输入函数,那么您就不必担心空字节[除非您也希望看到格式字符串漏洞]
这来自fgets的手册页:
fgets()从流中最多读入一个小于大小的字符,并将它们存储到s指向的缓冲区中。EOF或换行后,读取停止。如果换行符是
读取时,将其存储到缓冲区中。终止的空字节('\0')存储在缓冲区中最后一个字符之后
这显然意味着空字节不应该干扰您的攻击
我希望你的疑虑得到澄清 使用字节加载并找到其他替代方法以避免零字节。参考指令集参考。例如,
mov-rax,1
可以写成xor-eax,eax;mov al,1
。不幸的是,我找不到该集合引用。如果你做了,请也给我。即使这样也帮了我谢谢你@nltc见。另一个有用的参考是and。请注意,除了修复NUL字节外,还需要使代码位置独立。让我看看我是否能写一个合适的答案。@fuz,请写!你说的职位独立是什么意思?谢谢!您的回答似乎澄清了我的疑问,是的,新的汇编文件工作得非常完美!将此标记为正确答案。push-rax
似乎毫无意义。write
系统调用采用显式长度,而不是以0结尾的字符串。因此,即使执行此操作时RSP指向msg:db…
结尾后的8个字节,也没有必要这样做。还有几个浪费的REX前缀。此外,您可以通过向前跳过字符串来避免子rsi,0x41…
,使rel32
为负,高0xff
字节而不是零。(如果您想避免使用0xff
字节,这是一个很好的技巧。或者我想,对于缓冲区大小错误的FGET,确保换行符位于末尾。)此外,push 1
/pop rax
是一种将寄存器设置为小立即常数的更紧凑的方法@PeterCordes你是对的,代码有点长,也有点不必要。但毕竟,从这个问题来看,用户似乎对汇编不是很有经验,因此我从其他评论中选取了一些要点,以便于用户理解。是的,我在回答的其余部分对有用的评论/文本投了赞成票。但特别是对于一个没有经验的用户来说,引入一个问题中没有的push-rax
只是误导和混淆。在您没有提到的非常特定的情况下,它只会0-0终止msg
,这是不需要的。