Hintergründe zum GitHub-Hack

Sprachen  –  13 Kommentare

Ein russischer Programmierer hat vor Kurzem das populärste Open-Source-Code-Repository GitHub gehackt. Ohne böse Absicht, dafür aber mit Folgen.

Am 1. März öffnete Egor Homakov (GitHub-Nutzer @homakov) im – auf GitHub gehosteten – Ruby-on-Rails-Projekt das Issue 5228 ("Mass assignment vulnerability – how to force dev. define attr_accesible?"), um damit auf ein potentielles Problem mit Attribut-Zuweisungen hinzuweisen. Es folgte der übliche kleine Flamewar, doch der von ihm erwartete Ruck durch die Rails-Community blieb aus. Um die Gefahr zu veranschaulichen, nutzte er wenige Tage später (am Sonntag, den 4. März) genau diese Technik für einen Hack auf GitHub, das selbst in Ruby-on-Rails programmiert ist. Durch einen simplen Hack hatte er so die volle Kontrolle über das Ruby-on-Rails-Projekt bekommen.

Darum geht es

Die Mass-Assignment Vulnerability ist ein alter Hut in der Rails-Community und hängt mit dem Standardverhalten von Ruby-on-Rails zusammen. Dort gilt per Default eine Mass-Assignment Whitelist auf alle Attribute eines ActiveRecord-Models. Man kann also per HTTP-PUT alle Attribute eines ActiveRecord-Models mit Inhalt füllen. Dies ist per se ein Feature, das es ermöglicht, per RESTful HTTP-Aufruf ActiveRecord-Objekte leicht zu füllen oder auszulesen. Häufig will man aber nicht alle Attribute öffentlich lesbar beziehungsweise schreibbar haben und dann muss man auf die Sicherheit achten. Denn erst wenn der Entwickler mit der Methode attr_accessible gezielt bestimmte Attribute auf die Whitelist setzt, wird diese Voreinstellung deaktiviert.

Was bedeutet das in der Praxis? Beipielhaft sei ein Online-Shop mit einem User-Objekt vorgestellt. Ein Anwender hat als Attribute einen Login (login) und einen Kreditrahmen (credit_line). Jeder Nutzer kann sich selbst anlegen und auch seinen Login verändern, den eigenen Kreditrahmen sollte er natürlich nicht anpassen können.

---cut---
rails new shop
cd shop
rails generate scaffold User login:string 'credit_line:decimal{7,2}'
rake db:migrate
---cut---

Ein böswilliger Angreifer kann jetzt von außen einen neuen Nutzer anlegen und ihm direkt einen Kreditrahmen von 1 000 freischalten:

curl -v -H "Accept: applicon/json"-H "Content-type: application/json" 
-X POST -d ' {"login": "Mustermann", "credit_line": 1000}'
http://0.0.0.0:3000/users

Über die Rails-Console kann man jetzt einen Blick auf den neuen User mitsamt des Kreditrahmens anschauen:

---cut---
evil_hacker:shop sw$ rails console
Loading development environment (Rails 3.2.1)
1.9.2-p290 :001 > puts User.first.to_yaml
User Load (0.3ms) SELECT "users".* FROM "users" LIMIT 1
--- !ruby/object:User
attributes:
id: 1
login: Mustermann
credit_line: 1000.0
created_at: 2012-03-05 11:24:53.666888000Z
updated_at: 2012-03-05 11:24:53.666888000Z
=> nil
1.9.2-p290 :004 > exit
---cut---

Um diesen recht plumpen Angriff zu verhindern, sollte man immer mit attr_accessible die von außen erreichbaren Attribute bestimmen. Im Beispiel wäre das login in der Datei /app/models/user.rb:

---cut---
class User < ActiveRecord::Base
attr_accessible :login
end
---cut---

Will man jetzt einen zweiten Eintrag (ebenso mit einer 1000er-Kreditlinie) anlegen

curl -v -H "Accept: applicon/json"-H "Content-type: application/json" 
-X POST -d ' {"login": "Musterfrau", "credit_line": 1000}'
http://0.0.0.0:3000/users

so wird zwar der neue User mit dem Login "Musterfrau" angelegt, aber das Attribut credit_line wird korrekt auf nil gesetzt:

---cut---
evil_hacker:shop sw$ rails console
Loading development environment (Rails 3.2.1)
1.9.2-p290 :001 > puts User.last.to_yaml
User Load (0.3ms) SELECT "users".* FROM "users" LIMIT 1
--- !ruby/object:User
attributes:
id: 2
login: Musterfrau
credit_line: !!null
created_at: 2012-03-05 11:31:31.435220000Z
updated_at: 2012-03-05 11:31:31.435220000Z
=> nil
1.9.2-p290 :004 > exit
---cut---

Richtig interessant wird die Mass-Assignment Vulnerability für Angreifer oft dadurch, dass sie damit auch auf Nested-Objekte zugreifen können. So könnte ein Angreifer den Inhalt aller mit der has_many-Methode verknüpften Warenkörbe eines bestimmten Nutzers in einem Online-Shop verändern.

Schlagabtausch auf GitHub

Dieses Verhalten hat Egor Homakov ausgenutzt und den genauen Weg in seinem Blog dokumentiert. Unter https://api.github.com/users/rails konnte er die ID des Rails-Projektes auslesen, um diese dann dafür zu benutzen, den SSH PublicKey für diesen User in der Datenbank mit seinem eigenen zu ersetzen. Damit hatte er volle Kontrolle über das Rails-Projekt auf GitHub.

Bereits am 3. März hatte Egor Homakov das GitHub-Team über die prinzipielle Lücke informiert. Das GitHub-Team hat die Lücke zwar direkt geschlossen, wenn auch anscheinend nicht vollständig (nicht in allen Modellen). Zwei Tage später konnte Homakov die Kontrolle über das Rails-Projekt übernehmen und das öffentlich mit einem Commit in den Master-Branch von Ruby-on-Rails belegen. Zusätzlich hat er Humor bewiesen – mit einem neuen Issue "I'm Bender from Future." mit einem Datum aus der Zukunft. GitHub zeigte sich wenig amüsiert und schloss seinen Account. Alle GitHub-User wurden mit dem Blog-Eintrag Public Key Security Vulnerability and Mitigation über das Problem benachrichtigt. Rund vier Stunden später folgte ein zweiter Blog-Eintrag zu GitHubs "Responsible Disclosure Policy " und Hamokovs GitHub-Account wurde reaktiviert, da nach Durchsicht der Logs klar war, das er keinen Schaden angerichtet hatte und wirklich nur Sichtbarkeit für das Problem erzeugen wollte. Vermutlich haben sich die GitHub-Mitarbeiter einen ruhigeren Sonntag gewünscht. Soweit man es bis jetzt überblicken kann, wurde zumindest kein Schaden angerichtet.

Fazit

Es ist ein offenes Geheimnis, das viele Rails-Entwickler aus Bequemlichkeit (oder nur Unwissenheit) Applikationen ins Netz stellen, die anfällig für Mass-Assignment-Angriffe sind. Der GitHub-Vorfall hat gezeigt, dass selbst erfahrende Rails-Programmierer in diese Falle laufen können.

Die in Ruby-on-Rails benutzte Logik erleichtert es einem Angreifer, allein über die Analyse von URLs und des HTML-Codes von Formular-Seiten, einen entsprechenden Angriff durchzuführen. Dazu bedarf es nicht viel Hacker-Know-How. Alle Rails-Entwickler müssen daher darauf achten, ihre Applikation entsprechend abzusichern.

Sicherlich handelt es sich nicht um einen Fehler in Ruby-on-Rails. Aber die Wahl der Voreinstellungen hätte gerade für Rails-Anfänger glücklicher ausfallen können. In der Rails-Community hat Egor Hamakov die entsprechende Diskussion noch einmal angeheizt. (rl)

Stefan Wintermeyer
ist Geschäftsführer der AMOOMA GmbH und Autor des Ruby-on-Rails-Buches von Addison-Wesley (online unter ruby-auf-schienen.de).