Skip to main content
This guide covers advanced setup options for working with specific glibc versions, essential for testing techniques against different library implementations.

Prerequisites

1

Install Build Tools

Install required packages and tools:
sudo apt update
sudo apt install build-essential patchelf zstd wget git python3
2

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
3

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
This method tells the linker to link target binaries with the target libc and includes debug symbols.
1

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
2

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.
3

Debug with GDB

Debug with full symbol support:
gdb ./glibc_2.39/fastbin_dup

Building Specific 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.
1

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
2

Build Base Binaries

First, build the base binaries:
make base
3

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 <version> <target> [options]

Options

OptionDescription
-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 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:
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:
make test version=2.39
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

Binary Segfaults Immediately

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 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

Build docs developers (and LLMs) love