Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
libheif-grid-nextjs-rce — Private Fortbridge PoC for the CVE-2026-32740 Next.js/sharp leak-to-memcpy-GOT RCE chain | Kitploit
Tools/GitHubGitHub/fortbridge-uk/libheif-grid-nextjs-rce
Memory ForensicsVulnerability AnalysisExploitationReverse EngineeringWeb Application ExploitationPenetration TestingPayload DevelopmentBinary Exploitation

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
Labs & Practice
GitHubfortbridge-uk/libheif-grid-nextjs-rce

libheif-grid-nextjs-rce

Private Fortbridge PoC for the CVE-2026-32740 Next.js/sharp leak-to-memcpy-GOT RCE chain

View Repository
13 days agoNot yet reviewed

libheif grid-to-GOT Next.js RCE

Working proof of concept that turns CVE-2026-32740 in the hardcoded Next.js/sharp image stack into a chosen-address write and a validated /usr/bin/id callback.

This is a private Fortbridge research repository. Use it only against the included lab or another system you are explicitly authorised to test.

What the PoC proves

The exploit uses only the target's HTTP upload and image-optimization routes:

  1. It repeatedly submits an ASLR-leak AVIF and compares pointers in the returned pixels with every exact libvips profile in the manifest.
  2. It proceeds only when one profile and one randomized libvips base are supported by all required independent anchors.
  3. It resolves the two-byte fake-node selector using the selected profile. The stock profile requires a complete marked heap record. Each PIE profile uses its independently measured allocator page-lane relationship.
  4. It uses libvips' internal copy of GLib's g_module_open_full, a GModule routine that wraps dlopen to load a native shared library from a file path. The exploit calculates its runtime address as the recovered libvips base plus the hardcoded profile offset 0x3e995e. Loading the library runs its constructor.
  5. On the attacker machine, it compiles a small shared object whose constructor runs the fixed command /usr/bin/id. It sends that ELF through the public upload route under the image name x.jpg and media type image/jpeg.
  6. It generates a 116x33 four-tile AVIF whose Cb overflow redirects the Cr plane to memcpy@GOT - 16.
  7. The first chosen-address row stores uploads/x.jpg immediately before the GOT slot and replaces memcpy@GOT with the derived GModule loader. The next row calls that loader with the library path already in RDI.
  8. Loading the shared object invokes its constructor, which returns the /usr/bin/id output over TCP. A per-attempt token prevents a stale callback from being counted as success; the returned uid=... line is the proof.

The original libvips-relative validation runs are recorded in evidence/libvips-gmodule-rce-10x.json. All ten fresh processes returned valid /usr/bin/id output with ten distinct randomized libvips bases and ten independently derived loader addresses.

The exact Ubuntu run data are in evidence/libvips-gmodule-pie-rce-10x.json. The exact Debian 13 APT run data are in evidence/debian13-apt-libvips-gmodule-rce-10x.json.

Measured results

We tested the complete exploit against 10 newly started Ubuntu Node processes and 10 newly started Debian Node processes. All 20 runs reached command execution and returned the target's /usr/bin/id output. The exploit also calculated a different GModule-loader address for every randomized libvips base.

Before creating the final payload, the exploit may need several ASLR-leak attempts. Each attempt uploads the leak AVIF, sends it through the optimisation route, and checks the returned PNG for four pointers that identify one profile and one libvips base. Ubuntu needed between 3 and 23 attempts. Debian needed between 3 and 15. Incomplete or ambiguous evidence causes another attempt instead of a guessed profile.

The project also has 96 automated regression tests. These are code-level checks, not 96 additional exploit runs. They cover profile validation, returned-pointer classification, heap calibration, address calculation, payload construction, and safe failure when evidence does not match a supported target.

Tested stacks

Both x86-64 targets use Next.js 15.5.23, sharp 0.34.4, bundled libvips 8.17.2, bundled libheif 1.20.2, ASLR, and NX. Their native runtimes differ:

ProfileNodeglibclibstdc++Selector relation
Ubuntu25.8.1, PIE ET_DYN2.43-2ubuntu2.46.0.350x6000 - 0x690 = 0x5970
Debian 13Debian APT 20.19.2, PIE ET_DYN2.41-12+deb13u46.0.330x6000 - 0x3a0 = 0x5c60

The complete build IDs and SHA-256 values are in profiles/native_stack_profiles_pie.json. The Debian package, artifact, route-smoke, and five-lifetime layout measurements are captured in evidence/debian13-profile-derivation.json. The Debian target uses the standard distribution package nodejs=20.19.2+dfsg-1+deb13u3; Node is not compiled from source.

Hardcoded profile values

The chain does not need the randomized Node base. Its control target is the internal g_module_open_full routine inside libvips, whose randomized base is recovered from returned pixels. Each versioned profile hardcodes the build-specific constants required by the exploit:

  • returned-pointer offsets used to recover the libvips base and select a compatible native-stack profile;
  • the memcpy@GOT offset and the g_module_open_full offset plus its validating instruction bytes;
  • allocator page-lane and page-to-fake-node relationships;
  • object-layout offsets, tile geometry, row width, and application paths.

The randomized libvips base, the resulting runtime loader address, and the final two-byte selector are not hardcoded. They are derived for each target process from returned pixels and the selected profile.

The exploit fails closed when a profile is malformed or returned pixels do not select exactly one supported profile/base pair. The stock profile also requires its complete returned heap record. A profile is an exact compatibility claim, so the operator should verify the target artifacts offline before using it.

The loader ABI is important. The overwritten call supplies the library path in RDI, an image-row pointer in RSI, and the 58-byte copy length in RDX. This exact profiled GModule routine uses only supported flag bits from ESI and does not dereference RDX on the successful load path. An offline harness validated that entry point and instruction signature before it was used in the measured runs.

Requirements

  • Linux x86-64
  • Python 3.11 or later
  • ffmpeg with the libaom-av1 encoder
  • a C compiler available as cc on the attacker machine
  • an IPv4 callback address reachable from the target
  • Node.js and npm to run the lab directly, or Docker for either target

Install the only Python dependency:

python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -r requirements.txt

Confirm AV1 encoding support:

ffmpeg -hide_banner -encoders | grep libaom-av1

Start the included lab

The lab intentionally accepts arbitrary uploads and passes selected files to sharp. Do not expose it to an untrusted network.

cd lab
npm ci
npm run build
npm run start

The target is then available at http://127.0.0.1:3000.

To build an Ubuntu lab image around the Node artifact used by the first PIE profile:

./scripts/build_ubuntu2604_container.sh
docker run --rm --network host \
  fortbridge/libheif-grid-nextjs-rce:ubuntu2604

The digest-locked Ubuntu 26.04 image builds the exact Node 25.8.1 PIE artifact recorded in the profile, verifies its SHA-256, then copies it into a clean runtime stage. The source build is required because Node's official Linux binary is ET_EXEC, while this profile intentionally tests a PIE executable.

To reproduce the Debian target with Debian's supported APT package:

./scripts/build_debian13_container.sh
docker run --rm --network host \
  fortbridge/libheif-grid-nextjs-rce:debian13
Download Tool