Concourse Enumeration & Attacks
Concourse Enumeration & Attacks
User Roles & Permissions
Concourse viene fornito con cinque ruoli:
Concourse Admin: Questo ruolo è assegnato solo ai proprietari del team principale (team concourse iniziale predefinito). Gli admin possono configurare altri team (es.:
fly set-team
,fly destroy-team
...). I permessi di questo ruolo non possono essere influenzati da RBAC.owner: I proprietari del team possono modificare tutto all'interno del team.
member: I membri del team possono leggere e scrivere all'interno delle risorse del team ma non possono modificare le impostazioni del team.
pipeline-operator: Gli operatori della pipeline possono eseguire operazioni sulla pipeline come attivare build e fissare risorse, tuttavia non possono aggiornare le configurazioni della pipeline.
viewer: I visualizzatori del team hanno accesso "in sola lettura" a un team e alle sue pipeline.
Inoltre, i permessi dei ruoli owner, member, pipeline-operator e viewer possono essere modificati configurando RBAC (configurando più specificamente le sue azioni). Leggi di più al riguardo in: https://concourse-ci.org/user-roles.html
Nota che Concourse raggruppa le pipeline all'interno dei Team. Pertanto, gli utenti appartenenti a un Team saranno in grado di gestire quelle pipeline e possono esistere diversi Team. Un utente può appartenere a più Team e avere permessi diversi all'interno di ciascuno di essi.
Vars & Credential Manager
Nei file di configurazione YAML puoi configurare valori utilizzando la sintassi ((_source-name_:_secret-path_._secret-field_))
.
Dal documento: Il source-name è facoltativo, e se omesso, verrà utilizzato il gestore delle credenziali a livello di cluster, oppure il valore può essere fornito staticamente.
Il secret-field facoltativo specifica un campo sul segreto recuperato da leggere. Se omesso, il gestore delle credenziali può scegliere di leggere un 'campo predefinito' dalla credenziale recuperata se il campo esiste.
Inoltre, il secret-path e il secret-field possono essere racchiusi tra virgolette doppie "..."
se contengono caratteri speciali come .
e :
. Ad esempio, ((source:"my.secret"."field:1"))
imposterà il secret-path su my.secret
e il secret-field su field:1
.
Static Vars
Le variabili statiche possono essere specificate nei passaggi delle attività:
Or usando i seguenti fly
argomenti:
-v
o--var
NAME=VALUE
imposta la stringaVALUE
come valore per la varNAME
.-y
o--yaml-var
NAME=VALUE
analizzaVALUE
come YAML e lo imposta come valore per la varNAME
.-i
o--instance-var
NAME=VALUE
analizzaVALUE
come YAML e lo imposta come valore per la var di istanzaNAME
. Vedi Raggruppamento delle Pipeline per saperne di più sulle var di istanza.-l
o--load-vars-from
FILE
caricaFILE
, un documento YAML contenente la mappatura dei nomi delle var ai valori, e li imposta tutti.
Gestione delle Credenziali
Ci sono diversi modi in cui un Gestore di Credenziali può essere specificato in una pipeline, leggi come in https://concourse-ci.org/creds.html. Inoltre, Concourse supporta diversi gestori di credenziali:
Nota che se hai qualche tipo di accesso in scrittura a Concourse puoi creare lavori per esfiltrare quei segreti poiché Concourse deve essere in grado di accedervi.
Enumerazione di Concourse
Per enumerare un ambiente concourse devi prima raccogliere credenziali valide o trovare un token autenticato probabilmente in un file di configurazione .flyrc
.
Login e enumerazione dell'Utente Corrente
Per effettuare il login devi conoscere l'endpoint, il nome del team (il predefinito è
main
) e un team a cui appartiene l'utente:fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]
Ottieni i target configurati:
fly targets
Verifica se la connessione al target configurato è ancora valida:
fly -t <target> status
Ottieni il ruolo dell'utente rispetto al target indicato:
fly -t <target> userinfo
Nota che il token API è salvato in $HOME/.flyrc
per impostazione predefinita, se stai saccheggiando una macchina potresti trovare lì le credenziali.
Team e Utenti
Ottieni un elenco dei Team
fly -t <target> teams
Ottieni i ruoli all'interno del team
fly -t <target> get-team -n <team-name>
Ottieni un elenco di utenti
fly -t <target> active-users
Pipeline
Elenca le pipeline:
fly -t <target> pipelines -a
Ottieni il yaml della pipeline (informazioni sensibili potrebbero essere trovate nella definizione):
fly -t <target> get-pipeline -p <pipeline-name>
Ottieni tutte le var dichiarate nella config della pipeline
for pipename in $(fly -t <target> pipelines | grep -Ev "^id" | awk '{print $2}'); do echo $pipename; fly -t <target> get-pipeline -p $pipename -j | grep -Eo '"vars":[^}]+'; done
Ottieni tutti i nomi dei segreti delle pipeline utilizzati (se puoi creare/modificare un lavoro o dirottare un contenitore potresti esfiltrarli):
Contenitori e Lavoratori
Elenca lavoratori:
fly -t <target> workers
Elenca contenitori:
fly -t <target> containers
Elenca build (per vedere cosa è in esecuzione):
fly -t <target> builds
Attacchi Concourse
Brute-Force delle Credenziali
admin:admin
test:test
Enumerazione di segreti e parametri
Nella sezione precedente abbiamo visto come puoi ottenere tutti i nomi e le variabili dei segreti utilizzati dalla pipeline. Le variabili potrebbero contenere informazioni sensibili e il nome dei segreti sarà utile in seguito per cercare di rubarli.
Sessione all'interno di un contenitore in esecuzione o recentemente eseguito
Se hai privilegi sufficienti (ruolo membro o superiore) sarai in grado di elencare pipeline e ruoli e semplicemente ottenere una sessione all'interno del contenitore <pipeline>/<job>
utilizzando:
Con questi permessi potresti essere in grado di:
Rubare i segreti all'interno del container
Provare a fuggire verso il nodo
Enumerare/Abusare dell'endpoint cloud metadata (dal pod e dal nodo, se possibile)
Creazione/Modifica della Pipeline
Se hai privilegi sufficienti (ruolo di membro o superiore) sarai in grado di creare/modificare nuove pipeline. Controlla questo esempio:
Con la modifica/creazione di un nuovo pipeline sarai in grado di:
Rubare i segreti (facendo un echo o entrando nel container e eseguendo
env
)Evasione al nodo (dandoti abbastanza privilegi -
privileged: true
)Enumerare/Abusare dell'endpoint cloud metadata (dal pod e dal nodo)
Eliminare il pipeline creato
Esegui un Compito Personalizzato
Questo è simile al metodo precedente, ma invece di modificare/creare un intero nuovo pipeline puoi semplicemente eseguire un compito personalizzato (che sarà probabilmente molto più furtivo):
Uscire verso il nodo da un'attività privilegiata
Nelle sezioni precedenti abbiamo visto come eseguire un'attività privilegiata con concourse. Questo non darà al contenitore esattamente lo stesso accesso del flag privilegiato in un contenitore docker. Ad esempio, non vedrai il dispositivo del filesystem del nodo in /dev, quindi l'uscita potrebbe essere più "complessa".
Nel seguente PoC utilizzeremo il release_agent per uscire con alcune piccole modifiche:
Come avrai notato, questo è solo un escape regolare del release_agent modificando semplicemente il percorso del cmd nel nodo
Uscire verso il nodo da un contenitore Worker
Un escape regolare del release_agent con una modifica minore è sufficiente per questo:
Uscire verso il nodo dal contenitore Web
Anche se il contenitore web ha alcune difese disabilitate, non viene eseguito come un comune contenitore privilegiato (ad esempio, non puoi montare e le capacità sono molto limitate, quindi tutti i modi facili per uscire dal contenitore sono inutili).
Tuttavia, memorizza credenziali locali in chiaro:
Puoi utilizzare quelle credenziali per accedere al server web e creare un contenitore privilegiato ed evadere al nodo.
Nell'ambiente puoi anche trovare informazioni per accedere all'istanza postgresql che concourse utilizza (indirizzo, nome utente, password e database tra le altre informazioni):
Abusare del Servizio Garden - Non un vero attacco
Queste sono solo alcune note interessanti sul servizio, ma poiché ascolta solo su localhost, queste note non presenteranno alcun impatto che non abbiamo già sfruttato in precedenza.
Per impostazione predefinita, ogni worker di concourse eseguirà un servizio Garden sulla porta 7777. Questo servizio è utilizzato dal Web master per indicare al worker cosa deve eseguire (scaricare l'immagine ed eseguire ogni attività). Questo sembra piuttosto interessante per un attaccante, ma ci sono alcune buone protezioni:
È esposto solo localmente (127..0.0.1) e penso che quando il worker si autentica contro il Web con il servizio SSH speciale, viene creato un tunnel in modo che il server web possa comunicare con ogni servizio Garden all'interno di ogni worker.
Il server web monitora i container in esecuzione ogni pochi secondi, e i container inaspettati vengono eliminati. Quindi, se vuoi eseguire un container personalizzato, devi manipolare la comunicazione tra il server web e il servizio garden.
I worker di Concourse vengono eseguiti con privilegi elevati sui container:
Tuttavia, tecniche come mounting il dispositivo /dev del nodo o release_agent non funzioneranno (poiché il vero dispositivo con il filesystem del nodo non è accessibile, solo uno virtuale). Non possiamo accedere ai processi del nodo, quindi fuggire dal nodo senza exploit del kernel diventa complicato.
Nella sezione precedente abbiamo visto come fuggire da un contenitore privilegiato, quindi se possiamo eseguire comandi in un contenitore privilegiato creato dal lavoratore corrente, potremmo fuggire al nodo.
Nota che giocando con concourse ho notato che quando un nuovo contenitore viene generato per eseguire qualcosa, i processi del contenitore sono accessibili dal contenitore del lavoratore, quindi è come se un contenitore creasse un nuovo contenitore al suo interno.
Entrare in un contenitore privilegiato in esecuzione
Creazione di un nuovo container privilegiato
Puoi creare molto facilmente un nuovo container (basta eseguire un UID casuale) ed eseguire qualcosa su di esso:
Tuttavia, il server web controlla ogni pochi secondi i container in esecuzione e, se ne viene scoperto uno inaspettato, verrà eliminato. Poiché la comunicazione avviene in HTTP, potresti manomettere la comunicazione per evitare l'eliminazione di container inaspettati:
Riferimenti
https://concourse-ci.org/vars.html
Last updated