From d94ccc1f644bc7de1e8864a70f916799bc47bb19 Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 6 Jul 2026 15:32:18 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-ci-cd/github-security/abusing-github-act --- .../gh-actions-context-script-injections.md | 102 +++++++++++++----- 1 file changed, 73 insertions(+), 29 deletions(-) diff --git a/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-context-script-injections.md b/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-context-script-injections.md index d4d9ac763..487cf1133 100644 --- a/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-context-script-injections.md +++ b/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-context-script-injections.md @@ -2,20 +2,20 @@ {{#include ../../../banners/hacktricks-training.md}} -## Riskin anlaşılması +## Riski anlamak -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, step çalışmadan önce expression'ları ${{ ... }} olarak render eder. Render edilen değer, step’in programının içine yapıştırılır (run step’leri için bir shell script). Güvenilmeyen input’u doğrudan run: içinde interpolate ederseniz, attacker shell programının bir kısmını kontrol eder ve arbitrary commands çalıştırabilir. 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 -Önemli noktalar: -- Render işlemi yürütmeden önce gerçekleşir. Tüm ifadeler çözümlendikten sonra run script oluşturulur ve sonra shell tarafından çalıştırılır. -- Birçok contexts kullanıcı-kontrollü alanlar içerir; bu, tetikleyici olaya bağlıdır (issues, PRs, comments, discussions, forks, stars, vb.). Güvenilmeyen input referansına bakın: https://securitylab.github.com/resources/github-actions-untrusted-input/ -- run: içindeki shell quoting güvenilir bir savunma değildir, çünkü enjeksiyon şablon render aşamasında gerçekleşir. Saldırganlar tırnaklardan çıkabilir veya özel olarak hazırlanmış girdilerle operatörler enjekte edebilir. +Key points: +- Rendering execution’dan önce gerçekleşir. run script, tüm expression’lar resolve edildikten sonra üretilir ve ardından shell tarafından çalıştırılır. +- Birçok context, tetikleyen event’e bağlı olarak user-controlled alanlar içerir (issues, PRs, comments, discussions, forks, stars, vb.). Untrusted input referansına bakın: https://securitylab.github.com/resources/github-actions-untrusted-input/ +- run: içinde shell quoting güvenilir bir defense değildir, çünkü injection template rendering aşamasında gerçekleşir. Attacker’lar craft edilmiş input ile quote’lardan çıkabilir veya operator’ler inject edebilir. -## Zayıf örüntü → RCE on runner +## Vulnerable pattern → RCE on runner -Zayıf workflow (birisi yeni bir issue açtığında tetiklenir): +Vulnerable workflow (birisi yeni bir issue açtığında tetiklenir): ```yaml name: New Issue Created on: @@ -36,20 +36,56 @@ with: github_token: ${{ secrets.GITHUB_TOKEN }} labels: new ``` -Eğer bir saldırgan $(id) başlıklı bir issue açarsa, renderlenen adım şöyle olur: +Eğer bir attacker $(id) başlıklı bir issue açarsa, render edilen step şu hale gelir: ```sh echo "New issue $(id) created" ``` -Komut değişimi runner üzerinde id komutunu çalıştırır. Örnek çıktı: +Komut substitution, runner üzerinde id çalıştırır. Örnek çıktı: ``` New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created ``` -Neden tırnaklama sizi kurtarmaz: -- İfadeler önce render edilir, sonra ortaya çıkan script çalıştırılır. Eğer güvensiz değer $(...), `;`, `"`/`'`, veya yeni satırlar içeriyorsa, tırnaklama yapmış olsanız bile program yapısını değiştirebilir. +Neden quoting sizi korumaz: +- Expressions önce render edilir, ardından oluşan script çalışır. Güvenilmeyen değer $(...), `;`, `"`/`'` veya yeni satırlar içeriyorsa, quoting’e rağmen program yapısını değiştirebilir. -## Güvenli desen (shell variables via env) +## Comment-state confusion: sahte bot yorumları → shell injection -Doğru önlem: güvensiz girdiyi bir environment variable'a kopyalayın, sonra run script içinde native shell expansion ($VAR) kullanın. Komutun içinde ${{ ... }} ile tekrar gömmeyin. +Tehlikeli bir varyant, bir workflow **yorumları aradığında ve daha sonra dönen yorumu trusted automation state olarak ele aldığında** ortaya çıkar. Örneğin, `peter-evans/find-comment` `body-includes` ile arama yapabilir ve eşleşen `comment-body` değerini bir step output olarak açığa çıkarabilir. Eğer workflow, **ayrıca** `comment-author` ile kısıtlamazsa, yorum yapabilen herhangi bir kullanıcı bot’tan beklenen marker metnini spoof edebilir. +```yaml +- uses: peter-evans/find-comment@v4 +id: fc +with: +issue-number: ${{ github.event.issue.number }} +body-includes: "Opened a new issue in org/repo:" +``` +Bu çıktı daha sonra shell syntax içine gömülürse, orijinal kaynak "sadece bir comment" olsa bile workflow exploitable hale gelir: +```yaml +- run: | +if [ '${{ steps.fc.outputs.comment-body }}' = '' ]; then +echo "new issue needed" +fi +``` +Bir saldırgan, aşağıdakilerin ikisini de yapan bir comment gönderebilir: +- searched marker string ile eşleşir, ve +- `' ]; ; if [ 'x` gibi shell-breaking content içerir + +GitHub `${{ ... }}` kısmını render ettikten sonra, Bash attacker-controlled syntax alır, data değil. Bu, **iki aşamalı exploit** oluşturur: +1. **Provenance confusion**: workflow, attacker comments’ı bot state sanır. +2. **Script injection**: dönen `comment-body` `run:` içine yapıştırılır ve çalıştırılır. + +### Bot comments’a karşı TOCTOU race + +Eğer meşru bot comment’i ancak daha sonraki bir step’ten sonra oluşturuluyorsa, bir saldırgan sahte comment’i önce göndererek yarış kazanabilir. Search action, gerçek bot comment’i mevcut olmadan önce (veya seçilmeden önce) saldırganın comment’ini döndürürse, düşük yetkili bir public commenter bir `issue_comment`/issue workflow’unu privileged runner execution’a çevirebilir. + +### Comment-driven automation için daha güvenli pattern’ler + +- `find-comment` kullanırken, **hem content hem provenance** isteyin (`comment-author`, repository/App identity, veya başka güçlü bir binding). +- Aynı state bir label, artifact, issue field, veya external datastore içinde daha güvenli tutulabiliyorsa comment’leri state olarak kullanmayın. +- `comment-body`, issue titles, labels, veya bunlardan türetilmiş herhangi bir workflow output’u asla doğrudan `run:` içine yapıştırmayın. +- Comment text’ini kullanmanız gerekiyorsa, onu `env:` veya bir dosyadan geçirin ve yalnızca data olarak ele alın. + +## Safe pattern (shell variables via env) + +Doğru mitigation: güvenilmeyen input’u bir environment variable’a kopyalayın, sonra run script içinde native shell expansion ($VAR) kullanın. Komut içinde ${{ ... }} ile yeniden gömmeyin. ```yaml # safe jobs: @@ -62,32 +98,40 @@ TITLE: ${{ github.event.issue.title }} run: | echo "New issue $TITLE created" ``` -Notlar: -- run: içinde ${{ env.TITLE }} kullanmaktan kaçının. Bu, şablon render'ını komutun içine yeniden sokar ve aynı enjeksiyon riskini getirir. -- Güvensiz girdileri env: mapping ile geçirmek ve run: içinde bunlara $VAR ile referans vermek tercih edin. +Notes: +- ${{ env.TITLE }} içini run: içinde kullanmaktan kaçının. Bu, template rendering’i komuta yeniden sokar ve aynı injection riskini geri getirir. +- Güvenilmeyen girdileri env: mapping üzerinden geçirmeyi ve run: içinde bunlara $VAR ile referans vermeyi tercih edin. -## Reader-triggerable surfaces (treat as untrusted) +## Reader-triggerable surfaces (güvenilmeyen olarak değerlendirin) -Sadece public repository'lerde okuma izni olan hesaplar bile birçok eventi tetikleyebilir. Bu olaylardan türetilen contexts içindeki herhangi bir alan, aksi kanıtlanana kadar saldırgan kontrolünde kabul edilmelidir. Örnekler: +Public repositories üzerinde yalnızca read yetkisine sahip hesaplar bile birçok olayı tetikleyebilir. Bu olaylardan türetilen contexts içindeki herhangi bir field, aksi kanıtlanmadıkça attacker-controlled olarak kabul edilmelidir. Örnekler: - issues, issue_comment -- discussion, discussion_comment (org'lar discussions'ı kısıtlayabilir) +- discussion, discussion_comment (orgs discussions üzerinde kısıtlama getirebilir) - pull_request, pull_request_review, pull_request_review_comment -- pull_request_target (kötü kullanılırsa tehlikeli, base repo context'inde çalışır) -- fork (herkes public repo'yu fork'layabilir) -- watch (bir repo'yu star'lamak) -- Dolaylı olarak workflow_run/workflow_call zincirleri vasıtasıyla +- pull_request_target (kötü kullanılırsa tehlikelidir, base repo context içinde çalışır) +- fork (herkes public repos fork edebilir) +- watch (bir repo’yu star’lamak) +- Dolaylı olarak workflow_run/workflow_call zincirleri üzerinden -Hangi spesifik alanların saldırgan kontrolünde olduğu olay bazlıdır. GitHub Security Lab’in untrusted input rehberine bakın: https://securitylab.github.com/resources/github-actions-untrusted-input/ +Hangi spesifik field’ların attacker-controlled olduğu event’e özeldir. GitHub Security Lab’ın untrusted input guide dokümanına bakın: https://securitylab.github.com/resources/github-actions-untrusted-input/ -## Practical tips +## Hedef repo’ya dokunmadan yerel validation + +Birçok GitHub Actions script injections vakasını [`act`](https://github.com/nektos/act) ile güvenli şekilde yeniden üretebilirsiniz: sentetik bir event JSON üretin, vulnerable workflow’u yerelde çalıştırın ve external action output’unu kontrollü bir değerle değiştirin (örneğin mocked bir `comment-body`). Bu, payload yapısını debug etmek, injected text’in hâlâ geçerli Bash syntax bırakıp bırakmadığını doğrulamak ve herhangi bir canlı testten önce zararsız canary exfiltration’ı onaylamak için kullanışlıdır. + +## Pratik ipuçları - run: içinde expressions kullanımını en aza indirin. env: mapping + $VAR tercih edin. -- Eğer girdiyi dönüştürmeniz gerekiyorsa, bunu shell içinde güvenli araçlarla yapın (printf %q, jq -r, vb.), yine bir shell değişkeninden başlayarak. -- Branch isimlerini, PR başlıklarını, kullanıcı adlarını, label'ları, discussion başlıklarını ve PR head ref'lerini script'lere, komut satırı flag'lerine veya dosya yollarına interpolasyon yaparken ekstra dikkatli olun. -- Reusable workflows ve composite actions için de aynı deseni uygulayın: env'e map edip sonra $VAR ile referanslayın. +- Girdiyi dönüştürmeniz gerekiyorsa, bunu shell içinde güvenli araçlarla yapın (printf %q, jq -r, vb.), yine de bir shell variable’dan başlayarak. +- branch names, PR titles, usernames, labels, discussion titles ve PR head refs’i script’lere, command-line flags’e veya file paths’e yerleştirirken ekstra dikkatli olun. +- reusable workflows ve composite actions için de aynı deseni uygulayın: env’e map edin, sonra $VAR ile referans verin. ## References +- [Find Comment, Get Shell: Command Injection in dbt’s GitHub Actions](https://landh.tech/blog/20260701-find-comment-get-shell) +- [peter-evans/find-comment](https://github.com/peter-evans/find-comment) +- [GHSL-2023-109: GitHub Actions command injection in a TDesign Vue Next workflow](https://securitylab.github.com/advisories/GHSL-2023-109_TDesign_Vue_Next/) +- [nektos/act](https://github.com/nektos/act) - [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)