Hallo Habr! Heute werde ich Ihnen sagen, warum Valve die größten Prämien in der Geschichte seines Belohnungsprogramms für Schwachstellen gezahlt hat. Willkommen bei Katze!

1. SQL Injection
Der Dienst
partner.steampowered.com dient zum Empfang von Finanzinformationen von Steam-Partnern. Auf der Seite mit den Verkaufsberichten wird ein Diagramm mit Schaltflächen gezeichnet, die den Zeitraum ändern, in dem die Statistiken angezeigt werden. Hier sind sie im grünen Rechteck:

Die Anforderung zum Herunterladen von Statistiken sieht folgendermaßen aus:
Dabei ist "UA" der Ländercode.Na dann ist es Zeit für Zitate!
Versuchen wir mal "UA '":

Die Statistik ist NICHT zurückgekehrt, was zu erwarten ist.
Jetzt "UA":

Die Statistiken sind wieder da und es sieht aus wie eine Injektion!
Warum?Angenommen, die Datenbankanweisung sieht folgendermaßen aus:
SELECT * FROM countries WHERE country_code = `UA`;
Wenn Sie UA 'senden, lautet die Datenbankanweisung:
SELECT * FROM countries WHERE country_code = `UA``;
Haben Sie ein zusätzliches Angebot bemerkt? Und das bedeutet, dass die Anweisung ungültig ist.
Gemäß der SQL-Syntax ist die folgende Abfrage vollständig gültig (es gibt keine zusätzlichen Anführungszeichen):
SELECT * FROM countries WHERE country_code = `UA```;
Bitte beachten Sie, dass es sich um eine Reihe von
countryFilter [] handelt . Ich ging davon aus, dass, wenn wir den Parameter
countryFilter [] in der Abfrage mehrmals duplizieren, alle von uns
gesendeten Werte in der SQL-Abfrage folgendermaßen kombiniert werden:
'value1', 'value2', 'value3'
Wir prüfen und stellen sicher:

Tatsächlich haben wir Statistiken aus drei Ländern aus der Datenbank angefordert:
`UA`, `,` ,`RU`
Die Syntax ist korrekt - die Statistiken sind zurück :)
Umgehung der Webanwendungs-FirewallSteam-Server verstecken sich hinter Akamai WAF. Diese Schande fügt Stöcke in die Räder guter (und nicht so) Hacker ein. Es gelang mir jedoch, dies zu überwinden, indem ich die Werte des Arrays in einer einzigen Abfrage (wie oben erläutert) kombinierte und kommentierte. Stellen Sie zunächst sicher, dass Letzteres verfügbar ist:
?countryFilter[]=UA`/*&countryFilter[]=*/,`RU
Die Anfrage ist gültig, daher gibt es Kommentare in unserem Sortiment.
Wir hatten verschiedene Syntaxoptionen, lokale Datenbanken zum Testen von Nutzdaten, Kommentarzeichen und eine unendliche Anzahl von Anführungszeichen für alle Codierungen sowie selbst geschriebene Skripte auf Python, Dokumentation für alle Datenbanken, Anweisungen zum Umgehen von Firewalls, Wikipedia und Antichest. Es ist nicht so, dass es eine notwendige Reserve für die Förderung von Injektionen war, aber da es anfing, die Datenbank zu brechen, ist es schwer zu stoppen ...
WAF blockiert eine Anforderung, wenn sie auf eine darin enthaltene Funktion stößt. Wussten Sie, dass
DB_NAME / ** /
() ein gültiger Funktionsaufruf ist? Die Firewall weiß auch und blockiert. Dank dieser Funktion können wir den Funktionsaufruf jedoch in zwei Parameter aufteilen!
?countryFilter[]=UA',DB_NAME(),'RU
Wir haben eine Anfrage mit
DB_NAME / *
trotzdem * /
() gesendet - WAF hat nichts verstanden, aber die Datenbank hat eine solche Anweisung erfolgreich verarbeitet.
Werte aus einer Datenbank abrufenEin Beispiel zum Abrufen der Länge eines DB_NAME () -Werts:
https://partner.steampowered.com/report_xml.php?query=QuerySteamHistory&countryFilter[]=',(SELECTCASEWHEN(len(DB_NAME())=1)THEN'UA'ELSE'qwerty'END),'
In SQL:
SELECT CASE WHEN (len(DB_NAME())= 1) THEN 'UA' ELSE 'qwerty' END
Nun, menschlich:
DB_NAME() "1", “UA”, “qwerty”.
Das heißt, wenn der Vergleich wahr ist, erhalten wir im Gegenzug Statistiken für das Land „UA“. Es ist nicht schwer zu erraten, dass wir früher oder später den richtigen Wert finden, wenn wir Werte von 1 bis unendlich überschreiten.
Auf die gleiche Weise können Sie über Textwerte iterieren:
DB_NAME() “a”, "UA", "qwerty".
Normalerweise wird die Funktion "Teilzeichenfolge" verwendet, um das N-te Zeichen zu erhalten, aber WAF hat es hartnäckig blockiert. Hier kam die Kombination zur Rettung:
right(left(system_user,N),1)
Wie funktioniert es Wir erhalten N Zeichen des Wertes von system_user, von dem wir das letzte nehmen.
Stellen Sie sich vor, system_user = "steam". So sieht es aus, wenn man den dritten Charakter bekommt:
left(system_user,3) = ste right(“ste”,1) = e
Mit einem einfachen Skript wurde dieser Prozess automatisiert und ich erhielt den Hostnamen, den Systembenutzer, die Version und die Namen aller Datenbanken. Diese Informationen sind mehr als genug (letzteres ist sogar überflüssig, aber es war interessant), um Kritikalität zu demonstrieren.
Nach 5 Stunden wurde die Sicherheitsanfälligkeit behoben, aber der Teststatus wurde nach 8 Stunden festgelegt, und verdammt noch mal, für mich waren es sehr schwierige 3 Stunden, für die mein Gehirn die Phasen von der Verweigerung bis zur Akzeptanz überstanden hat.
Erklärung der ParanoiaDa die Sicherheitsanfälligkeit nicht als akzeptiert eingestuft wurde, glaubte ich, dass die Leitung meinen Bericht noch nicht erreicht hatte. Aber sie haben den Fehler behoben, was bedeutet, dass sie ihn vor mir hätten registrieren können.
2. Erhalten Sie alle Schlüssel zu jedem Spiel
In der Steam-Partneroberfläche gibt es eine Funktion zum Generieren von Spielschlüsseln.
Sie können den generierten Schlüsselsatz mithilfe der folgenden Anfrage herunterladen:
https://partner.steamgames.com/partnercdkeys/assignkeys/ &sessionid=xxxxxxxxxxxxx&keyid=123456&sourceAccount=xxxxxxxxx&appid=xxxxxx&keycount=1&generateButton=Download
In dieser Anforderung ist der Parameter
keyid die ID des Schlüsselsatzes, und
keycount ist die Anzahl der Schlüssel, die aus diesem Satz abgerufen werden müssen.
Natürlich
streckten meine Hände sofort die Hand aus, um eine andere
Schlüssel-ID einzugeben , aber als Antwort erhielt ich eine Fehlermeldung: „
CD-Schlüssel konnten nicht generiert werden: Keine Zuweisung für den Benutzer. ". Es stellte sich heraus, dass nicht alles so einfach war, und Steam überprüfte, ob ich den angeforderten Schlüsselsatz besaß. Wie bin ich um diesen Test herumgekommen? Achtung ...
keycount=0
Eine Datei mit 36.000 Schlüsseln für das Spiel Portal 2 wurde generiert. Wow.
Nur in einem Satz war diese Anzahl von Schlüsseln. Und alle Sets im Moment mehr als 430.000. Beim
Durchsuchen der
Keyid- Werte
war ich ein potenzieller Angreifer, der alle Schlüssel herunterladen konnte, die jemals von Steam-Spieleentwicklern generiert wurden.
Schlussfolgerungen
- Kostspielige WAF-Systeme von Top-Unternehmen sind weit davon entfernt, die Sicherheit Ihrer Webanwendungen zu gewährleisten.
- Wenn Sie ein Insektenjäger sind, versuchen Sie, so tief wie möglich einzudringen. Je weniger Benutzer Zugriff auf eine Schnittstelle haben, desto wahrscheinlicher ist es, dass in dieser Schnittstelle eine Sicherheitsanfälligkeit festgestellt wird.
- Entwickler und Geschäftsinhaber, es gibt keine absolut sicheren Anwendungen! Aber du hältst fest. Gute Laune!
Aber im ErnstMachen Sie Pentests, zahlen Sie für Schwachstellen, denken Sie strategisch.