This guide covers advanced setup options for working with specific glibc versions, essential for testing techniques against different library implementations.
Prerequisites
Install Build Tools
Install required packages and tools: sudo apt update
sudo apt install build-essential patchelf zstd wget git python3
Ensure Python Symlink
The build system requires /usr/bin/python to exist: # Check if it exists
ls -la /usr/bin/python
# If not, create symlink to python3
sudo ln -s /usr/bin/python3 /usr/bin/python
Clone Repository
Clone the how2heap repository: git clone https://github.com/shellphish/how2heap
cd how2heap
Setup Methods
You can choose between two methods depending on your needs:
Method 1: Link Against Older libc Links binaries directly to specific glibc versions with debug symbols
Method 2: Docker Environment Compiles in Ubuntu containers matching the target glibc version
Why Specific Glibc Versions?
You’ll encounter symbol versioning issues if you try to LD_PRELOAD different libcs to a binary compiled on your host machine. These methods bypass that limitation.
Heap exploitation techniques are version-specific because:
Glibc constantly adds security checks
Techniques may work on older versions but fail on newer ones
Some attacks require precise knowledge of internal structures
Method 1: Link Against Older libc
This method tells the linker to link target binaries with the target libc and includes debug symbols.
Build for Specific Version
Build all techniques for a specific glibc version: H2H_USE_SYSTEM_LIBC = N make v2.39
Available versions: 2.23, 2.24, 2.27, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, 2.37, 2.38, 2.39, 2.40, 2.41
Run the Binaries
Execute the compiled binaries directly: ./glibc_2.39/fastbin_dup
./glibc_2.39/tcache_poisoning
The binaries are already linked with the correct libc and include debug symbols.
Debug with GDB
Debug with full symbol support: gdb ./glibc_2.39/fastbin_dup
Building Specific Techniques
Single Version
Multiple Versions
All Techniques
# Build all glibc 2.39 techniques
H2H_USE_SYSTEM_LIBC = N make v2.39
The first build downloads the corresponding libc from glibc-all-in-one . Subsequent builds for the same version are faster.
Method 2: Docker Environment
This method uses Docker to compile binaries inside an Ubuntu container that matches the target libc version.
Install Docker
Make sure Docker is installed and you have access: docker --version
# Add your user to docker group if needed
sudo usermod -aG docker $USER
newgrp docker
Build Base Binaries
First, build the base binaries:
Prepare with glibc_run.sh
Use the glibc_run.sh script to set up and run binaries: # The -d flag builds the docker environment
./glibc_run.sh 2.39 ./malloc_playground -d
This script:
Downloads the target libc if needed
Patches the binary’s interpreter and RUNPATH
Optionally builds a Docker environment
Runs the binary with the correct libc
Using glibc_run.sh
The glibc_run.sh script is a powerful wrapper that handles libc version management.
Basic Usage
./glibc_run.sh < versio n > < targe t > [options]
Options
Option Description -dBuild the debugging environment in Docker -gdbStart target in GDB -r2Start target in radare2 -pJust set interpreter and rpath without execution -uUpdate libc list in glibc-all-in-one -rDownload libc in glibc-all-in-one -i686Use 32-bit libc instead of 64-bit
Examples
Run with Specific Version
Debug with GDB
Docker Environment
Prepare Binary Only
# Run malloc_playground with glibc 2.35
./glibc_run.sh 2.35 ./malloc_playground
How It Works
The script uses patchelf to modify the binary:
# Check the interpreter
readelf -l ./malloc_playground | grep interpreter
# Check the RUNPATH
readelf -d -W ./malloc_playground | grep RUNPATH
After running glibc_run.sh, the binary is patched to use:
Interpreter : The ld-linux loader from the target glibc version
RUNPATH : Path to the downloaded glibc libraries
The script only patches the binary if the system glibc version differs from the target version.
Environment Configuration
Directory Structure
After setup, your directory will look like:
how2heap/
├── glibc_2.23/ # Techniques for glibc 2.23
├── glibc_2.39/ # Techniques for glibc 2.39
├── glibc_2.41/ # Techniques for glibc 2.41
├── glibc-all-in-one/ # Submodule for downloading libcs
│ ├── libs/ # Downloaded glibc versions
│ └── debs/ # Cached .deb packages
├── glibc_versions/ # Prepared glibc versions
│ └── 2.39/
│ └── x64/
│ └── lib/ # libc, ld-linux, debug symbols
├── malloc_playground # Interactive heap tool
└── glibc_run.sh # Version management script
Verifying Setup
Check that binaries are correctly linked:
Check Interpreter
Check RUNPATH
Verify Linked Libc
readelf -l ./glibc_2.39/fastbin_dup | grep interpreter
# Should show: glibc_versions/2.39/.../ld-linux-x86-64.so.2
Testing Techniques
Run automated tests for all techniques in a specific version:
This runs each technique 20 times to account for ASLR and race conditions.
Troubleshooting
Symbol Versioning Errors
Problem : Error like version GLIBC_2.34 not foundSolution : Use Method 1 (link against older libc) instead of trying to LD_PRELOAD different versions.
Missing Dependencies
# zstd is required for decompressing glibc packages
sudo apt install zstd
# patchelf is required for binary patching
sudo apt install patchelf
Docker Permission Denied
# Add user to docker group
sudo usermod -aG docker $USER
# Apply group changes
newgrp docker
# Or run with sudo (not recommended)
sudo ./glibc_run.sh 2.39 ./malloc_playground -d
Failed to Download Libc
# Update the glibc list
cd glibc-all-in-one
./update_list
cd ..
# Or use glibc_run.sh with -u flag
./glibc_run.sh 2.39 ./malloc_playground -u -r
Check that you’re using compatible architectures:
# Verify binary architecture
file ./malloc_playground
# Should show: ELF 64-bit LSB executable, x86-64
# For 32-bit binaries, use -i686 flag
./glibc_run.sh 2.39 ./malloc_playground -i686
GDB Can’t Find Debug Symbols
# Use glibc_run.sh with -gdb flag (handles debug symbols automatically)
./glibc_run.sh 2.39 ./glibc_2.39/fastbin_dup -gdb
# Or manually specify debug directory
gdb ./glibc_2.39/fastbin_dup \
-iex "set debug-file-directory glibc_versions/2.39/x64/lib/.debug"
Cleaning Up
Remove Binaries
Full Clean
# Remove all compiled binaries
make clean
make distclean will remove all downloaded glibc versions. You’ll need to re-download them on the next build.
Advanced Configuration
Building for Specific Architecture
By default, how2heap builds for x86-64. For 32-bit:
# Using Makefile
ARCH = i386 H2H_USE_SYSTEM_LIBC = N make v2.39
# Using glibc_run.sh
./glibc_run.sh 2.39 ./malloc_playground -i686
Custom Compiler Flags
Modify Makefile to add custom flags:
CFLAGS += -std=c99 -g -Wno-unused-result -Wno-free-nonheap-object
# Add your custom flags here
CFLAGS += -O0 -fno-stack-protector
Using with CTF Challenges
To test your exploit against a specific libc version:
# Patch your exploit binary
./glibc_run.sh 2.35 ./my_exploit -p
# Now run with the correct libc
./my_exploit
# Or debug it
./glibc_run.sh 2.35 ./my_exploit -gdb
Next Steps
Start Learning Begin with the quickstart guide and try your first technique
Debugging Tools Install pwndbg, gef, or Pwngdb for advanced heap visualization