> For the complete documentation index, see [llms.txt](https://cajac.gitbook.io/ctf-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cajac.gitbook.io/ctf-notes/bin-exp/tools/checksec.md).

# checksec

**Checksec** is a bash script to check the properties of executables (like PIE, RELRO, Canaries, ASLR, Fortify Source).

## Descriptions

Reference: <https://slimm609.github.io/checksec/checks/binary/>

### RELRO <a href="#relro" id="relro"></a>

**Key:** `relro`

**Protects against:** overwriting the GOT (Global Offset Table) and other runtime relocations to hijack control flow.

**How checksec detects it:** looks for a `PT_GNU_RELRO` segment (Partial) and a `DT_BIND_NOW` / `DF_BIND_NOW` flag in the dynamic section (Full). Any present `DT_BIND_NOW` entry counts as bind-now regardless of its value.

<table><thead><tr><th width="179">Value</th><th width="160">Color</th><th>Meaning</th></tr></thead><tbody><tr><td><code>Full RELRO</code></td><td>green</td><td>GOT is mapped read-only and bound at startup.</td></tr><tr><td><code>Partial RELRO</code></td><td>yellow</td><td>Some sections are read-only, but the GOT is still writable (lazy binding).</td></tr><tr><td><code>No RELRO</code></td><td>red</td><td>No RELRO protection.</td></tr><tr><td><code>N/A</code></td><td><em>italic</em></td><td>Not a dynamically-linked object.</td></tr></tbody></table>

**Enable:**

```
gcc -Wl,-z,relro,-z,now      # Full RELRO
gcc -Wl,-z,relro             # Partial RELRO only
```

### Stack Canary <a href="#stack-canary" id="stack-canary"></a>

**Key:** `canary`

**Protects against:** stack-buffer-overflow attacks that overwrite the saved return address.

**How checksec detects it:** scans the symbol table for the stack-guard symbols `__stack_chk_fail`, `__stack_chk_guard`, or `__intel_security_cookie`.

| Value             | Color | Meaning                                     |
| ----------------- | ----- | ------------------------------------------- |
| `Canary Found`    | green | Stack-protector instrumentation is present. |
| `No Canary Found` | red   | No stack canary.                            |

**Enable:**

```
gcc -fstack-protector-strong   # recommended
gcc -fstack-protector-all      # every function (higher overhead)
```

{% hint style="info" %}
**NOTE**

Stripped binaries can hide the symbol; checksec reports based on the symbols it can see. A binary with no vulnerable buffers may legitimately lack a canary even when the flag was passed.
{% endhint %}

### NX <a href="#nx" id="nx"></a>

**Key:** `nx`

**Protects against:** executing injected code from the stack or heap (W^X for data pages).

**How checksec detects it:** inspects the `PT_GNU_STACK` program header's permission flags.

<table><thead><tr><th width="188">Value</th><th width="150">Color</th><th>Meaning</th></tr></thead><tbody><tr><td><code>NX enabled</code></td><td>green</td><td>Stack is non-executable.</td></tr><tr><td><code>No GNU_STACK</code></td><td>yellow</td><td>No <code>PT_GNU_STACK</code> header — permissions are toolchain/loader-dependent.</td></tr><tr><td><code>NX disabled</code></td><td>red</td><td>Stack is executable (<code>RWX</code>).</td></tr><tr><td><code>N/A</code></td><td><em>italic</em></td><td>Not applicable to this object.</td></tr></tbody></table>

**Enable:** NX is the default. Avoid `-z execstack`; use `-z noexecstack` to be explicit. A `No GNU_STACK` result often means an assembly object didn't declare `.note.GNU-stack`.

### PIE <a href="#pie" id="pie"></a>

**Key:** `pie`

**Protects against:** defeats ASLR bypasses by making the executable itself load-address-independent.

**How checksec detects it:** examines the ELF type (`ET_DYN` vs `ET_EXEC`), the `DF_1_PIE` flag, and the presence of a `PT_INTERP` segment.

<table><thead><tr><th width="197">Value</th><th width="142">Color</th><th>Meaning</th></tr></thead><tbody><tr><td><code>PIE Enabled</code></td><td>green</td><td>Position-independent executable.</td></tr><tr><td><code>Static PIE</code></td><td>green</td><td>Statically linked PIE (no interpreter).</td></tr><tr><td><code>DSO</code></td><td>plain</td><td>A shared library (<code>.so</code>) — PIE doesn't apply the same way.</td></tr><tr><td><code>REL</code></td><td>yellow</td><td>A relocatable object file (<code>.o</code>).</td></tr><tr><td><code>PIE Disabled</code></td><td>red</td><td>Fixed-load-address executable.</td></tr></tbody></table>

**Enable:**

```
gcc -fPIE -pie
```

### RPATH <a href="#rpath" id="rpath"></a>

**Key:** `rpath`

**Protects against:** library-injection / hijacking via unsafe runtime library search paths baked into the binary (`DT_RPATH`).

**How checksec detects it:** reads `DT_RPATH` entries and classifies each path.

<table><thead><tr><th width="256">Value</th><th width="115">Color</th><th>Meaning</th></tr></thead><tbody><tr><td><code>No RPATH</code></td><td>green</td><td>No <code>DT_RPATH</code> set.</td></tr><tr><td><code>RPATH [path]</code></td><td>plain</td><td>Safe absolute path(s).</td></tr><tr><td><code>RPATH [path] ($ORIGIN)</code></td><td>yellow</td><td>Uses <code>$ORIGIN</code> or a nonexistent dir — context-dependent.</td></tr><tr><td><code>RPATH [path] (relative)</code></td><td>red</td><td>Relative, empty (cwd), or world-writable path — insecure.</td></tr></tbody></table>

**Enable / remediate:** prefer no rpath at all. If you must set one, use a trusted absolute path, and prefer `RUNPATH` over `RPATH` (`-Wl,--enable-new-dtags`).

### RUNPATH <a href="#runpath" id="runpath"></a>

**Key:** `runpath`

**Protects against:** the same library-hijacking risk as RPATH, for the newer `DT_RUNPATH` entry (which is searched *after* `LD_LIBRARY_PATH`).

**How checksec detects it:** identical classification to RPATH, applied to `DT_RUNPATH`.

<table><thead><tr><th width="276">Value</th><th width="115">Color</th><th>Meaning</th></tr></thead><tbody><tr><td><code>No RUNPATH</code></td><td>green</td><td>No <code>DT_RUNPATH</code> set.</td></tr><tr><td><code>RUNPATH [path]</code></td><td>plain</td><td>Safe absolute path(s).</td></tr><tr><td><code>RUNPATH [path] ($ORIGIN)</code></td><td>yellow</td><td><code>$ORIGIN</code>/nonexistent — context-dependent.</td></tr><tr><td><code>RUNPATH [path] (relative)</code></td><td>red</td><td>Relative/empty/world-writable — insecure.</td></tr></tbody></table>

**Enable / remediate:** same guidance as RPATH — ideally none, otherwise a trusted absolute path.

### Symbols <a href="#symbols" id="symbols"></a>

**Key:** `symbols`

**Protects against:** information leakage — a fully populated symbol table makes reverse engineering and exploit development easier.

**How checksec detects it:** counts entries in the ELF symbol table.

<table><thead><tr><th width="166">Value</th><th width="126">Color</th><th>Meaning</th></tr></thead><tbody><tr><td><code>No Symbols</code></td><td>green</td><td>Stripped — no symbol table.</td></tr><tr><td><code>N symbols</code></td><td>red</td><td><code>N</code> symbols are present (not stripped).</td></tr></tbody></table>

**Enable (strip):**

```
strip -s ./myapp        # strip an existing binary
gcc -s ...              # strip at link time
```

## Slimm609 version

To check the properties and protections of a binary with `checksec`

```bash
checksec --file=<binary>
```

<details>

<summary>Example run</summary>

```bash
┌──(kali㉿kali)-[/mnt/…/Pwn/Easy_Pwn/El_Mundo/challenge]
└─$ checksec --file=el_mundo                                                         
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      No canary found   NX enabled    No PIE          No RPATH   RW-RUNPATH   51 Symbols        No    0               2               el_mundo

```

</details>

### Usage information

<details>

<summary>checksec --help</summary>

```bash
┌──(kali㉿kali)-[~]
└─$ checksec --help    
Usage: checksec [--format={cli,csv,xml,json}] [OPTION]


Options:

 ## Checksec Options
  --file={file}
  --dir={directory}
  --listfile={text file with one file per line}
  --proc={process name}
  --proc-all
  --proc-libs={process ID}
  --kernel[=kconfig]
  --fortify-file={executable-file}
  --fortify-proc={process ID}
  --version
  --help
  --update or --upgrade

 ## Modifiers
  --debug
  --verbose
  --format={cli,csv,xml,json}
  --output={cli,csv,xml,json}
  --extended

For more information, see:
  http://github.com/slimm609/checksec.sh

```

</details>

## Pwntools version

To check the properties and protections of a binary with `pwntools` [checksec](https://docs.pwntools.com/en/stable/commandline.html#pwn-checksec)

```bash
pwn checksec <binary>
```

<details>

<summary>Example run</summary>

```bash
┌──(kali㉿kali)-[/mnt/…/Pwn/Easy_Pwn/El_Mundo/challenge]
└─$ pwn checksec el_mundo                                 
[*] '/mnt/hgfs/Wargames/Hack_the_Box/HTB_Challenges/Pwn/Easy_Pwn/El_Mundo/challenge/el_mundo'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    RUNPATH:    b'./glibc/'
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

```

</details>

## Resources

Checksec.sh - Docs: <https://slimm609.github.io/checksec/>

Checksec.sh - Github: <https://github.com/slimm609/checksec.sh>

Hardening ELF binaries using Relocation Read-Only (RELRO): <https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro>

High level explanation on some binary executable security: <https://blog.siphos.be/2011/07/high-level-explanation-on-some-binary-executable-security/>

NX bit - Wikipedia: <https://en.wikipedia.org/wiki/NX_bit>

Position-independent code - Wikipedia: <https://en.wikipedia.org/wiki/Position-independent_code>

rpath - Wikipedia: <https://en.wikipedia.org/wiki/Rpath>

rpath and runpath - Shared Libraries: <https://amirrachum.com/shared-libraries/#rpath-and-runpath>

Symbol (programming) - Wikipedia: <https://en.wikipedia.org/wiki/Symbol_(programming)>
