Skip to content

Commit 25fbc1e

Browse files
committed
feat: add neovim, ImHex, upx, unblob, p7zip; fix X11 and GDB support
- Add neovim, ImHex, upx, p7zip-full, unblob to the image - Fix X11 GUI: add xcb/GL/EGL libs, switch to openjdk-21-jdk (non-headless) - Add CTF_UID/CTF_GID build args (default 1000) for X11 socket permissions - Remove default ubuntu user to free UID 1000 for ctf user - Add --cap-add=SYS_PTRACE to all docker run examples for GDB - Optimize Dockerfile: BuildKit cache mounts, merge layers, fewer RUN steps - Update README.md and CLAUDE.md with new tools and usage instructions
1 parent c173868 commit 25fbc1e

3 files changed

Lines changed: 77 additions & 46 deletions

File tree

CLAUDE.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
A Docker image for CTF pwn/reverse-engineering. Single Dockerfile (Ubuntu 24.04) with 40+ pre-installed tools, a non-root `ctf` user, and GDB plugin switching.
7+
A Docker image for CTF pwn/reverse-engineering. Single Dockerfile (Ubuntu 24.04) with 45+ pre-installed tools, a non-root `ctf` user (UID configurable via build args), and GDB plugin switching.
88

99
## Build & Run
1010

1111
```bash
1212
# Build
1313
docker build -t pwndocker-reverse .
1414

15-
# Run interactively
16-
docker run -it --rm -v $(pwd):/ctf pwndocker-reverse
15+
# Build with custom UID/GID (if host UID is not 1000)
16+
docker build --build-arg CTF_UID=$(id -u) --build-arg CTF_GID=$(id -g) -t pwndocker-reverse .
1717

18-
# Run with X11 (for Ghidra, Cutter, IDA, Binary Ninja, jd-gui)
19-
docker run -it --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -v $(pwd):/ctf pwndocker-reverse
18+
# Run interactively (--cap-add=SYS_PTRACE needed for GDB)
19+
docker run -it --rm --cap-add=SYS_PTRACE -v $(pwd):/ctf pwndocker-reverse
20+
21+
# Run with X11 (for Ghidra, Cutter, IDA, Binary Ninja, jd-gui, ImHex)
22+
docker run -it --rm --cap-add=SYS_PTRACE -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -v $(pwd):/ctf pwndocker-reverse
2023
```
2124

2225
## Architecture
@@ -25,15 +28,15 @@ Single `Dockerfile` with 13 logical layers, organized by purpose:
2528

2629
| Layer | Contents |
2730
|---|---|
28-
| 1. Base | Ubuntu 24.04, system deps, multilib, X11, JDK 21, QEMU user-mode, wabt |
29-
| 2-4. Python | pwntools, angr, qiling, ropper, ROPgadget, binary-refinery, frida-tools (pipx). Libraries (capstone, keystone, unicorn, z3, yara, r2pipe) injected into pwntools venv |
31+
| 1. Base | Ubuntu 24.04, system deps, multilib, X11/GL, JDK 21, QEMU user-mode, wabt, neovim, upx, p7zip |
32+
| 2-4. Python | pwntools, angr, qiling, ropper, ROPgadget, binary-refinery, frida-tools, unblob (pipx). Libraries (capstone, keystone, unicorn, z3, yara, r2pipe) injected into pwntools venv |
3033
| 5. Pip/Manual | binwalk, hash-identifier, opengrep |
3134
| 6. Ruby | one_gadget, seccomp-tools |
3235
| 7. GDB | pwndbg, GEF, PEDA + switcher (`gdb-pwndbg`, `gdb-gef`, `gdb-peda`, `gdb-switch`) |
33-
| 8. RE | radare2, rizin, Cutter, Ghidra, retdec, IDA Free, Binary Ninja Free, pycdc, jd-gui |
36+
| 8. RE | radare2, rizin, Cutter, Ghidra, retdec, IDA Free, Binary Ninja Free, ImHex, pycdc, jd-gui |
3437
| 9. Fuzzing | AFL++, villoc |
3538
| 10. Workflow | libc-database (`libc-find`, `libc-identify`, `libc-dump`), pwninit |
36-
| 11-13. User | `ctf` user with sudo, oh-my-zsh, pre-populated history, helper scripts, MOTD |
39+
| 11-13. User | `ctf` user (UID/GID configurable via `CTF_UID`/`CTF_GID` build args, default 1000) with sudo, oh-my-zsh, pre-populated history, helper scripts, MOTD |
3740

3841
## File Structure
3942

@@ -54,3 +57,6 @@ Single `Dockerfile` with 13 logical layers, organized by purpose:
5457
- **Ghidra zip is platform-independent** — no "linux" in the asset name, jq filter uses `endswith(".zip")` + `test("PUBLIC")`
5558
- **decomp2dbg deferred** — requires interactive `--install` step; noted in MOTD for manual setup
5659
- **libc-database replaces Docker-in-Docker multi-glibc** — the original approach was broken by design
60+
- **`CTF_UID`/`CTF_GID` build args** — default 1000 to match most Linux hosts; avoids X11 socket permission issues
61+
- **`openjdk-21-jdk` (not headless)** — Ghidra needs AWT/Swing for its GUI
62+
- **`--cap-add=SYS_PTRACE`** — required at runtime for GDB to attach to processes

Dockerfile

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# syntax=docker/dockerfile:1
12
FROM ubuntu:24.04
23
LABEL maintainer="you@example.com"
34

@@ -8,38 +9,47 @@ ENV DEBIAN_FRONTEND=noninteractive \
89
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
910

1011
# Layer 1: System packages
11-
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
13+
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
14+
apt-get update && apt-get install -y --no-install-recommends \
1215
build-essential cmake nasm gcc-multilib g++-multilib meson ninja-build liblzma-dev elfutils \
1316
wabt \
1417
libc6-i386 libc6-dev-i386 \
1518
gdb-multiarch patchelf strace ltrace \
1619
xxd binutils file less hexedit \
1720
curl wget socat netcat-openbsd nmap tcpdump tshark lsof \
18-
git unzip jq tmux zsh vim sudo procps bsdmainutils libfuse2 zstd \
19-
x11-apps libx11-dev libgl1 libegl-mesa0 libglx-mesa0 libosmesa6 \
20-
openjdk-21-jdk-headless \
21+
git unzip p7zip-full jq tmux zsh vim neovim sudo procps bsdmainutils libfuse2 zstd upx \
22+
x11-apps libx11-dev libgl1 libegl1 libegl-mesa0 libglx-mesa0 libosmesa6 libopengl0 \
23+
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 \
24+
libxcb-render0 libxcb-shape0 libxcb-xinerama0 libxcb-xkb1 \
25+
libxkbcommon-x11-0 libxkbcommon0 \
26+
openjdk-21-jdk \
2127
qemu-user qemu-user-static \
2228
llvm llvm-dev clang lld \
2329
python3 python3-dev python3-pip python3-venv pipx \
24-
ruby-dev \
25-
&& rm -rf /var/lib/apt/lists/*
30+
ruby-dev
2631

27-
# Layer 2: Python pwn tools (pipx)
28-
RUN pipx install pwntools
29-
RUN pipx install ropper
30-
RUN pipx install ropgadget
31-
RUN pipx install angr
32-
RUN pipx install qiling
32+
# Layer 2: Python pwn tools (pipx) — merged into fewer layers
33+
RUN --mount=type=cache,target=/root/.cache/pip \
34+
pipx install pwntools \
35+
&& pipx install ropper \
36+
&& pipx install ropgadget \
37+
&& pipx install angr \
38+
&& pipx install qiling
3339

3440
# Layer 3: Python libraries (injected into pwntools venv)
35-
RUN pipx inject pwntools capstone keystone-engine unicorn z3-solver yara-python r2pipe
41+
RUN --mount=type=cache,target=/root/.cache/pip \
42+
pipx inject pwntools capstone keystone-engine unicorn z3-solver yara-python r2pipe
3643

3744
# Layer 4: Python CLI tools (pipx)
38-
RUN pipx install binary-refinery
39-
RUN pipx install frida-tools
45+
RUN --mount=type=cache,target=/root/.cache/pip \
46+
pipx install binary-refinery \
47+
&& pipx install frida-tools \
48+
&& pipx install unblob
4049

4150
# Layer 5: Python tools (pip/manual)
42-
RUN pip install --break-system-packages binwalk
51+
RUN --mount=type=cache,target=/root/.cache/pip \
52+
pip install --break-system-packages binwalk
4353

4454
RUN git clone --depth=1 https://github.com/blackploit/hash-identifier /opt/hash-identifier \
4555
&& ln -s /opt/hash-identifier/hash-id.py /usr/local/bin/hash-identifier \
@@ -57,9 +67,8 @@ RUN gem install one_gadget seccomp-tools
5767
RUN git clone --depth=1 https://github.com/pwndbg/pwndbg /opt/pwndbg \
5868
&& cd /opt/pwndbg && ./setup.sh
5969

60-
RUN git clone --depth=1 https://github.com/hugsy/gef /opt/gef
61-
62-
RUN git clone --depth=1 https://github.com/longld/peda /opt/peda
70+
RUN git clone --depth=1 https://github.com/hugsy/gef /opt/gef \
71+
&& git clone --depth=1 https://github.com/longld/peda /opt/peda
6372

6473
# GDB switcher and wrapper scripts
6574
COPY config/gdb-pwndbg config/gdb-gef config/gdb-peda config/gdb-switch /usr/local/bin/
@@ -116,6 +125,15 @@ RUN wget -qO /tmp/binaryninja_free.zip "https://cdn.binary.ninja/installers/bina
116125
&& ln -s /opt/binaryninja/binaryninja /usr/local/bin/binaryninja \
117126
&& rm /tmp/binaryninja_free.zip
118127

128+
# ImHex (hex editor for RE)
129+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
130+
--mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
131+
curl -s https://api.github.com/repos/WerWolv/ImHex/releases/latest \
132+
| jq -r '.assets[] | select(.name | test("Ubuntu.*24\\.04.*\\.deb$")) | .browser_download_url' \
133+
| head -1 | xargs wget -qO /tmp/imhex.deb \
134+
&& apt-get update && apt-get install -y --no-install-recommends /tmp/imhex.deb \
135+
&& rm /tmp/imhex.deb
136+
119137
# pycdc (Python bytecode decompiler)
120138
RUN git clone --depth=1 https://github.com/zrax/pycdc /tmp/pycdc \
121139
&& mkdir /tmp/pycdc/build && cd /tmp/pycdc/build \
@@ -124,11 +142,11 @@ RUN git clone --depth=1 https://github.com/zrax/pycdc /tmp/pycdc \
124142
&& rm -rf /tmp/pycdc
125143

126144
# jd-gui (Java decompiler)
145+
COPY config/jd-gui /usr/local/bin/jd-gui
127146
RUN mkdir -p /opt/jd-gui \
128147
&& wget -qO /opt/jd-gui/jd-gui.jar \
129-
"https://github.com/java-decompiler/jd-gui/releases/download/v1.6.6/jd-gui-1.6.6.jar"
130-
COPY config/jd-gui /usr/local/bin/jd-gui
131-
RUN chmod +x /usr/local/bin/jd-gui
148+
"https://github.com/java-decompiler/jd-gui/releases/download/v1.6.6/jd-gui-1.6.6.jar" \
149+
&& chmod +x /usr/local/bin/jd-gui
132150

133151
# Layer 9: Fuzzing & Dynamic Analysis
134152

@@ -156,20 +174,22 @@ RUN curl -s https://api.github.com/repos/io12/pwninit/releases/latest \
156174
&& chmod +x /usr/local/bin/pwninit
157175

158176
# Layer 11: User Setup & Shell
159-
RUN useradd -m -s /bin/zsh -G sudo ctf \
177+
ARG CTF_UID=1000
178+
ARG CTF_GID=1000
179+
RUN userdel -r ubuntu 2>/dev/null; groupdel ubuntu 2>/dev/null; true \
180+
&& groupadd -f -g ${CTF_GID} ctf \
181+
&& useradd -m -s /bin/zsh -u ${CTF_UID} -g ${CTF_GID} -G sudo ctf \
160182
&& echo "ctf ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
161183
&& mkdir -p /ctf && chown ctf:ctf /ctf
162184

163185
# MOTD with post-build notes
164186
RUN echo '\n=== pwndocker-reverse ===\nNote: Run "decomp2dbg --install" for Ghidra/Cutter GDB integration.\nUse "gdb-switch {pwndbg|gef|peda}" to change default GDB plugin.\n' > /etc/motd
165187

166-
# Layer 12: Pre-populated command history
188+
# Layer 12: Config files and helper scripts
167189
COPY config/zsh_history /home/ctf/.zsh_history
168-
RUN chown ctf:ctf /home/ctf/.zsh_history
169-
170-
# Layer 13: Helper scripts
171190
COPY config/start-cutter.sh config/start-ghidra.sh /usr/local/bin/
172-
RUN chmod +x /usr/local/bin/start-cutter.sh /usr/local/bin/start-ghidra.sh
191+
RUN chown ctf:ctf /home/ctf/.zsh_history \
192+
&& chmod +x /usr/local/bin/start-cutter.sh /usr/local/bin/start-ghidra.sh
173193

174194
USER ctf
175195

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,33 @@
44
[![Docker](https://img.shields.io/badge/docker-ubuntu%2024.04-blue?logo=docker)](https://ghcr.io/gl0bal01/pwndocker-reverse)
55
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/gl0bal01/pwndocker-reverse/blob/master/LICENSE)
66

7-
A single Dockerfile that bundles 40+ CTF pwn and reverse-engineering tools into one Ubuntu 24.04 image. Includes 7 disassemblers and decompilers (Ghidra, IDA Free, Binary Ninja Free, Cutter, radare2, rizin, retdec), 3 GDB plugins with instant switching, and a pre-populated command history.
7+
A single Dockerfile that bundles 45+ CTF pwn and reverse-engineering tools into one Ubuntu 24.04 image. Includes 7 disassemblers and decompilers (Ghidra, IDA Free, Binary Ninja Free, Cutter, radare2, rizin, retdec), 3 GDB plugins with instant switching, and a pre-populated command history.
88

99
IDA Free and Binary Ninja Free are installed from their vendors' free-tier downloads. Users are responsible for compliance with each vendor's license terms.
1010

1111
## Why?
1212

13-
Given Docker on the host, this image packages 40+ tools that would otherwise require separate installation steps -- Python packages, Java-based disassemblers, GDB plugins, and Ruby gems -- into a single Dockerfile.
13+
Given Docker on the host, this image packages 45+ tools that would otherwise require separate installation steps -- Python packages, Java-based disassemblers, GDB plugins, and Ruby gems -- into a single Dockerfile.
1414

1515
## Quick Start
1616

1717
```bash
1818
# Pull from GHCR (fastest)
1919
docker pull ghcr.io/gl0bal01/pwndocker-reverse:latest
20-
docker run -it --rm -v $(pwd):/ctf ghcr.io/gl0bal01/pwndocker-reverse
20+
docker run -it --rm --cap-add=SYS_PTRACE -v $(pwd):/ctf ghcr.io/gl0bal01/pwndocker-reverse
2121

2222
# Or build locally
2323
docker build -t pwndocker-reverse .
24-
docker run -it --rm -v $(pwd):/ctf pwndocker-reverse
24+
docker run -it --rm --cap-add=SYS_PTRACE -v $(pwd):/ctf pwndocker-reverse
2525

2626
# With X11 forwarding (requires X11 server on host -- see GUI tools section)
27-
docker run -it --rm \
27+
docker run -it --rm --cap-add=SYS_PTRACE \
2828
-e DISPLAY=$DISPLAY \
2929
-v /tmp/.X11-unix:/tmp/.X11-unix \
3030
-v $(pwd):/ctf pwndocker-reverse
31+
32+
# Custom UID/GID (if your host UID is not 1000)
33+
docker build --build-arg CTF_UID=$(id -u) --build-arg CTF_GID=$(id -g) -t pwndocker-reverse .
3134
```
3235

3336
You land in `/ctf` as user `ctf` with sudo, oh-my-zsh, and 97 pre-loaded history entries searchable via Ctrl+R.
@@ -40,20 +43,22 @@ You land in `/ctf` as user `ctf` with sudo, oh-my-zsh, and 97 pre-loaded history
4043
| **Libraries** | capstone, keystone, unicorn, z3, yara, r2pipe *(in pwntools venv)* |
4144
| **Disassemblers / Decompilers** | Ghidra, IDA Free, Binary Ninja Free, Cutter (rizin), retdec, radare2, rizin, pycdc, jd-gui |
4245
| **GDB** | pwndbg, GEF, PEDA + switcher scripts |
46+
| **Hex Editors** | ImHex, hexedit |
4347
| **Fuzzing** | AFL++ |
4448
| **Dynamic** | frida, strace, ltrace, villoc |
45-
| **Workflow** | libc-database, pwninit, patchelf, binwalk |
49+
| **Workflow** | libc-database, pwninit, patchelf, binwalk, unblob, upx |
4650
| **Analysis** | binary-refinery, opengrep, hash-identifier |
4751
| **Networking** | socat, ncat, tcpdump, tshark, nmap |
48-
| **System** | QEMU user-mode, wabt, hexedit, gdb-multiarch, oh-my-zsh |
52+
| **Editors** | vim, neovim |
53+
| **System** | QEMU user-mode, wabt, gdb-multiarch, p7zip, oh-my-zsh |
4954

5055
## Usage
5156

5257
### Typical CTF workflow
5358

5459
```bash
5560
# Start the container with your challenge directory mounted
56-
docker run -it --rm -v $(pwd):/ctf pwndocker-reverse
61+
docker run -it --rm --cap-add=SYS_PTRACE -v $(pwd):/ctf pwndocker-reverse
5762

5863
# Analyze the binary
5964
checksec --file=./challenge
@@ -90,7 +95,7 @@ gdb-switch pwndbg # set default for plain `gdb`
9095
Requires X11 forwarding. On Linux this works natively; on macOS install [XQuartz](https://www.xquartz.org/), on Windows install [VcXsrv](https://sourceforge.net/projects/vcxsrv/) or use WSLg.
9196

9297
```bash
93-
docker run -it --rm \
98+
docker run -it --rm --cap-add=SYS_PTRACE \
9499
-e DISPLAY=$DISPLAY \
95100
-v /tmp/.X11-unix:/tmp/.X11-unix \
96101
-v $(pwd):/ctf pwndocker-reverse

0 commit comments

Comments
 (0)