- Die Checksum Database von Go und der öffentliche Module-Proxy akzeptieren auch Repositories ohne Go-Code, wodurch ein Pfad entsteht, beliebige Git-Repository-Daten in die Go-Infrastruktur einzuspeisen und später wieder herunterzuladen
- Eine Anfrage an
sum.golang.org/lookup/$module@$versionholt bei einer noch nicht protokollierten Modulversion das Modul vom Origin-Server, wobei in diesem Prozess auch beiproxy.golang.orgdie ZIP-Datei des Repositories bereitgestellt wird - Das Ruby-Repository von Homebrew und ein Fork eines Rust-Repositories befanden sich in der Checksum Database, und ein Experiment zeigte erfolgreich, dass sich nicht nur neue Go-Module, sondern auch Repositories ohne Go-Dateien per Pseudo-Version registrieren lassen
- Für Modul-ZIPs gilt sowohl komprimiert als auch unkomprimiert ein Limit von maximal 500 MiB, was dennoch groß genug ist, um Download-Beschränkungen auf Entwicklerrechnern und in CI/CD zu umgehen, Payloads zu speichern oder C2 zu implementieren
- Von rund 1,59 Millionen eindeutigen Pfaden in
sum.golang.orgentfallen etwa 1,51 Millionen auf GitHub-Pfade, also rund 95 %, was sowohl die GitHub-Abhängigkeit des Go-Ökosystems als auch das Missbrauchspotenzial des öffentlichen Proxys offenlegt
In der Go-Checksum-Database gefundene Nicht-Go-Repositories
- Beim Durchsehen der Checksum Database von Go fiel in der Tabelle
modulesauf, dassgithub.com/homebrew/homebrew-coresehr häufig vorkommtgithub.com/homebrew/homebrew-core: 39.438github.com/Homebrew/homebrew-core: 30.896github.com/concourse/concourse: 25.372github.com/openshift/release: 24.065github.com/cilium/cilium: 22.138
- Das Homebrew-Repository ist als Ruby-Repository bekannt, und weder im Repository noch in einer geklonten Kopie wurden
go.mododer Go-Quelldateien gefunden - Der Unterschied in der Groß-/Kleinschreibung lässt sich durch die Regeln zur Case Encoding in der Go-Dokumentation erklären
- Großbuchstaben werden als
!plus entsprechender Kleinbuchstabe kodiert, sodass auf Dateisystemen ohne Unterscheidung von Groß- und Kleinschreibung sowohlexample.com/Mals auchexample.com/mgespeichert werden können
- Großbuchstaben werden als
- Auch
github.com/Edu4rdSHL/rust-headless-chrometaucht in der Checksum Database auf, obwohl es sich um einen nicht mit Go verbundenen Fork eines Rust-Repositories handelt
Wie /lookup Repositories abruft
- Laut Go Modules Reference der Go-Modul-Dokumentation ruft der Go-Befehl beim Abfragen der Checksum Database zunächst die Datensätze über den Endpunkt
/lookupab - Wenn eine Modulversion noch nicht im Log verzeichnet ist, versucht die Checksum Database vor der Antwort, das betreffende Modul vom Origin-Server zu holen
- Das Endpunktformat lautet
$base/lookup/$module@$version- Zur
$versionvon$modulewerden die Nummer des Log-Eintrags,go.sum-Zeilen und eine signierte Baumbeschreibung zurückgegeben
- Zur
- Bei der Abfrage einer Pseudo-Version von
github.com/homebrew/homebrew-corewerden ein Checksum-Datensatz und der Hash vongo.modzurückgegeben - Wenn ein Repository kein Versions-Tag hat, kommen die Regeln für Pseudo-Versionen von Go zur Anwendung
Experiment zur Registrierung eines neuen Go-Moduls
- Nach dem Anlegen des neuen Go-Moduls
github.com/gdbinit/fluxmatterwurde mit einerlookup-Anfrage geprüft, ob es registriert ist - Die Abfrage von
@latestgab einen Fehler zurück, dass es sich nicht um eine kanonische Version handeltbad request: version "latest" is not canonical
- Die Abfrage von
@v0.0.0lieferte einen Fehler, dass diese Revision unbekannt seinot found: ... invalid version: unknown revision v0.0.0
- Nach erneuter Synchronisierung und Abfrage der Checksum Database war das Modul jedoch registriert
github.com/gdbinit/fluxmatter|v0.0.0-20240524163826-a7e64ffd69f2|2024-05-24T16:40:51.203837Z
proxy.golang.org/github.com/gdbinit/fluxmatter/@latestlieferte die Pseudo-Version und Informationen zum GitHub-Origin, und die ZIP-Datei dieser Version ließ sich herunterladen und auf Komprimierung prüfen- Für das anfängliche Seeding musste keine exakte Version angegeben werden; schon eine Lookup-Abfrage, die einen Modulpfad und etwas versionsähnlich Aussehendes enthält, reicht aus
Auch Repositories ohne Go-Code werden in den öffentlichen Proxy geladen
- Dasselbe Experiment gelang auch mit dem Repository
github.com/gdbinit/readmem, das keinerlei Go-Code enthält - Die
lookup-Anfrage meldete zwar, dass die Revisionv0.0.0unbekannt sei, doch in der Checksum Database wurde das Repository als Pseudo-Version registriertgithub.com/gdbinit/readmem|v0.0.0-20131006075740-407cb0a56933|2024-05-24T16:45:35.88456Z
@latestbeiproxy.golang.orggab die Pseudo-Version und Informationen zur Git-Origin des Repositories zurück- Die heruntergeladene ZIP-Datei enthielt keine Go-Dateien, sondern unter anderem
Entitlements.plist,README, Xcode-Projektdateien undmain.c - Das Experiment nutzte zwar ein GitHub-Repository, könnte aber grundsätzlich auch mit anderen Hosting-Seiten funktionieren, sofern das VCS unterstützt wird
GitHub-Abhängigkeit und Größenbeschränkungen
- Die Zahl eindeutiger Pfade in der Checksum Database betrug 1.591.375, davon waren 1.515.957 Pfade
github.com% - Rund 95 % der eindeutigen Pfade werden auf GitHub gehostet {p:95}
- Diese Zahl ist eine rohe Statistik, bei der weder Forks noch Nicht-Go-Code-Projekte herausgefiltert wurden
- Für Go-Modul-ZIPs gelten die Beschränkungen für Dateipfade und -größen
- Modul-ZIP-Dateien: maximal 500 MiB
- gesamte unkomprimierte Dateigröße ebenfalls maximal 500 MiB
go.mod-Datei: maximal 16 MiBLICENSE-Datei ebenfalls maximal 16 MiB
- Diese Limits sollen Denial-of-Service-Angriffe gegen Nutzer, Proxys und andere Teile des Modul-Ökosystems abmildern
- Im Hinblick auf Missbrauchsmöglichkeiten sind 500 MiB dennoch groß genug
Mögliche Missbrauchsszenarien
- Der öffentliche Go-Proxy könnte auf Entwicklerrechnern oder CI/CD-Servern genutzt werden, um Beschränkungen für Download-Ziele zu umgehen
- vorausgesetzt, es gibt kein privates
GOPROXY - Schadsoftware könnte Payloads in ein Repository hochladen und sie bei Bedarf über den Proxy abrufen
- Selbst wenn die ursprüngliche Quelle verschwindet, könnte im Eintrag der Checksum Database nur eine kleine Spur verbleiben
- vorausgesetzt, es gibt kein privates
- Ein DoS gegen
proxy.golang.orgkönnte schwer praktisch umzusetzen sein- Der Proxy kann dazu gebracht werden, beliebige Git-Repositories herunterzuladen
- Ein denkbarer Angriff wäre, viele GitHub-URLs zu sammeln und dann massenhaft Anfragen an die
lookup-API zu senden - Die Server-Implementierung ist unbekannt, aber es könnte Begrenzungen für parallele Verarbeitung geben, etwa über eine Work Queue
- Auch Schutzmechanismen für GitHub-Bandbreite könnten greifen
- Ebenso ist ein auf Speicherplatz zielender DoS denkbar, bleibt aber Spekulation
- C2 (Command and Control) lässt sich leicht auf
proxy.golang.orgaufbauen- Über eine
@latest-Abfrage kann die neueste Version eines bestimmten Moduls ermittelt werden - Die Payload kann eine einfache Datei sein oder in
go.modbzw. in Go-Quelldateien versteckt werden - Um die Nutzung eines einzelnen Repositories zu vermeiden, könnte eine Modul-DGA verwendet werden
- Über eine
C2-Download-Ablauf
- Damit ein Implant Befehle abrufen kann, müsste es nur diese Schritte ausführen
- Anfrage an
https://proxy.golang.org/module_path/@latest - Aus dem JSON-Ergebnis die Pseudo-Version oder die Version extrahieren
- Mit
https://proxy.golang.org/module_path/@v/version.zipdie ZIP-Datei herunterladen - Den ZIP-Inhalt entpacken und die Befehle parsen
- Anfrage an
- Dieser Ablauf ist so simpel, dass er sich in weniger als 300 Zeilen Go-Code umsetzen lässt
Fazit und offene Fragen
- Die Go-Checksum-Database und der Proxy können gemäß dem dokumentierten Verfahren nicht protokollierte Module vom Origin-Server holen und speichern
- Der aktuelle Zustand wirkt nicht wie ein schwerwiegendes Problem der Go-Infrastruktur, lässt sich aber leicht missbrauchen und bietet Raum für Verbesserungen
- Es könnte dokumentierte oder nicht öffentliche Gründe dafür geben, dass auch Nicht-Go-Repositories in Proxy und Checksum Database aufgenommen werden können
- Um festzustellen, ob dies bereits aktiv missbraucht wird, müssten rund 1,6 Millionen eindeutige Repositories und nach aktuellem lokalen Datenbankstand etwa 22 Millionen Einträge untersucht werden
- Warum einige legitime Nicht-Go-Projekte in der Database auftauchen, bleibt vorerst eine offene Frage
1 Kommentare
Hacker-News-Meinungen
Ein Onlinedienst, bei dem Nutzer Inhalte hochladen und diese Inhalte öffentlich sichtbar erscheinen, wird am Ende für Command-and-Control, Urheberrechtsverletzungen und CSAM-Hosting genutzt.
Das gilt besonders für Dienste, die neben Datei-Hosting noch wichtige andere Zwecke erfüllen und sich deshalb schwer blockieren lassen; passiert ist das bereits bei Twitter[1], Telegram[2] und der PGP-Key-Infrastruktur[3] – von offensichtlichen Zielen wie GitHub ganz zu schweigen.
[1] https://pentestlab.blog/2017/09/26/command-and-control-twitt...
[2] https://www.blazeinfosec.com/post/leveraging-telegram-as-a-c...
[3] https://torrentfreak.com/openpgp-keyservers-now-store-irremo...
Bei Gmail wurden Zugangsdaten verteilt, damit sich die Leute einloggen konnten, und dann lasen sie per IMAP die hochgeladenen Anhänge.
Ich war früher Google SAD-SRE (Spam, Abuse, Delivery).
Es wäre auch möglich, Dateien als Base64 in Python-Code-Strings zu kodieren.
Ich bin Googler, das ist meine persönliche Meinung, und ich kenne mich in diesem Bereich nicht gut aus.
Ich hoffe, dass das Go-Team mit den GCP- und Drive-Teams zusammengearbeitet hat, denn Hosting bösartiger Dateien ist ein Problem, mit dem Google ständig zu tun hat.
Es unterscheidet sich nicht wesentlich von anderen Endpunkten, über die Google bereits zulässt, dass Leute beliebige Daten einstellen.
Google ist sehr gut darin, dass zentrale Teams Infrastruktur betreiben und unternehmensweit bereitstellen. Außer bei Messenger-Apps jedenfalls; reine Spekulation, aber ich vermute, dass das Go-Team einen internen Blob-Speicher nutzt und es auch ein internes Infrastrukturteam gibt, das Missbrauchsbekämpfung und Datei-Scanning automatisch übernimmt.
Auf PyPI gibt es auch ziemlich viele Nicht-Python-Projekte.
Weil Python-Nutzer Library-Code unter Umständen nicht kompilieren können, braucht man die Möglichkeit, Wheels als kompilierte Binaries zu verteilen.
Solcher Code ist oft in C geschrieben, aber Golang[1] geht ebenfalls; ich finde kein Beispiel, glaube aber, gesehen zu haben, dass es auch zur Verteilung von Anwendungen und nicht nur von Libraries genutzt wurde.
Eine App in C zu schreiben, sie auf PyPI hochzuladen und den Nutzern zu sagen, sie sollen sie mit
pip installinstallieren, ist ziemlich cool.[1] https://github.com/popatam/gopy_build_wheel_example
Dann wäre es Linux, aber
lswäre in Python geschrieben; solche Spielchen sollte man wahrscheinlich lieber nicht spielen.pipverlangt hat, dass man sich in einer Umgebung wie venv/virtualenv/pipenv/pyenv befindet, um ein Paket herunterzuladen, wäre dieser Anwendungsfall wohl deutlich nützlicher gewesen.pip install cmake, und proprietäre Binaries gehen ebenfalls, etwa mitpip install nvidia-cudnn-cu12.Das ist einer der Gründe, warum ich Homebrew komplett aufgeben konnte.
Vielleicht ist das naiv, aber ich verstehe nicht, wie sich das vom Hochladen einer Datei in ein GitHub-Repository unterscheidet.
Besteht der Unterschied nur darin, dass man bei GitHub ein Konto erstellen muss? Auch auf GitHub kann man beliebige Daten speichern, und es gibt kein 500-MB-Limit.
Das Modulsystem von CUE wird endlich veröffentlicht, und MVS ähnelt Go, ist aber auf OCI-Infrastruktur aufgebaut.
Falls man sich für Dependency-Management-Systeme interessiert, sind hier ein paar Links.
proposal: https://github.com/cue-lang/proposal/tree/main/designs/modul...
custom registry: https://cuelang.org/docs/tutorial/working-with-a-custom-modu...
road map: https://github.com/orgs/cue-lang/projects/10/views/8
Seit 0.9.0-alpha-5 sind Module standardmäßig aktiviert: https://github.com/cue-lang/cue/releases/tag/v0.9.0-alpha.5
Bei Go Sum stützt das Trillian-Projekt das Transparenz-Log: https://github.com/google/trillian
CUE plant, auf OCI-Optionen wie Attestations aufzusetzen.
Ich habe mit der Idee herumgespielt, mich an den golang proxy und sumdb dranzuhängen – genauer: sie zu missbrauchen –, um ein kostenloses Transparenz-Log für Checksummen beliebiger URLs zu erstellen
https://getsum.pub/
Wenn man nur ein öffentliches Transparenz-Log will, ist die öffentliche rekor-Instanz des sigstore-Projekts deutlich besser geeignet
https://www.sigstore.dev/
https://docs.sigstore.dev/logging/overview/
Vielleicht bin ich ja begriffsstutzig, aber ich verstehe nicht, was hier genau das Problem sein soll
Dass der Proxy Nicht-Go-Repositories cached, mag etwas verschwenderisch sein, aber selbst wenn er das nicht täte, könnte man ihn doch ohnehin dazu bringen, beliebige Daten zu speichern, indem man ihn Go-Repositories cachen lässt?
Wenn ich nicht irgendetwas übersehe, klingt das nach einer völligen Nicht-Nachricht
Die Neuigkeit hier scheint nur zu sein, dass ein öffentlicher Proxy ohne Sicherheitsmechanismen entgegennimmt, was er proxen soll, und es dann auf unsichere Weise öffentlich bereitstellt
Im Artikel heißt es, manche überwachten Netzwerke könnten golang-proxy-URLs mehr vertrauen als beliebigen Web-URLs, wodurch sich das etwa zur Umgehung von Reputationsfiltern nutzen ließe; solche Methoden gibt es aber bereits in vielen Varianten, und diese hier wirkt nicht besonders speziell
Off-topic, aber der Domainname verhieß wegen des Wortspiels nichts Gutes, also habe ich put.as geprüft, und es war im Großen und Ganzen das, was ich erwartet hatte
Das ist ein bereits bekanntes Issue: https://github.com/golang/go/issues/31866
.mod- und eine.go-Datei im Root hinzufügen, oder?Er und Aaron haben Athens gebaut, und soweit ich weiß, hat Marwan die erste Implementierung des Go-Download-Protokolls geschrieben, auf der Athens basiert
Interessant an diesem Issue ist, dass Athens bereits den erwähnten Befehl
go mod download -jsonals Vorabprüfung für die Modulvalidierung verwendetIm Großen und Ganzen liefert Athens ein Repository aus, wenn es als Modul durch die Go-Modulbefehle kommt
Etwas formaler gesagt: Man muss Modulversionen, Pseudoversionen und
+incompatibleerzeugen können, und dieses Modul samt Abhängigkeiten muss gültige Checksummen ergebenModul-Checksummen haben derzeit damit zu tun, die
.mod-Datei, alle Dateien sowie rekursiv jede Abhängigkeit einzubeziehenWie der Autor sagt, reicht deshalb schon ein grundlegendes Go-Programm, um konstruktionsbedingt viel Platz für beliebige Dateien zu haben
Das W3C hat die Grundlage dafür gelegt, dass alles im Web stark cachebar sein kann; daher ist es seltsam, dass es so wenige universelle Proxy-Caches gibt
Senden Publisher unnötigerweise kurze
Cache-Control: max-age- oderVary: Cookie-Antworten?Zahlen ISPs zu viel für Transit im Vergleich zu Peering?
Bei Nicht-HTTPS-Sites könnte ein ISP-Proxy zum Beispiel Werbung einfügen
Software-Downloads haben normalerweise Signaturen und Checksummen, aber bei beliebigen Inhalten gibt es so etwas kaum