Einführung
GitLab ist ein Open-Source-Code-Repository-System für die Softwareentwicklung, das in erster Linie von großen Unternehmen für die Verwaltung von DevOps- und anderen damit verbundenen Softwareprojekten verwendet wird. Das Hauptangebot von GitLab wird von der Firma GitLab selbst verwaltet und gehostet; sie bietet auch eine selbst gehostete Version ihres Produkts sowohl für Communities als auch für Unternehmen mit unterschiedlichen Support-Levels an.
Am 07. Mai 2021 meldete ein Forscher namens "vakzz" (William Bowling) über das Bug Bounty-Programm von HackerOne einen bösen Fehler, der die Unternehmens- und Community-Software von GitLab betraf. Die GitLab-Ingenieure haben das Problem umgehend behoben, und die Schwachstelle schien für einige Monate unter dem Radar zu verschwinden. Bis ein Benutzer auf Twitter berichtete, dass ein Botnet mit Tausenden von kompromittierten GitLab-Instanzen eine massive DDoS-Kampagne startete und mehr als ein Terabit an Daten pro Sekunde generierte(das sind 75.000 ZD/m (Zip Disks pro Minute)).
Was ist das Problem?
Dem ursprünglichen Bericht zufolge werden Bilder, die auf den GitLab-Server hochgeladen werden, durch ein Perl-Tool namens ExifTool geleitet, um unbrauchbare Metadaten zu entfernen. Leider unterstützt ExifTool auch ein DjVu-Dateiformat, das benutzerdefinierte S-Ausdrücke verarbeitet, eine LISP-ähnliche Auswertungssprache, die in bestimmten Abschnitten der DjVu-Datei gefunden wird. Ein verwandter Fehler, CVE-2021-22204, wurde bereits im April 2021 bekannt gegeben, wobei derselbe Forscher zeigte, dass das ExifTool DjVu Eingaben vor dem Aufruf der Perl-Funktion eval() nicht ordnungsgemäß bereinigt, was eine benutzergesteuerte, beliebige Perl-Codeausführung (Remote Code Execution) ermöglicht. William Bowling hat in seinem Blog einen ausgezeichneten Überblick über die Forschung, die zu diesen Ergebnissen geführt hat, geschrieben.
Zum Zeitpunkt der Erstellung dieses Berichts fand Censys 20.524 Hosts mit Internetzugang, auf denen 20.565 Dienste liefen, die als verwundbare Version der GitLab-Server-Software identifiziert wurden. Auf den meisten Hosts lief Version 11.11 mit über 1.400 Vorkommen, dicht gefolgt von Version 13.1 und 12.1 mit rund 1.300 Hosts.
Da der GitLab-Server über keine Funktion verfügte, mit der wir die spezifische Version der laufenden Software ermitteln konnten, haben wir eine effektive Methode zur Identifizierung und zum Fingerprinting entwickelt, bei der wir (buchstäbliche) Artefakte aus der Build-Pipeline von GitLab verwenden.
GitLab startet automatisch eine Reihe von Aufträgen, die die GitLab-Software kompilieren und testen, sobald ein Code-Commit markiert wird. Ein Teil dieses Build-Prozesses ist ein Job namens "compile-production-assets
", das im Verzeichnis ".gitlab/ci/frontend.gitlab-ci.yml
"dessen Ziel es ist, die öffentlichen Assets des Produkts (Bilder und CSS-Dateien) in einem Ausgabeordner zusammenzufassen und zu kompilieren. Da diese Dateien ohne Authentifizierung öffentlich zugänglich sind und in einem offenen GitLab-Website-Index referenziert werden (und somit über Censys durchsuchbar sind), eignen sie sich perfekt für ein Ad-hoc-Fingerprinting.
Viele dieser generierten Dateinamen ändern sich kaum (z. B. das Logo), aber einige schon. Zum Beispiel scheint "public/assets/application.css" für jede kleinere Version einen anderen generierten Dateinamen zu haben. Darüber hinaus enthalten die Namen dieser Dateien eine 64-Byte-Zeichenkette in ASCII-HEX-Kodierung, die an den ursprünglichen Dateinamen angehängt ist, so dass wir diese Dateinamen dem Build-Job und der Softwareversion zuordnen können, die sie erzeugt haben. Unser Ziel war es also, jeden mit einem Tag versehenen Build (mit einer verwundbaren Version) der GitLab-Software herunterzuladen, dann den Namen des erzeugten Dateinamens mit dem Präfix "public/assets/application-" und der Erweiterung "css" zu notieren und diesen Dateinamen mit dem Tag des Builds zu verknüpfen. Das ist nicht perfekt, aber es reicht.
Nachdem wir jedes verwundbare Image von docker.io heruntergeladen hatten (alle 247 Major-, Minor- und Release-Kandidaten), führten wir ein kleines Shell-Skript aus, das eine Tabelle mit Tag-Namen zu eindeutigen Dateinamen generierte, was zu 44 eindeutigen Dateinamen-Hashes führte:
#!/usr/bin/env bash
assetdir="/opt/gitlab/embedded/service/gitlab-rails/public/assets"
tags=$(cat ./vulnerable_tags.txt)
for tag in $tags; do
filename=$(docker run --rm -it --entrypoint "" gitlab/gitlab-ce:$tag ls $assetdir|egrep '^application-.*\.css' | grep -v \.gz)
echo $tag,$filename
done
Nach einer manuellen Datenbereinigung begannen wir mit der Suche, indem wir eine BigQuery-SQL-Anweisung generierten, um alle laufenden GitLab-Dienste zusammen mit dem gesuchten Dateinamen zu finden. Die Ergebnisse wurden in einer temporären Datenbanktabelle für die weitere Analyse gespeichert. (Eine Funktion, auf die Censys Unternehmenskunden Zugriff haben):
WITH
results AS (
SELECT
DISTINCT host_identifier.ipv4 AS host,
autonomous_system.asn AS asn,
autonomous_system.name AS asn_name,
location.country_code AS cc,
location.coordinates.latitude AS lat,
location.coordinates.longitude AS long,
REGEXP_EXTRACT(SAFE_CONVERT_BYTES_TO_STRING(svc.http.response.body),
".*(/assets/application-[a-f0-9]{64}.css).*") AS version,
FROM
`censys-io.universal_internet_dataset.universal_internet_dataset`
JOIN
UNNEST(services) svc
JOIN
UNNEST(svc.http.response.html_tags) x
WHERE
DATE(snapshot_date) = "2021-11-03"
AND SAFE_CONVERT_BYTES_TO_STRING(svc.http.response.body)LIKE '%/assets/application-%.css%'
AND SAFE_CONVERT_BYTES_TO_STRING(x) LIKE '%/assets/gitlab_logo-%'
ORDER BY
version DESC )
SELECT
*
FROM
results;
Der nächste Schritt bestand darin, die von der obigen Abfrage generierten Daten zu nehmen und die gefundenen Dateinamen der jeweiligen Version zuzuordnen, wie sie in den Docker-Images zu sehen ist, was zu folgendem Ergebnis führte
Dateiname |
Abgebildete Version |
Host-Zahl |
/assets/application-5440e2dd89d3c803295cc924699c93eb762e75d42178eb3fe8b42a5093075c71.css |
11.11 |
1448 |
/assets/application-02aa9533ec4957bb01d206d6eaa51d762c7b7396362f0f7a3b5fb4dd6088745b.css |
13.10 |
1416 |
/assets/application-450cbe5102fb0f634c533051d2631578c8a6bae2c4ef1c2e50d4bfd090ce3b54.css |
12.10 |
1322 |
/assets/application-45b2cf643afd34888294a073bf55717ea00860d6a1dca3d301ded1d0040cac44.css |
12.9 |
1277 |
/assets/application-d161b6e25db66456f8e0603de5132d1ff90f9388d0a0305d2d073a67fd229ddb.css |
13.9 |
1157 |
/assets/application-52560ba2603619d2ff1447002a60dcb62c7c957451fb820f1894e1ce7c23821c.css |
13.8 |
1000 |
/assets/application-051048a171ccf14f73419f46d3bd8204aa3ed585a72924faea0192f53d42cfce.css |
13.6 |
985 |
/assets/application-a0c92bafde7d93e87af3bc2797125cba613018240a9f5305ff949be8a1b16528.css |
13.7 |
833 |
/assets/application-c8d8d30d89b00098edab024579a3f3c0df2613a29ebcd57cdb9a9062675558e4.css |
13.0 |
736 |
/assets/application-4abc4e078df94075056919bd59aed6e7a0f95067039a8339b8f614924d8cb160.css |
13.1 |
700 |
/assets/application-def1880ada798c68ee010ba2193f53a2c65a8981871a634ae7e18ccdcd503fa3.css |
12.3 |
699 |
/assets/application-969119f639d0837f445a10ced20d3a82d2ea69d682a4e74f39a48a4e7b443d5e.css |
13.4 |
639 |
/assets/application-455d114267e5992b858fb725de1c1ddb83862890fe54436ffea5ff2d2f72edc8.css |
13.3 |
605 |
/assets/application-3407a4fd892e9d5024f3096605eb1e25cad75a8bf847d26740a1e6a77e45b087.css |
12.4 |
594 |
/assets/application-aeddf31361633b3d1196c6483f25c484855e0f243e7f7e62686a4de9e10ec03b.css |
12.6 |
567 |
/assets/application-bec9544b57b8b2b515e855779735ad31c3eacf65d615b4bfbd574549735111e7.css |
12.7 |
557 |
/assets/application-a9308f85e95b00007892d451fd9f6beabcd8792b4c5f8cd7524ba7e941d479c9.css |
13.2 |
549 |
/assets/application-77566acc818458515231d0a82c131a42890d771ea998b9f578dc38e0eb7e517f.css |
12.0 |
509 |
/assets/application-3cbf1ae156fa85f16d4ca01321e0965db8cfb9239404aaf52c3cebfc5b4493fb.css |
11.9 |
458 |
/assets/application-bf1ba5d5d3395adc5bad6f17cc3cb21b3fb29d3e3471a5b260e0bc5ec7a57bc4.css |
13.5.0-ce.0 |
436 |
/assets/application-d56f0577fbbbd6f159e9be00b274270cb25b60a7809871a6a572783b533f5a3c.css |
12.2 |
409 |
/assets/application-38981e26a24308976f3a29d6e5e2beef57c7acda3ad0d5e7f6f149d58fd09d3d.css |
11.10.5-ce.0 |
406 |
/assets/application-4a081f9e3a60a0e580cad484d66fbf5a1505ad313280e96728729069f87f856e.css |
12.8.0-ce.0 |
371 |
/assets/application-dc6b3e9c0fad345e7c45a569f4c34c3e94730c33743ae8ca055aa6669ad6ac56.css |
12.8 |
367 |
/assets/application-d812b9bf6957fafe35951054b9efc5be6b10c204c127aa5a048506218c34e40f.css |
12.5 |
359 |
/assets/application-78812856e55613c6803ecb31cc1864b7555bf7f0126d1dfa6f37376d37d3aeab.css |
12.1 |
325 |
/assets/application-93ebf32a4bd988b808c2329308847edd77e752b38becc995970079a6d586c39b.css |
11.10 |
300 |
/assets/application-73a21594461cbc9a2fb00fc6f94aec1a33ccf435a7d008d764ddd0482e08fc8d.css |
12.5.0-ce.0 |
255 |
/assets/application-340c31a75c5150c5e501ec143849adbed26fed0da5a5ee8c60fb928009ea3b86.css |
12.1.0-ce.0 |
250 |
/assets/application-be9a23d3021354ec649bc823b23eab01ed235a4eb730fd2f4f7cdb2a6dee453a.css |
13.5 |
233 |
/assets/application-34031b465d912c7d03e815c7cfaff77a3fa7a9c84671bb663026d36b1acd3f86.css |
11.11.0-rc4 |
224 |
/assets/application-67ac5da9c95d82e894c9efe975335f9e8bdae64967f33652cd9a97b5449216d2.css |
11.1 |
171 |
/assets/application-7f1c7b2bfaa6152740d453804e7aa380077636cad101005ed85e70990ec20ec5.css |
13.3.8-ce.0 |
130 |
/assets/application-f154ef27cf0f1383ba4ca59531058312b44c84d40938bc8758827023db472812.css |
13.2.0-ce.0 |
61 |
/assets/application-f9ab217549b223c55fa310f2007a8f5685f9596c579f5c5526e7dcb204ba0e11.css |
13.4.0-ce.0 |
60 |
/assets/application-ec9dfedd7bd44754668b208858a31b83489d5474f7606294f6cc0128bb218c6d.css |
13.1.0-ce.0 |
60 |
/assets/application-292ca64c0c109481b0855aea6b883a588bd293c6807e9493fc3af5a16f37f369.css |
11.9.0 |
46 |
/assets/application-39fdbd63424a09b5b065a6cc60c9267d3f49950bf1f1a7fd276fe1ece4a35c09.css |
12.7.0-ce.0 |
43 |
/assets/application-9c095c833db4364caae1659f4e4dcb78da3b5ec5e9a507154832126b0fe0f08e.css |
11.11.0-rc1.ce.0 |
6 |
/assets/application-79837fd1939f90d58cc5a842a81120e8cecbc03484362e88081ebf3b7e3830e9.css |
13.7.0-rc3.ce.0 |
1 |
/assets/application-2eaf7e76aa55726cc0419f604e58ee73c5578c02c9e21fdbe7ae887925ea92ae.css |
11.10.0-rc7.ce.0 |
1 |
Wir können auch eine etwas ausführliche Censys -Suchabfrage mit den obigen Hashes erstellen, um die Hosts, die diesen Bedingungen entsprechen, besser anzuzeigen, indem wir sowohl nach dem Dateinamen gitlab_logo als auch nach der Liste der übereinstimmenden Dateien suchen.
Während die Verwendung dieser ausgenutzten Hosts für DDoS an sich schon schrecklich ist, gab es auch Diskussionen über andere Massenangriffe, bei denen zufällige Admin-Benutzer gefunden wurden. Ein Angreifer könnte zum Beispiel Hintertüren und anfällige Funktionen in den Quellcode von Projekten einschleusen, die von diesen Diensten gehostet werden. In diesem Fall könnte selbst der am sichersten geschriebene Code zu einem administrativen Albtraum werden.
Der Angriff selbst ist einfach, und es gibt leicht zugängliche Exploits, was dieses Problem zu einem schwerwiegenden Problem macht, das sofort behoben werden sollte. Wir hoffen, dass die in diesem Beitrag vorgestellten Daten Ingenieuren und Administratoren dabei helfen werden, anfällige GitLab-Instanzen zu identifizieren und zu patchen.
Was kann ich dagegen tun?
Referenzen