- GPT5.6 Sol Ultra analysierte die aktuelle stabile WordPress-Version und stellte in etwas mehr als 10 Stunden eine Angriffskette fertig, die von einer SQL-Injection vor der Authentifizierung bis zur Erstellung eines Administratorkontos und zur Remote Code Execution (RCE) reicht
- Ausgangspunkt war eine Array-Index-Fehlanpassung in der Batch API, die seit WordPress 5.6 verfügbar ist; durch die Kombination rekursiver Batch-Anfragen wurden GET-Beschränkungen und Parameterprüfungen umgangen
- Über eine nicht validierte
author_exclude-Zeichenkette wurde eine UNION-Injection ausgelöst, danach wurden manipulierte Beiträge in den In-Memory-Cache gelegt und oEmbed-Cache, Changesets, zirkuläre Referenzen und Hooks nacheinander missbraucht - Mit
user_id: 1incustomize_changesetwurden vorübergehend Administratorrechte erlangt, perparse_request-Hook Batch-Anfragen erneut ausgeführt, ein neuer Administrator angelegt und schließlich durch den Upload einer Backdoor-Plugin-ZIP Codeausführung erreicht - Die anteilig berechneten Kosten eines 200-Dollar-Monatsabos bei 50 % des Wochenkontingents lagen bei etwa 25 Dollar; die menschliche Rolle dürfte sich stärker auf die übergeordnete Steuerung der Forschung verlagern, etwa Produktauswahl, Wahl der Angriffsfläche und Prompt-Anpassung
Entdeckungsprozess und Versuchsbedingungen
- Der von OpenAI als für die Lösung der Cycle-Double-Cover-Vermutung verwendet veröffentlichte Prompt wurde für Sicherheitsforschung angepasst und GPT5.6 Sol Ultra gegeben
- Die aktuelle stabile WordPress-Version wurde nach
main/geklont, das Verzeichnis.gitentfernt und ein leeres Verzeichnisthird_party/vorbereitet, damit abhängiger Code untersucht werden konnte - Der Prompt wies an, bis zu 4 Agenten parallel zu nutzen und über mindestens 6 Stunden verschiedene Angriffspfade aufrechtzuerhalten
- Untersucht wurden Eingabe-Parsing, Zeichensätze, Datei-Uploads, Fehlerbehandlung, eingebaute Pfade, Serialisierung, Caching, Race Conditions, Kryptografie, Typen und Mass Assignment
- Verwandte Vorgehensweisen wurden registriert, und wenn Agenten sich auf bestimmte Strategien konzentrierten, wurden sie in weniger erkundete Bereiche umverteilt
- Konkrete Bugs wurden von gegnerischen Agenten erneut verifiziert, und auch gescheiterte Pfade wurden wieder geöffnet, sobald neue Mechanismen entstanden
- Es war untersagt, Changelogs, Unterschiede zu Patch-Versionen oder Hinweise aus dem Internet zu nutzen; neue Schwachstellen sollten allein aus dem Quellcode gefunden werden
- Um unrealistische Konfigurationen oder Voraussetzungen zu vermeiden, die ein Angreifer nicht erfüllen kann, wurde das Ziel als „RCE vor der Authentifizierung in einer typischen Produktionsumgebung mit MySQL“ festgelegt
- Nach etwa 6 Stunden fand das Modell eine SQL-Injection vor der Authentifizierung und reproduzierte sie innerhalb weniger Minuten auf einem Standard-WordPress-Remote-Server durch das Auslesen der Admin-E-Mail
- Nach einer zusätzlichen Aufforderung zur Eskalation bis RCE stellte es etwa 4 Stunden später eine Kette fertig, die ohne Passwort-Cracking oder Offline-Berechnungen von einer schreibgeschützten SQL-Injection zu Administratorrechten aufstieg
- Die gesamte Arbeitszeit betrug etwas mehr als 10 Stunden und verbrauchte 50 % des Wochenkontingents. Anteilig berechnet aus dem 200-Dollar-Monatsabo ergaben sich Kosten von rund 25 Dollar
- Vor der Offenlegung wurde dem Betreiber über das Wochenende Zeit gegeben, WordPress zu aktualisieren; in dieser Zeit reproduzierten Calif und Hacktron die gesamte Kette unabhängig und noch vor anderen PoCs auf GitHub
- Laufende Instanzen können unter wp2shell.com auf Verwundbarkeit geprüft werden
Validierungs-Fehlanpassung in der Batch API
- Die in WordPress 5.6 eingeführte Batch API verarbeitet mehrere virtuelle API-Anfragen in einer einzigen Anfrage. Der Endpoint selbst ist ohne Authentifizierung erreichbar, an jede Unteranfrage werden jedoch Authentifizierungsinformationen weitergereicht
- Normale REST-Anfragen werden in folgender Reihenfolge verarbeitet
has_valid_params()prüft Pflichtwerte und Gültigkeitsanitize_params()bereinigt Werte- Der Berechtigungs-Callback wird ausgeführt
- Der Endpoint-Callback wird ausgeführt
- Die Batch API trennt aus Performance-Gründen Validierung und Ausführung in zwei Schleifen
- In der ersten Schleife werden alle Anfragen validiert und bereinigt
- In der zweiten Schleife werden die Validierungsergebnisse geprüft und Berechtigungs- sowie Endpoint-Callbacks ausgeführt
- Die Implementierung geht davon aus, dass in
$matchesals Ergebnis des Route-Matchings und in$validationals Ergebnis der Prüfung jeweils dieselben Indizes zueinander gehören - Wenn eine fehlerhafte Anfrage in den Zweig
is_wp_error($single_request)gelangt, wird zwar ein Eintrag zu$validationhinzugefügt, wegencontinuejedoch keiner zu$matches- Danach sind alle Einträge in
$matchesum eine Position verschoben - Parameter einer Anfrage können dann nach den Regeln einer anderen Anfrage validiert und anschließend in einem ursprünglich nicht vorgesehenen Endpoint-Handler ausgeführt werden
- Danach sind alle Einträge in
- Mithilfe dieser Index-Fehlanpassung lässt sich das Validierungsergebnis eines anderen Endpoints, der Parameter nicht bereinigt, auf einen Batch-fähigen Endpoint anwenden
SQL-Injection in author__not_in
GET /wp/v2/postsverwendet die interne Query-Variableauthor__not_in, um bestimmte Autoren aus den Ergebnissen auszuschließen- Ist der Wert ein Array, wird auf jedes Element
absintangewandt und es zu einer Ganzzahl gemacht; bei einem Skalarwert wird dieser jedoch unverändert perimplodezusammengesetzt und in die SQL-KlauselNOT INeingefügt - Bei normalen Aufrufen muss der öffentliche Parameter
author_excludeein Integer-Array sein, daher fällt das Problem nicht auf - Über die Batch-Index-Fehlanpassung lässt sich die Zeichenkette
author_excludenach den Regeln vonDELETE /wp/v2/posts/1, das diesen Parameter nicht erkennt, validieren und anschließend anGET /wp/v2/postsübergeben - Auch die Einschränkung, dass die Batch API keine GET-Unteranfragen zulässt, wird durch rekursive Batch-Aufrufe umgangen
- Im äußeren Batch wird durch eine Index-Fehlanpassung die Prüfung von
methodfür die innere Anfrage übersprungen - Im inneren Batch wird erneut eine Index-Fehlanpassung erzeugt, um die Prüfung von
author_excludezu umgehen
- Im äußeren Batch wird durch eine Index-Fehlanpassung die Prüfung von
- Mit einem Wert wie
0) OR 1=1 --werden alle Beitragszeilen zurückgegeben, wodurch sich die Injektion bestätigen lässt - Danach können über UNION-basierte Injections Zeilen in Form von
wp_postserzeugt und beliebige Datenbankwerte exfiltriert werden - Passwörter, Reset-Tokens und API-Schlüssel sind in der Datenbank gehasht, daher führt Datenabfluss allein nicht zur Kontoübernahme, solange das Admin-Passwort nicht schwach ist
Manipulation des beitragsbezogenen Anfrage-Caches
- WordPress speichert innerhalb einer Anfrage wiederholt referenzierte
WP_Post-Objekte in einem In-Memory-Cache, um Datenbank-Roundtrips zu verringern - Gibt eine UNION-Injection gefälschte Beitragszeilen zurück, kann ein Angreifer zahlreiche Felder wie Beitrags-ID, Typ, Status, Parent-Beziehung und Inhalt mit frei gewählten Werten in den Cache bringen
- Auch API-Antworten verarbeiten den Beitragsinhalt nachträglich, sodass mit manipuliertem Inhalt zusätzliche Codepfade ausgeführt werden können
- Dieser Cache verschwindet am Ende der Anfrage, und die gefälschten Beiträge existieren nicht in der Datenbank; allein durch Cache-Manipulation lässt sich daher keine Persistenz über mehrere Anfragen hinweg erreichen
Erzeugen einer Datenbankzeile über den oEmbed-Cache
- Die WordPress-Funktion embeds bettet per
[embed]...[/embed]im Beitragsinhalt unterstützte entfernte Inhalte ein - Damit nicht jedes Mal eine HTTP-Anfrage gesendet werden muss, wird das Ergebnis als Beitrag vom Typ
oembed_cacheinwp_postsin der Datenbank gespeichert - Wird ein lokaler WordPress-Beitrag per relativem Pfad eingebettet, entfällt die HTTP-Anfrage, und es wird nicht geprüft, ob die referenzierte Beitrags-ID tatsächlich existiert
- Selbst wenn ein nicht existierender lokaler Beitrag wie
/?p=10eingebettet wird, kann eineoembed_cache-Zeile für diese Daten erstellt werden - Wird die erzeugte Zeile anschließend wieder per SQL-Injection abgefragt und der Beitragstyp im Speicher zu
posto. Ä. manipuliert, unterscheiden sich Datenbank- und Cache-Darstellung - Beim Abgleich dieser beiden Darstellungen ruft WordPress
wp_update_post()auf und bevorzugt für alle außer explizit gesetzten Feldern wieIDundpost_contentdie vom Angreifer erzeugten Speicherwerte - Dadurch lässt sich eine
oembed_cache-Zeile in einen normalen Beitrag umwandeln; in diesem Aufruf wirdpost_contentjedoch mit dem Embed-Ergebnis überschrieben, sodass der Angreifer den Inhalt nicht mitsteuern kann
Temporäre Administratorrechte über customize_changeset
- Entwürfe für Theme-Anpassungen werden in
wp_postsals besondere Beiträge vom Typcustomize_changesetgespeichert post_contententhält JSON mit den Änderungswerten und Typen je Einstellungsschlüssel sowie der Benutzer-ID, die die Änderung durchführen soll- Beim Anwenden eines Changesets liest WordPress die jeweilige
user_idund wechselt mitwp_set_current_user()vorübergehend zum aktuellen Benutzer - Wendet ein Angreifer ein Changeset mit
user_id: 1an, kann er selbst in einer anonymen Anfrage kurzzeitig die Identität des Administrators nutzen - Der vorherige oEmbed-Abgleich überschreibt
post_content, daher wird ein separater Aufrufpfad vonwp_update_post()benötigt, um bösartiges Changeset-JSON zu erhalten
Beibehaltung des Inhalts über einen Parent-Zyklus
- WordPress-Beiträge können einen Parent haben, eine zyklische Struktur mit sich selbst oder einem Unterbeitrag als Parent ist jedoch nicht erlaubt
- Der Filter
wp_insert_post_parentprüft entlang der Parent-Hierarchie auf Zyklen und ruft bei Entdeckung eines Zykluswp_update_post()auf, umpost_parentdes betreffenden Beitrags auf 0 zu setzen - Dieser zweite Aufruf setzt nur
IDundpost_parentund überschreibtpost_contentnicht - Wird ein Beitrag im Speicher per SQL-Injection als
customize_changesetmit sich selbst als Parent getarnt, schreibt der Zyklus-Reparaturprozess das vom Angreifer definierte bösartige Changeset-JSON in die Datenbank - Wird ein Changeset mit vergangenem Datum und Status
futureerzeugt, wendet WordPress es an und führt die vorgesehenen Einstellungsänderungen gemäßuser_id: 1mit Administratorrechten aus - Die Administratorrechte bleiben nur während der Changeset-Verarbeitung erhalten und fallen danach wieder auf Gastrechte zurück
Erneute Ausführung der gesamten Anfrage über einen dynamischen Hook
- WordPress-Hooks bestehen aus Actions und Filtern und erlauben Plugins Eingriffe an vielen Punkten des Lebenszyklus wie Login, Veröffentlichung oder Script-Registrierung
- Ändert sich der Beitragsstatus, führt WordPress eine dynamische Action der Form
"{$new_status}_{$post->post_type}"aus- Für einen normalen Beitrag ergibt sich ein Name wie
publish_post - Ein gefälschter Beitrag im Speicher kann Status und Typ beliebig setzen und dadurch einen gewünschten Action-Namen mit einem oder mehreren Unterstrichen bilden
- Für einen normalen Beitrag ergibt sich ein Name wie
- Die Hook-Argumente sind auf die vom Angreifer gesetzte Beitrags-ID und das
WP_Post-Objekt beschränkt, daher ist ein direkter sinnvoller Aufruf beliebiger Actions schwierig - Die Angriffskette setzt den Status auf
parseund den Typ aufrequest, um den Hookparse_requestaufzurufen parse_requestwird früh im Anfrage-Lebenszyklus ausgeführt; ein erneuter Aufruf verarbeitet daher die ursprüngliche Batch-API-Anfrage noch einmal vollständig von Anfang an- Diese erneute Verarbeitung geschieht, solange die durch das Changeset gesetzte temporäre Administratoridentität noch aktiv ist, sodass Admin-exklusive Anfragen, die beim ersten Durchlauf mangels Rechten scheiterten, im zweiten Durchlauf erfolgreich sind
Die RCE-Kette in zwei Anfragen
- Der finale Exploit verwendet zwei HTTP-Anfragen und weist den gefälschten Beiträgen so hohe IDs zu, dass sie nicht mit echten Beiträgen kollidieren
-
Erste Anfrage: persistente Zeilen vorbereiten
- Durch SQL-Injection wird ein gefälschter Beitrag mit drei lokalen Embeds zurückgegeben, wodurch 3
oembed_cache-Zeilen erzeugt werden, dieO,CundDentsprechen - Alle drei Embeds verweisen auf denselben Beitrag
S, nutzen aber unterschiedliche Query-Strings, um getrennte oEmbed-Cache-Hashes zu erzeugen
- Durch SQL-Injection wird ein gefälschter Beitrag mit drei lokalen Embeds zurückgegeben, wodurch 3
-
Zweite Anfrage: sechs Beiträge zusammensetzen
- Im In-Memory-Cache werden die folgenden sechs gefälschten Beiträge aufgebaut
O: alter Cache mit Status/Typpublish/oembed_cacheund ParentCC:future/customize_changesetmit sich selbst als Parent und bösartigem Changeset-JSONP:draft/pagemit ParentDD:parse/requestmit sich selbst als ParentS:publish/post, das Embed-Daten liefertT:publish/post, das das äußere Embed enthält- Das Embed in
TfragtOab und veranlasst wegen des alten Änderungszeitpunkts eine Aktualisierung des Caches vonS - Wird bei der Aktualisierung von
Oder Zyklus in ParentCerkannt, setzt WordPress den Parent vonCauf 0 und schreibt dabei das im Speicher befindlichecustomize_changesetsamt bösartigem JSON in die Datenbank - Das
future-Changeset mit Datum in der Vergangenheit wird angewendet und veröffentlichtPmit der Administratoridentität aususer_id: 1 - Die Aktualisierung von
Pentdeckt den Zyklus in ParentD, schreibtDund ruft mit manipuliertem Status und Typ die Actionparse_requestauf - Die Batch-Anfrage enthält von Anfang an eine Anfrage zur Erstellung eines neuen Administrators
- Bei der ersten Verarbeitung scheitert sie mit Gastrechten
- Bei der erneuten Ausführung über
parse_requestist die temporäre Administratorberechtigung noch vorhanden, daher gelingt sie - Nach dem Login mit dem neuen Administratorkonto führt der Upload einer Backdoor-Plugin-ZIP schließlich zur Remote Code Execution
Sich verändernde Rollen in der KI-Sicherheitsforschung
- Besonders kreative Schritte der gesamten Kette waren die Umgehung der GET-Beschränkung durch rekursive Batch-Aufrufe, das Erlangen von Administratorrechten durch die Kombination aus Cache und Changesets sowie die erneute Ausführung der Anfrage per
parse_requestüber gefälschte Beiträge - Eine allgemeine Überlegenheit lässt sich daraus nicht ableiten, aber die Einschätzung lautet, dass ein Sicherheitsforscher dieselbe Kette ohne KI kaum innerhalb von 10 Stunden gefunden und fertiggestellt hätte
- Selbst wenn der ursprüngliche Batch-Bug bereits bekannt gewesen wäre, sei fraglich, ob sich in dieser Zeit auch der Weg bis zur RCE hätte konstruieren lassen
- GPT5.6 Sol Ultra habe gegenüber GPT5.5 deutlich bei der Fähigkeit zugelegt, mehrere voneinander getrennte Code-Gadgets zu finden und zu einer Kette zu verbinden
- Je mehr technische Exploit-Entwicklung das Modell übernimmt, desto stärker werden sich Menschen auf die Auswahl von Produkten und Angriffsflächen, die Zeiteinteilung, die Forschungsrichtung und Korrekturen bei Fehlentwicklungen des Modells konzentrieren
- Diese Meta-Forschungskompetenz könne KI derzeit noch nicht gut abdecken und werde mit steigender technischer Leistungsfähigkeit der Modelle voraussichtlich noch wichtiger
1 Kommentare
Meinungen auf Hacker News
Es gibt keine Grundlage dafür, dass für diesen Exploit 500.000 Dollar gezahlt wurden oder gezahlt werden. Im Beitrag heißt es, der Prompt werde so vorsichtig überarbeitet wie die Bibel; dann könnte man diesen Prompt wohl eher für 500.000 Dollar verkaufen.
Der Autor arbeitet bei https://www.assetnote.io/, das ein automatisiertes Scanning-AI-Produkt anbietet.
Solche Broker zahlen üblicherweise keine großen Summen auf einmal aus, sondern verkaufen den Zugriff an staatliche Akteure und zahlen dann in Raten, solange der Bug ungepatcht bleibt. Das ist so strukturiert, um Weiterverkauf oder eine frühe Entwertung zu verhindern; daher dürfte es kaum jemanden geben, der bestätigen kann, ob für eine vergleichbare Schwachstelle tatsächlich der volle Betrag gezahlt wurde.
Das nächstliegende Beispiel sind Teenager aus Florida, die in Steam-Spiele Malware eingebaut haben, um Konten zu stehlen, und dann erwischt wurden. Sie wären so oder so gefasst worden, aber ohne Prahlerei in sozialen Medien hätten die Ermittlungen deutlich länger gedauert.
Wenn man sich https://github.com/WordPress/WordPress/commit/3a640e1c5e39aa... ansieht, taucht auch 2026 noch SQL-Injection durch String-Verkettung auf.
Statt SQL direkt auszuführen, soll man
dbDeltaverwenden, verlangt werden aber extrem pingelige Formatierungsregeln: jedes Feld in eine eigene Zeile, zwei Leerzeichen zwischenPRIMARY KEY,KEYstattINDEXusw. Feldnamen dürfen weder Anführungszeichen noch Backticks verwenden, Datentypen müssen kleingeschrieben, SQL-Keywords großgeschrieben sein, und auch alle Längenparameter müssen angegeben werden.sprintfbaut.In
POST- undGET-Requests steckten Payloads der Form/wp/v2/widgets?author_exclude=1%29+AND+1%3D0+UNION+ALL+SELECT....Principal Software Engineer @ Bluehost,WordPress Core Committer; bei solchem Code klingt „principal“ wirklich merkwürdig.Ich habe genug von FOMO-Schreiberei. Es wurde nicht einfach mit 25 Dollar gefunden, sondern mit Branchenexpertise darüber, wo man hinschauen und wie man suchen muss, sowie über Jahre angesammeltem Material.
Man sollte aufhören, diese Glücksspiel-Erzählung und die Illusion zu verbreiten, alle würden gerade eine Chance verpassen.
Überraschend ist der hohe Preis für eine bereits bekannte Schwachstelle, und womöglich stimmt er auch nicht. WordPress wird nicht umsonst oft als Remote-Root-Shell mit Blog-Funktion bezeichnet.
Ich verstehe, dass Drag-and-drop leichter zu vermitteln ist, als normalen Nutzern zu sagen, sie sollen in ein GitHub-Repository committen und mit Hugo bauen. Aus Sicherheitssicht ist es aber eine Architektur, die nur darauf wartet, dass im Core oder in einem von Tausenden Plugins eine Schwachstelle entsteht und Remote Code Execution as a Service eröffnet.
Ein interessanter Beitrag, und LLM-gestützte Exploit-Findung und Disclosure sind tatsächlich ein Grund zur Sorge. Ich habe Modelle auch schon vergleichsweise schnell Code für einen Container-Escape aus einer lokalen Linux-Privilege-Escalation-Schwachstelle erstellen lassen.
Allerdings ist erstaunlich, dass GPT-5.6 den Prompt nicht durch Sicherheitsmechanismen blockiert hat. GPT-5.5 und höher meiden offensive Security-Arbeiten eher, ähnlich wie Opus 4.7+/Fable; daher wirkt es plausibel, dass der Autor von OpenAI eine Cybersecurity-Freigabe mit gelockerten Sicherheitsmechanismen erhalten hat.
Auch Nicht-KI-Tools für statische Anwendungssicherheitstests (SAST) aus der Zeit vor 2020 haben viele solcher SQL-Injections gefunden; spätestens im Code-Review hätte das auffallen müssen. Ich frage mich, ob WordPress keine Code-Reviews oder SAST einsetzt
Eine meiner Websites wurde über diese Schwachstelle gehackt, zum Glück war es eine ohne Nutzer
Der Angreifer legte zwei Admin-Konten in der Datenbank an und installierte unter
wp-content/plugins/wp-coreeine Web-Shell zur Remote Command Execution namenswp-core-[12 beliebige Zeichen].php. Inmu-pluginsplatzierte er außerdem einefirewall.php-Backdoor, die perGET ?sergeieinen Administrator anlegt, fügte auch einecache-seo-helper.php-Backdoor hinzu und änderte mitfixer.phpdie WordPress-Versionsnummer so, dass sie wie eine gepatchte Version aussah. Am Ende habe ich beschlossen, WordPress aufzugebenGegen Ende des Beitrags wurde es schwer verständlich, als Posts plötzlich mit merkwürdigen Namen bezeichnet wurden. Ich frage mich, warum eine ID
Ound eine andere0ist und warum stattEMBED_01oderABCDEFeinzelne Zeichen und das zufällig wirkendeOCPDSTverwendet wurdenOsteht fürpublish/oembed_cache,Cfürfuture/customize_changeset,Pfürdraft/page,Dfürparse/request,Sfürpublish/post, das Embed-Daten bereitstellt, undTfürpublish/post, das ein externes Embed enthältIch frage mich, ob hier unterstellt wird, dass Leute, die 500.000 Dollar zahlen würden, GPT-5.6 nicht selbst nutzen können
Auch ich suche mit LLMs nach Sicherheitslücken, aber man kann die Ergebnisse nicht einfach unverändert einreichen und damit fertig sein; viele versuchen genau das
Ob GPT-5.6 Sol übermenschlich ist, ist keine einfache Ja-oder-nein-Frage. Computer übertreffen Menschen seit Jahrzehnten im Schach, und diesem Beitrag nach scheinen sie Menschen nun auch beim Codeverständnis überholt zu haben