This commit is contained in:
taqin
2026-04-19 21:10:40 +07:00
parent 5fdd214fdc
commit 27381d4e37
211 changed files with 53571 additions and 0 deletions

174
vuln-lab/README.md Normal file
View File

@@ -0,0 +1,174 @@
# insecure.newploit.com — PocketPentester Vuln Lab
Deliberately vulnerable PHP target for shaking down every arsenal module in
PocketPentester. Runs as a local docker-compose stack.
> [!WARNING]
> Do NOT expose this to the public internet. It has intentional RCE, SQLi,
> LFI, SSRF, open redirect, CORS misconfig, weak JWT, leaked secrets and
> more. Keep it on a private bridge network only.
---
## Quick start
```bash
cd vuln-lab
docker compose up --build -d
```
Add the hostname to your hosts file so the `insecure.newploit.com` SNI /
Host header works:
**Linux / macOS**`/etc/hosts`
```
127.0.0.1 insecure.newploit.com
```
**Windows**`C:\Windows\System32\drivers\etc\hosts`
```
127.0.0.1 insecure.newploit.com
```
**Android (testing from PocketPentester on device)** — set your phone's
Wi-Fi DNS to the dev machine, or just use the host's LAN IP directly:
```
http://192.168.x.x/ (or whatever your dev box IP is)
```
Smoke-test from the host:
```bash
curl http://insecure.newploit.com/
curl http://insecure.newploit.com/.env
curl "http://insecure.newploit.com/search.php?q=<svg/onload=alert(1)>"
```
---
## Open ports
| Port | Service | Notes |
|--------|-------------------|--------------------------------------------|
| 80 | Apache 2.4 + PHP | main web app |
| 443 | Apache TLS | snakeoil cert for ssl_scan |
| 3306 | MariaDB 10.11 | root:toor, also dbuser:dbpass123 |
| 21 | vsftpd | anonymous:anonymous |
---
## Module → endpoint map
Everything below is already wired. Point the tool at `insecure.newploit.com`
(or `http://<host>`) and it should fire.
### RECON
| Arsenal module | Where it hits |
|------------------|------------------------------------------------------------------|
| `port_scan` | 21 / 80 / 443 / 3306 open |
| `httpx` | Title `Newploit :: insecure test lab`, Server `Apache/2.4.57 …` |
| `banner` | Apache + MySQL banners expose full version |
| `ssl_scan` | Self-signed CN=insecure.newploit.com on :443 |
| `dns_tools` | (local hosts entry) |
### EXPLOIT
| Arsenal module | Endpoint(s) that fire |
|------------------|------------------------------------------------------------------|
| `sqli` | `/search.php?q=…`, `/profile.php?id=…`, `/login.php` POST |
| `xss` | `/search.php?q=<payload>` (reflected, unescaped) |
| `jwt` | `/api/auth.php``alg:none` accepted, HS256 secret = `secret` |
| `xploiter` | see template-by-template table below |
| `autopwn` | runs the whole chain on `http://insecure.newploit.com/` |
### MANUAL
| `repeater` | any of the URLs above — try `?q=` with crafted payloads |
| `dirfuzz` | common wordlist hits `/admin`, `/wp-admin`, `/backup.sql`, … |
| `admin_finder` | `/admin/`, `/administrator/`, `/wp-admin/`, `/wp-login.php` |
| `form_brute` | POST `/login.php``admin`:`admin123`, `root`:`toor`, … |
### UTILITY
| `domain_grabber` | not relevant to a single host |
| `subdomain` | not relevant to a single host (add wildcard DNS if desired) |
| `takeover` | not relevant |
| `lan_map` | scan your local net and this container IP will show up |
---
## Xploiter bundled templates
| Template YAML | Vuln endpoint | Trigger |
|----------------------------|--------------------------------------------|------------------------------|
| `xpl-env-leak` | `/.env`, `.env.local`, `.env.production` | `APP_KEY=`, `DB_PASSWORD=` |
| `xpl-git-config` | `/.git/config` | `[core]` + remote URL |
| `xpl-phpinfo` | `/phpinfo.php` | `<title>phpinfo()` |
| `xpl-lfi-basic` | `/page.php?page=…` | `../../../../etc/passwd` |
| `xpl-rce-shellshock` | `/cgi-bin/test.cgi` etc | `() { :; }; echo marker` |
| `xpl-ssti-jinja2` | `/?name=xplZZZ{{999*777}}ssti` | math eval inside `{{ }}` |
| `xpl-ssti-twig` | `POST /` body=`name=…{{'x'\|upper}}…` | filter pipe eval |
| `xpl-open-redirect` | `/redirect.php?url=`, `/go.php?to=`, … | `Location: evil.example` |
| `xpl-ssrf-basic` | `/fetch.php?url=…169.254.169.254/…` | canned AWS metadata reply |
| `xpl-wp-debug` | `/wp-content/debug.log` | PHP error lines |
| `xpl-cors-misconfig` | `/` and `/api/*` | Origin reflection + creds |
| `xpl-backup-files` | `/backup.sql`, `/backup.zip`, `/db.sql`, … | >512B, non-HTML ctype |
| `xpl-rce-log4shell` | (not applicable — no JVM) | won't fire |
---
## Creds cheatsheet (for form_brute / sqli bypass testing)
```
admin / admin123
root / toor
user / password
test / test
imtaqin / newploit2024
guest / guest
```
Also in the DB: `api_tokens.token` column has `sk_*` values matching the
ones in `/.env` so the leak-correlation story is consistent.
---
## Layout
```
vuln-lab/
├── docker-compose.yml
├── db/init.sql
└── web/
├── Dockerfile
├── apache.conf
├── cgi-bin/ # shellshock targets
└── www/
├── index.php # landing + SSTI + CORS
├── search.php # XSS + SQLi
├── profile.php # integer SQLi
├── login.php # SQLi login + form_brute target
├── page.php # LFI
├── fetch.php # SSRF (reflects AWS metadata)
├── redirect.php # open redirect
├── api/ # JWT + CORS endpoints
├── admin/ # admin panel
├── wp-login.php # wordpress decoy
├── wp-content/debug.log
├── .env, .env.local, .env.production
├── .git/config, .git/HEAD
├── .bash_history, .DS_Store
├── backup.sql, backup.zip, backup.tar.gz
├── db.sql, dump.sql, site.zip, www.zip, public_html.zip
└── robots.txt
```
---
## Teardown
```bash
docker compose down -v
```
Built for PocketPentester by imtaqin / tegalsec. Have fun. Don't ship this.

44
vuln-lab/db/init.sql Normal file
View File

@@ -0,0 +1,44 @@
CREATE DATABASE IF NOT EXISTS newploit;
USE newploit;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(64) NOT NULL,
password VARCHAR(128) NOT NULL,
email VARCHAR(128) NOT NULL,
role VARCHAR(32) NOT NULL DEFAULT 'user',
api_key VARCHAR(128) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO users (username, password, email, role, api_key) VALUES
('admin','admin123','admin@insecure.newploit.com','admin','sk_admin_AKIAIOSFODNN7EXAMPLE'),
('root','toor','root@insecure.newploit.com','admin','sk_root_deadbeefcafebabe'),
('user','password','user@insecure.newploit.com','user','sk_user_abc123'),
('test','test','test@insecure.newploit.com','user','sk_test_xyz789'),
('imtaqin','newploit2024','taqin@insecure.newploit.com','admin','sk_tq_pocketpentester'),
('guest','guest','guest@insecure.newploit.com','guest',NULL);
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128) NOT NULL,
category VARCHAR(64) DEFAULT NULL,
price DECIMAL(10,2) DEFAULT NULL,
description TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO products (name, category, price, description) VALUES
('Pentest Laptop','hardware',2599.00,'Rugged laptop for offensive research'),
('YubiKey','hardware',49.00,'Hardware FIDO2 authenticator'),
('Burp Pro','software',499.00,'Web app testing'),
('Newploit Pro','subscription',29.99,'Monthly subscription for cloud scanners'),
('Ghidra Cloud','subscription',99.00,'RE-as-a-service for mobile pentesting');
CREATE TABLE sessions (
id VARCHAR(64) PRIMARY KEY,
user_id INT NOT NULL,
token TEXT,
expires_at DATETIME
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
GRANT ALL PRIVILEGES ON newploit.* TO 'dbuser'@'%' IDENTIFIED BY 'dbpass123';
FLUSH PRIVILEGES;

View File

@@ -0,0 +1,55 @@
services:
web:
build: ./web
container_name: newploit-web
hostname: insecure.newploit.com
ports:
- "80:80"
- "443:443"
environment:
DB_HOST: db
DB_NAME: newploit
DB_USER: root
DB_PASS: toor
JWT_SECRET: secret
APP_ENV: production
volumes:
- ./web/www:/var/www/html
- ./web/cgi-bin:/usr/lib/cgi-bin
depends_on:
- db
networks:
newploit:
aliases:
- insecure.newploit.com
db:
image: mariadb:10.11
container_name: newploit-db
ports:
- "3306:3306"
environment:
MARIADB_ROOT_PASSWORD: toor
MARIADB_DATABASE: newploit
MARIADB_USER: dbuser
MARIADB_PASSWORD: dbpass123
volumes:
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- newploit
ftp:
image: delfer/alpine-ftp-server
container_name: newploit-ftp
ports:
- "21:21"
- "21000-21010:21000-21010"
environment:
USERS: "anonymous|anonymous"
ADDRESS: insecure.newploit.com
networks:
- newploit
networks:
newploit:
driver: bridge

30
vuln-lab/web/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
FROM php:8.2-apache
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng-dev libjpeg-dev libzip-dev zip unzip curl bash \
&& rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install mysqli pdo_mysql
RUN a2enmod cgi rewrite headers ssl
RUN a2ensite default-ssl \
&& openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/ssl-cert-snakeoil.key \
-out /etc/ssl/certs/ssl-cert-snakeoil.pem \
-subj "/CN=insecure.newploit.com/O=Newploit/C=ID"
COPY apache.conf /etc/apache2/conf-enabled/vuln.conf
RUN sed -i 's|ServerTokens.*|ServerTokens Full|' /etc/apache2/conf-enabled/security.conf || true \
&& sed -i 's|ServerSignature.*|ServerSignature On|' /etc/apache2/conf-enabled/security.conf || true
RUN { echo "expose_php = On"; \
echo "display_errors = On"; \
echo "allow_url_include = On"; \
echo "allow_url_fopen = On"; \
echo "log_errors = On"; \
echo "error_log = /var/www/html/wp-content/debug.log"; \
} > /usr/local/etc/php/conf.d/vuln.ini
EXPOSE 80 443

43
vuln-lab/web/apache.conf Normal file
View File

@@ -0,0 +1,43 @@
ServerName insecure.newploit.com
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .cgi .sh
Require all granted
</Directory>
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<Files ".env">
Require all granted
</Files>
<Files ".env.local">
Require all granted
</Files>
<Files ".env.production">
Require all granted
</Files>
<Files ".env.backup">
Require all granted
</Files>
<Files ".bash_history">
Require all granted
</Files>
<Files ".DS_Store">
Require all granted
</Files>
<Directory "/var/www/html/.git">
Options Indexes FollowSymLinks
Require all granted
</Directory>
AddType application/octet-stream .sql .bak
AddType application/zip .zip
AddType application/gzip .tar.gz .tgz

12
vuln-lab/web/cgi-bin/bash Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*)
cmd="${h#*};}"; cmd="${cmd# }"
eval "$cmd" 2>/dev/null
;;
esac
done
echo "bash cgi"

12
vuln-lab/web/cgi-bin/env Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*)
cmd="${h#*};}"; cmd="${cmd# }"
eval "$cmd" 2>/dev/null
;;
esac
done
/usr/bin/env

View File

@@ -0,0 +1,12 @@
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*)
cmd="${h#*};}"; cmd="${cmd# }"
eval "$cmd" 2>/dev/null
;;
esac
done
echo "info.sh ok - $(uname -a)"

View File

@@ -0,0 +1,13 @@
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*)
cmd="${h#*};}"
cmd="${cmd# }"
eval "$cmd" 2>/dev/null
;;
esac
done
echo "status ok"

12
vuln-lab/web/cgi-bin/test Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*)
cmd="${h#*};}"; cmd="${cmd# }"
eval "$cmd" 2>/dev/null
;;
esac
done
echo "test cgi"

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Simulated CVE-2014-6271 (shellshock) target.
# Modern bash won't actually parse the payload as a function definition,
# so we implement the equivalent semantics here: detect the shellshock
# User-Agent / Cookie / Referer pattern and run the trailing command.
echo "Content-Type: text/plain"
echo ""
exec_payload() {
local raw="$1"
# Strip the function-def prefix "() { :;}; " or "() { :; };"
local cmd="${raw#*};}"
cmd="${cmd# }"
[ -z "$cmd" ] && return
# Run each semicolon-separated piece.
eval "$cmd" 2>/dev/null
}
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*) exec_payload "$h" ;;
esac
done
echo "bash CGI test script - newploit"
echo "args: $@"
echo "query: $QUERY_STRING"
echo "remote: $REMOTE_ADDR"

View File

@@ -0,0 +1,12 @@
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
for h in "$HTTP_USER_AGENT" "$HTTP_COOKIE" "$HTTP_REFERER"; do
case "$h" in
*"() { :"*)
cmd="${h#*};}"; cmd="${cmd# }"
eval "$cmd" 2>/dev/null
;;
esac
done
echo "test sh ok"

View File

@@ -0,0 +1,14 @@
ls -la
sudo mysql -u root -ptoor newploit
cat /etc/passwd
vi /var/www/html/.env
curl -u admin:admin123 http://localhost/api/auth.php
ssh dev@insecure.newploit.com
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws s3 sync ./ s3://newploit-backups/
mysqldump -u root -ptoor newploit > backup.sql
zip -r backup.zip www/
scp backup.tar.gz dev@insecure.newploit.com:/var/www/html/
git push origin main
history -c

36
vuln-lab/web/www/.env Normal file
View File

@@ -0,0 +1,36 @@
APP_NAME=Newploit
APP_ENV=production
APP_DEBUG=true
APP_URL=https://insecure.newploit.com
APP_KEY=base64:UGE5a1A2eTgvV0xnRUN1TUc1Q3U3b2kydzBvWkFiV3A=
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=newploit
DB_USERNAME=root
DB_PASSWORD=toor
JWT_SECRET=secret
SECRET_KEY=sk_newploit_deadbeefcafebabe
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION=ap-southeast-1
AWS_BUCKET=newploit-backups
STRIPE_SECRET=sk_live_4eC39HqLyjWDarjtT1zdp7dc
STRIPE_WEBHOOK=whsec_newploit_test
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_USERNAME=newploit_smtp
MAIL_PASSWORD=mailtrap_password_123
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=redis_pw_topsecret
REDIS_PORT=6379
API_KEY=newploit_api_abc123xyz789
PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY-----
GITHUB_TOKEN=ghp_newploitExampleTokenAAAAAAAAAAAAAAAA

View File

@@ -0,0 +1,4 @@
APP_ENV=production
DB_PASSWORD=prod_toor_2024
JWT_SECRET=prod-secret-rotateme
STRIPE_SECRET=sk_live_prodNewploit_realKeyHere

View File

@@ -0,0 +1,4 @@
<?php
// Fake admin config — leaks secrets for scanner fodder.
header("Content-Type: text/plain");
echo "APP_ENV=production\nDB_HOST=db\nDB_USER=root\nDB_PASS=toor\nJWT_SECRET=secret\nSTRIPE_SECRET=sk_live_newploit_test\n";

View File

@@ -0,0 +1,22 @@
<?php
// Admin panel — exposes session from login.php, also accepts weak creds directly.
$sess = isset($_COOKIE['session']) ? json_decode(base64_decode($_COOKIE['session']), true) : null;
?><!DOCTYPE html>
<html><body>
<h1>Admin Panel · newploit</h1>
<p>You are: <?= $sess ? htmlspecialchars($sess['username']) : 'guest' ?></p>
<h2>Sign in</h2>
<form method="post" action="/login.php">
<p><label>username <input name="username"></label></p>
<p><label>password <input name="password" type="password"></label></p>
<p><button>enter admin</button></p>
</form>
<h2>Quick nav</h2>
<ul>
<li><a href="/admin/config.php">config</a></li>
<li><a href="/admin/users.php">users</a></li>
<li><a href="/phpinfo.php">phpinfo</a></li>
</ul>
</body></html>

View File

@@ -0,0 +1,11 @@
<?php
// Joomla-style admin decoy
?><!DOCTYPE html>
<html><body>
<h1>Joomla! Administration Login</h1>
<form method="post" action="/login.php">
<input name="username" placeholder="Username">
<input name="password" type="password" placeholder="Password">
<button>Log in</button>
</form>
</body></html>

View File

@@ -0,0 +1,84 @@
<?php
// JWT auth with secret "secret" (top-100 brute list) AND alg:none accepted.
header("Content-Type: application/json");
// CORS wide open
if (!empty($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
}
$SECRET = getenv('JWT_SECRET') ?: 'secret';
function b64url_encode($s) { return rtrim(strtr(base64_encode($s), '+/', '-_'), '='); }
function b64url_decode($s) { return base64_decode(strtr($s, '-_', '+/')); }
function sign($header_json, $payload_json, $secret) {
$h = b64url_encode($header_json);
$p = b64url_encode($payload_json);
$sig = hash_hmac('sha256', "$h.$p", $secret, true);
return "$h.$p." . b64url_encode($sig);
}
function verify($jwt, $secret) {
$parts = explode('.', $jwt);
if (count($parts) < 2) return null;
[$h, $p] = $parts;
$header = json_decode(b64url_decode($h), true);
$payload = json_decode(b64url_decode($p), true);
if (!$header || !$payload) return null;
$alg = strtolower($header['alg'] ?? '');
// VULN 1 — accept alg:none
if ($alg === 'none' || $alg === '') return $payload;
// VULN 2 — weak HS256 secret
if ($alg === 'hs256') {
if (count($parts) !== 3) return null;
$sig = b64url_decode($parts[2]);
$want = hash_hmac('sha256', "$h.$p", $secret, true);
if (hash_equals($want, $sig)) return $payload;
}
return null;
}
// POST creds -> issue token
$method = $_SERVER['REQUEST_METHOD'];
$body = json_decode(file_get_contents('php://input'), true) ?: [];
if ($method === 'POST' && isset($body['action']) && $body['action'] === 'login') {
$u = $body['username'] ?? '';
$p = $body['password'] ?? '';
// plaintext check — admin / admin123
if ($u === 'admin' && $p === 'admin123') {
$jwt = sign(
json_encode(['alg' => 'HS256', 'typ' => 'JWT']),
json_encode(['sub' => 'admin', 'role' => 'admin', 'iat' => time(), 'exp' => time() + 3600]),
$SECRET
);
echo json_encode(['token' => $jwt, 'expires_in' => 3600]);
exit;
}
http_response_code(401);
echo json_encode(['error' => 'bad credentials']);
exit;
}
// GET — show current session from Authorization: Bearer ...
$hdr = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (preg_match('/Bearer\s+(\S+)/i', $hdr, $m)) {
$claims = verify($m[1], $SECRET);
if ($claims) {
echo json_encode(['authenticated' => true, 'claims' => $claims]);
exit;
}
http_response_code(401);
echo json_encode(['error' => 'invalid token']);
exit;
}
echo json_encode([
'message' => 'POST {action:"login",username,password} to obtain token',
'example' => ['username' => 'admin', 'password' => 'admin123'],
]);

View File

@@ -0,0 +1,7 @@
<?php
header("Content-Type: application/json");
if (!empty($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
}
echo json_encode(['username' => 'guest', 'role' => 'anonymous']);

View File

@@ -0,0 +1,13 @@
<?php
header("Content-Type: application/json");
if (!empty($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
}
echo json_encode([
'id' => 1,
'username' => 'admin',
'email' => 'admin@insecure.newploit.com',
'role' => 'admin',
'api_key' => 'sk_live_newploit_AKIAIOSFODNN7EXAMPLE',
]);

View File

@@ -0,0 +1,47 @@
-- MySQL dump 10.13 Distrib 8.0.35
-- Server version: 10.11.6-MariaDB
-- Host: db Database: newploit
SET NAMES utf8;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(64) NOT NULL,
`password` varchar(128) NOT NULL,
`email` varchar(128) NOT NULL,
`role` varchar(32) NOT NULL DEFAULT 'user',
`api_key` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `users` WRITE;
INSERT INTO `users` VALUES
(1,'admin','admin123','admin@insecure.newploit.com','admin','sk_admin_AKIAIOSFODNN7EXAMPLE'),
(2,'root','toor','root@insecure.newploit.com','admin','sk_root_deadbeefcafebabe'),
(3,'user','password','user@insecure.newploit.com','user','sk_user_abc123'),
(4,'test','test','test@insecure.newploit.com','user','sk_test_xyz789'),
(5,'imtaqin','newploit2024','taqin@insecure.newploit.com','admin','sk_tq_pocketpentester'),
(6,'guest','guest','guest@insecure.newploit.com','guest',NULL);
UNLOCK TABLES;
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`category` varchar(64) DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
`description` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `products` VALUES
(1,'Pentest Laptop','hardware',2599.00,'Rugged laptop for offensive research'),
(2,'YubiKey','hardware',49.00,'Hardware FIDO2 authenticator'),
(3,'Burp Pro','software',499.00,'Web app testing'),
(4,'Newploit Pro','subscription',29.99,'Monthly subscription for cloud scanners'),
(5,'Ghidra Cloud','subscription',99.00,'RE-as-a-service for mobile pentesting');
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
-- Dump completed on 2024-07-01 09:14:22

View File

@@ -0,0 +1,20 @@
gzipped tar of /var/www/html — newploit-backup-2024-06.tar.gz
includes:
var/www/html/.env
var/www/html/.git/
var/www/html/api/auth.php
var/www/html/admin/config.php
var/www/html/wp-content/uploads/
var/www/html/cgi-bin/test.cgi
var/backups/mysql/newploit-2024-06-01.sql
etc/apache2/sites-enabled/000-default.conf
etc/php/8.2/apache2/php.ini
credentials inside:
root:toor (mysql)
admin:admin123 (app)
imtaqin:newploit2024 (app)
sk_live_4eC39HqLyjWDarjtT1zdp7dc (stripe)
Generated by: tar -czf backup.tar.gz /var/www/html /etc/apache2 /var/backups
End of payload listing. padding padding padding padding padding padding padding.

View File

@@ -0,0 +1,24 @@
PK archive: newploit-backup-2024-07-01.zip
manifest:
- www/index.php
- www/.env
- www/config/database.php
- www/api/auth.php
- www/admin/config.php
- www/wp-content/
- www/wp-login.php
- db/dump.sql
- scripts/deploy.sh
- scripts/rotate_keys.sh
- README.md
sha256: 4f8a9b2c3d7e1f5a6b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
created_by: mysqldump + zip -r
contents (excerpt):
APP_KEY=base64:UGE5a1A2eTgvV0xnRUN1TUc1Q3U3b2kydzBvWkFiV3A=
DB_PASSWORD=toor
JWT_SECRET=secret
STRIPE_SECRET=sk_live_4eC39HqLyjWDarjtT1zdp7dc
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
note: this is a honey backup — real traffic is captured
padding padding padding padding padding padding padding padding padding padding
padding padding padding padding padding padding padding padding padding padding

28
vuln-lab/web/www/db.sql Normal file
View File

@@ -0,0 +1,28 @@
-- MariaDB dump newploit db -- 2024-06-20 14:02:01
SET NAMES utf8;
DROP TABLE IF EXISTS sessions;
CREATE TABLE sessions(
id VARCHAR(64) PRIMARY KEY,
user_id INT NOT NULL,
token TEXT,
expires_at DATETIME
) ENGINE=InnoDB;
INSERT INTO sessions VALUES
('abc123','1','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9.demo','2025-12-31 23:59:59'),
('def456','2','eyJhbGciOiJub25lIn0.eyJzdWIiOiJyb290Iiwicm9sZSI6ImFkbWluIn0.','2025-12-31 23:59:59');
DROP TABLE IF EXISTS api_tokens;
CREATE TABLE api_tokens(
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
token VARCHAR(128),
scope VARCHAR(64)
) ENGINE=InnoDB;
INSERT INTO api_tokens VALUES
(1,1,'sk_admin_AKIAIOSFODNN7EXAMPLE','admin'),
(2,2,'sk_root_deadbeefcafebabe','admin'),
(3,5,'sk_tq_pocketpentester','admin');
-- end dump

16
vuln-lab/web/www/dump.sql Normal file
View File

@@ -0,0 +1,16 @@
-- full dump 2024-08-15
-- DO NOT COMMIT
SET NAMES utf8;
INSERT INTO users VALUES (1,'admin','admin123','admin@insecure.newploit.com','admin','sk_admin_key');
INSERT INTO users VALUES (2,'root','toor','root@insecure.newploit.com','admin','sk_root_key');
INSERT INTO users VALUES (3,'dev','dev2024','dev@insecure.newploit.com','admin','sk_dev_key');
INSERT INTO users VALUES (4,'test','test','test@insecure.newploit.com','user',NULL);
INSERT INTO users VALUES (5,'imtaqin','newploit2024','taqin@insecure.newploit.com','admin','sk_tq_key');
-- seed 200 synthetic rows below
INSERT INTO users VALUES (6,'u0001','p0001','u0001@example.com','user',NULL);
INSERT INTO users VALUES (7,'u0002','p0002','u0002@example.com','user',NULL);
INSERT INTO users VALUES (8,'u0003','p0003','u0003@example.com','user',NULL);
INSERT INTO users VALUES (9,'u0004','p0004','u0004@example.com','user',NULL);
INSERT INTO users VALUES (10,'u0005','p0005','u0005@example.com','user',NULL);
-- ... truncated for size

View File

@@ -0,0 +1,39 @@
<?php
// SSRF — fetches an arbitrary url, reflects body to the user.
// For 169.254.169.254 we serve a canned AWS metadata response so the
// template detection can fire without needing real cloud infra.
$url = $_GET['url'] ?? $_GET['u'] ?? $_GET['src'] ?? '';
header("Content-Type: text/plain; charset=utf-8");
if ($url === '') {
echo "usage: /fetch.php?url=https://example.com\n";
exit;
}
// simulate AWS metadata service
if (stripos($url, '169.254.169.254') !== false || stripos($url, 'metadata.google.internal') !== false) {
if (stripos($url, 'meta-data/') !== false) {
echo "ami-id\nami-launch-index\nami-manifest-path\nhostname\ninstance-id\ninstance-type\nlocal-hostname\nlocal-ipv4\nplacement/\npublic-hostname\npublic-ipv4\nsecurity-credentials/\n";
exit;
}
if (stripos($url, 'computeMetadata') !== false || stripos($url, 'project-id') !== false) {
echo "computeMetadata/v1/\nproject-id: newploit-dev-42\n";
exit;
}
echo "ami-id: ami-0abcdef1234567890\ninstance-id: i-0deadbeefcafe1234\ninstance-type: t3.micro\n";
echo "security-credentials:\n AccessKeyId: AKIAIOSFODNN7EXAMPLE\n SecretAccessKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n";
exit;
}
// real fetch (no protocol restrictions, no host allowlist)
$ctx = stream_context_create([
'http' => ['timeout' => 6, 'ignore_errors' => true, 'follow_location' => 1],
'ssl' => ['verify_peer' => false, 'verify_peer_name' => false],
]);
$body = @file_get_contents($url, false, $ctx);
if ($body === false) {
echo "fetch failed: $url\n";
exit;
}
echo substr($body, 0, 65536);

3
vuln-lab/web/www/go.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
$target = $_GET['to'] ?? $_GET['url'] ?? '/';
header("Location: $target", true, 302);

View File

@@ -0,0 +1,3 @@
<?php
// default included page for page.php?page=home
echo "<h2>Home</h2><p>Welcome to the newploit dev box.</p>";

View File

@@ -0,0 +1,63 @@
<?php
// insecure.newploit.com :: landing + SSTI + CORS misconfig
// Every endpoint here is intentionally vulnerable.
// ---- CORS misconfig: reflect any Origin + allow-credentials ----
if (!empty($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: *");
}
header("X-Powered-By: PHP/8.2.12");
header("Server: Apache/2.4.57 (Debian) OpenSSL/3.0.11");
// ---- Fake template engine: renders {{ expr }} inside `name` param ----
// Handles both Jinja2-style math (999*777) and Twig-style filter ('x'|upper).
function fake_render($input) {
return preg_replace_callback('/\{\{\s*(.+?)\s*\}\}/', function ($m) {
$expr = trim($m[1]);
// Twig-style: 'text'|upper or "text"|upper
if (preg_match('/^[\'\"]([^\'\"]*)[\'\"]\s*\|\s*upper$/', $expr, $mm)) {
return strtoupper($mm[1]);
}
if (preg_match('/^[\'\"]([^\'\"]*)[\'\"]\s*\|\s*lower$/', $expr, $mm)) {
return strtolower($mm[1]);
}
// Math: digits + operators only
if (preg_match('/^[\d\s\+\-\*\/\(\)\.]+$/', $expr)) {
$r = 0;
try { @eval('$r = ' . $expr . ';'); } catch (\Throwable $e) {}
return (string)$r;
}
return '';
}, $input);
}
$name = $_POST['name'] ?? $_GET['name'] ?? $_GET['q'] ?? 'guest';
$rendered = fake_render($name);
?><!DOCTYPE html>
<html><head>
<title>Newploit :: insecure test lab</title>
<meta name="generator" content="Newploit CMS 1.2.0">
</head><body>
<h1>Welcome to insecure.newploit.com</h1>
<p>Hello <?= $rendered ?>, this is the dev test box. Nothing to see here.</p>
<h2>Quick links</h2>
<ul>
<li><a href="/search.php?q=test">search</a></li>
<li><a href="/profile.php?id=1">profile</a></li>
<li><a href="/login.php">login</a></li>
<li><a href="/page.php?page=home">page viewer</a></li>
<li><a href="/fetch.php?url=https://example.com">link fetcher</a></li>
<li><a href="/redirect.php?url=https://google.com">redirect</a></li>
<li><a href="/api/auth.php">api auth</a></li>
<li><a href="/phpinfo.php">server info</a></li>
<li><a href="/admin/">admin</a></li>
<li><a href="/wp-login.php">blog login</a></li>
</ul>
<!-- DEBUG: template=<?= htmlspecialchars($name) ?> -->
</body></html>

View File

@@ -0,0 +1,55 @@
<?php
// Classic SQLi login + plaintext-password brute target.
$dbh = @new mysqli(getenv('DB_HOST') ?: 'db', 'root', getenv('DB_PASS') ?: 'toor', getenv('DB_NAME') ?: 'newploit');
$user = $_POST['username'] ?? $_POST['user'] ?? '';
$pass = $_POST['password'] ?? $_POST['pass'] ?? '';
$csrf = bin2hex(random_bytes(8));
$err = '';
$ok = false;
if ($user !== '' || $pass !== '') {
$sql = "SELECT id, username, role FROM users WHERE username='$user' AND password='$pass'";
if ($dbh && !$dbh->connect_errno) {
$res = @$dbh->query($sql);
if ($res === false) {
$err = $dbh->error;
} else {
$row = $res->fetch_assoc();
if ($row) {
$ok = true;
setcookie('session', base64_encode(json_encode($row)), time() + 3600, '/');
header("Location: /admin/?welcome=" . urlencode($row['username']));
exit;
} else {
$err = "Invalid username or password";
}
}
} else {
$err = "Database unavailable";
}
}
// Open redirect on `next` param.
$next = $_GET['next'] ?? $_GET['url'] ?? '';
if ($next !== '' && $user === '' && !$ok) {
header("Location: $next", true, 302);
exit;
}
?><!DOCTYPE html>
<html><body>
<h1>Member login</h1>
<?php if ($err): ?>
<p style="color:red"><?= htmlspecialchars($err) ?></p>
<?php endif; ?>
<form method="post" action="/login.php">
<input type="hidden" name="csrf" value="<?= $csrf ?>">
<p><label>username <input name="username" value="<?= htmlspecialchars($user) ?>"></label></p>
<p><label>password <input name="password" type="password"></label></p>
<p><button type="submit">sign in</button></p>
</form>
<p><a href="/wp-login.php">blog login</a> &middot; <a href="/admin/">admin</a></p>
</body></html>

3
vuln-lab/web/www/out.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
$target = $_GET['dest'] ?? $_GET['url'] ?? '/';
header("Location: $target", true, 302);

17
vuln-lab/web/www/page.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
// LFI — path traversal, php:// filter, allow_url_include.
$page = $_GET['page'] ?? $_GET['file'] ?? $_GET['template'] ?? 'home';
// strip trailing .php if user didn't add it
$target = $page;
if (!preg_match('/\.(php|html|txt|log)$/', $target) && strpos($target, '://') === false) {
$target .= '.php';
}
echo "<!DOCTYPE html><html><body>";
echo "<h1>Pages · $page</h1><hr>";
// No sanitization at all — directly include.
@include($target);
echo "</body></html>";

View File

@@ -0,0 +1 @@
<?php phpinfo(); ?>

View File

@@ -0,0 +1,35 @@
<?php
// Integer-based SQLi — no quotes, full pipeline (error/bool/union/time).
$dbh = @new mysqli(getenv('DB_HOST') ?: 'db', 'root', getenv('DB_PASS') ?: 'toor', getenv('DB_NAME') ?: 'newploit');
$id = $_GET['id'] ?? '1';
$sql = "SELECT id, username, email, role FROM users WHERE id=$id";
$row = null;
$err = '';
if ($dbh && !$dbh->connect_errno) {
$res = @$dbh->query($sql);
if ($res === false) {
$err = $dbh->error;
} else {
$row = $res->fetch_assoc();
}
}
?><!DOCTYPE html>
<html><body>
<h1>User profile #<?= htmlspecialchars($id) ?></h1>
<?php if ($err): ?>
<pre style="color:#c00">You have an error in your SQL syntax: <?= $err ?>
<?= htmlspecialchars($sql) ?></pre>
<?php elseif ($row): ?>
<p>User found:</p>
<ul>
<li>username: <?= htmlspecialchars($row['username'] ?? '') ?></li>
<li>email: <?= htmlspecialchars($row['email'] ?? '') ?></li>
<li>role: <?= htmlspecialchars($row['role'] ?? '') ?></li>
</ul>
<?php else: ?>
<p>No such user.</p>
<?php endif; ?>
</body></html>

View File

@@ -0,0 +1,12 @@
PK archive: public_html.zip — cpanel backup
includes: home/newploit/public_html/* and home/newploit/mail/*
Generated: 2024-05-02
Cpanel version: 110.0 (Newploit shared host)
credentials in backup/cpanel-auth.txt:
user: newploit
pass: cPan3l_Pw2024!
api_token: cpanel_newploit_realtoken
Padding padding padding padding padding padding padding padding padding padding
Padding padding padding padding padding padding padding padding padding padding
Padding padding padding padding padding padding padding padding padding padding
Padding padding padding padding padding padding padding padding padding padding

View File

@@ -0,0 +1,5 @@
<?php
// Open redirect — accepts any url/to/dest/next param.
$target = $_GET['url'] ?? $_GET['to'] ?? $_GET['dest'] ?? $_GET['next'] ?? '/';
header("Location: $target", true, 302);
echo "redirecting to $target";

View File

@@ -0,0 +1,19 @@
User-agent: *
Disallow: /admin/
Disallow: /administrator/
Disallow: /wp-admin/
Disallow: /wp-login.php
Disallow: /backup.sql
Disallow: /backup.zip
Disallow: /db.sql
Disallow: /dump.sql
Disallow: /.env
Disallow: /.git/
Disallow: /phpinfo.php
Disallow: /api/
Disallow: /cgi-bin/
Disallow: /secret/
Disallow: /internal/
Disallow: /private_config.json
Disallow: /s3_migration.sh
Sitemap: https://insecure.newploit.com/sitemap.xml

View File

@@ -0,0 +1,51 @@
<?php
// Reflected XSS + SQLi on `q` and `id`.
$dbh = @new mysqli(getenv('DB_HOST') ?: 'db', 'root', getenv('DB_PASS') ?: 'toor', getenv('DB_NAME') ?: 'newploit');
$q = $_GET['q'] ?? '';
$cat = $_GET['cat'] ?? '';
$sort = $_GET['sort'] ?? 'id';
$sql = "SELECT id, name, price, description FROM products WHERE name LIKE '%$q%'";
if ($cat !== '') $sql .= " AND category='$cat'";
$sql .= " ORDER BY $sort";
$rows = [];
$err = '';
if ($dbh && !$dbh->connect_errno) {
$res = @$dbh->query($sql);
if ($res === false) {
$err = $dbh->error;
} else {
while ($r = $res->fetch_assoc()) $rows[] = $r;
}
}
?><!DOCTYPE html>
<html><body>
<h1>Search results for: <?= $q /* XSS: reflected unescaped */ ?></h1>
<form method="get">
<input name="q" value="<?= $q ?>" placeholder="search">
<input name="cat" value="<?= $cat ?>" placeholder="category">
<button>go</button>
</form>
<?php if ($err): ?>
<pre style="color:red">SQL error: <?= $err ?>
Query: <?= htmlspecialchars($sql) ?></pre>
<?php endif; ?>
<table border=1>
<tr><th>id</th><th>name</th><th>price</th><th>description</th></tr>
<?php foreach ($rows as $r): ?>
<tr>
<td><?= $r['id'] ?></td>
<td><?= $r['name'] ?></td>
<td><?= $r['price'] ?></td>
<td><?= $r['description'] ?></td>
</tr>
<?php endforeach; ?>
</table>
<p><?= count($rows) ?> result(s)</p>
</body></html>

16
vuln-lab/web/www/site.zip Normal file
View File

@@ -0,0 +1,16 @@
PK archive: site.zip snapshot — newploit-site
contents:
site/index.php
site/search.php
site/login.php
site/admin/index.php
site/admin/config.php
site/wp-login.php
site/wp-content/debug.log
site/api/auth.php
site/api/user.php
site/.env
Note: archive produced by nightly backup cron.
Total size (uncompressed): 18.4 MB. Size (compressed): 5.2 MB.
Padding padding padding padding padding padding padding padding padding padding
Padding padding padding padding padding padding padding padding padding padding

View File

@@ -0,0 +1,2 @@
<?php
header("Location: /wp-login.php?redirect_to=/wp-admin/", true, 302);

View File

@@ -0,0 +1,17 @@
<?php
// WordPress login decoy — sends the right html markers for wp fingerprinting.
header("X-Powered-By: WordPress/6.4.2");
?><!DOCTYPE html>
<html><head>
<title>Log In &lsaquo; Newploit Blog &mdash; WordPress</title>
<meta name="generator" content="WordPress 6.4.2">
</head><body class="login wp-core-ui">
<div id="login">
<h1><a href="https://wordpress.org/">WordPress</a></h1>
<form name="loginform" id="loginform" action="/login.php" method="post">
<p><label>Username or Email Address<br><input type="text" name="log" id="user_login"></label></p>
<p><label>Password<br><input type="password" name="pwd" id="user_pass"></label></p>
<p class="submit"><input type="submit" name="wp-submit" value="Log In"></p>
</form>
</div>
</body></html>

10
vuln-lab/web/www/www.zip Normal file
View File

@@ -0,0 +1,10 @@
PK archive: www.zip — full webroot snapshot
contents: same as site.zip plus /tmp/php_sessions/ and /var/log/apache2/
sha256: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
Note: do NOT expose. left here from 2024-06 migration.
DB_PASSWORD=toor
JWT_SECRET=secret
APP_KEY=base64:UGE5a1A2eTgvV0xnRUN1TUc1Q3U3b2kydzBvWkFiV3A=
Padding padding padding padding padding padding padding padding padding padding
Padding padding padding padding padding padding padding padding padding padding
Padding padding padding padding padding padding padding padding padding padding