Concourse Enumeration & Attacks
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Concourse vem com cinco papéis:
Concourse Admin: Este papel é dado apenas aos proprietários da equipe principal (equipe inicial padrão do concourse). Os administradores podem configurar outras equipes (por exemplo: fly set-team
, fly destroy-team
...). As permissões deste papel não podem ser afetadas pelo RBAC.
owner: Os proprietários da equipe podem modificar tudo dentro da equipe.
member: Os membros da equipe podem ler e escrever dentro dos ativos da equipe, mas não podem modificar as configurações da equipe.
pipeline-operator: Os operadores de pipeline podem realizar operações de pipeline como acionar builds e fixar recursos, no entanto, não podem atualizar as configurações do pipeline.
viewer: Os visualizadores da equipe têm acesso "somente leitura" a uma equipe e seus pipelines.
Além disso, as permissões dos papéis owner, member, pipeline-operator e viewer podem ser modificadas configurando o RBAC (configurando mais especificamente suas ações). Leia mais sobre isso em: https://concourse-ci.org/user-roles.html
Note que o Concourse agrupa pipelines dentro de Equipes. Portanto, usuários pertencentes a uma Equipe poderão gerenciar esses pipelines e várias Equipes podem existir. Um usuário pode pertencer a várias Equipes e ter permissões diferentes dentro de cada uma delas.
Nos arquivos de configuração YAML, você pode configurar valores usando a sintaxe ((_source-name_:_secret-path_._secret-field_))
.
Dos docs: O source-name é opcional, e se omitido, o gerenciador de credenciais em todo o cluster será usado, ou o valor pode ser fornecido estaticamente.
O campo _secret-field_ opcional especifica um campo no segredo obtido para leitura. Se omitido, o gerenciador de credenciais pode optar por ler um 'campo padrão' da credencial obtida, se o campo existir.
Além disso, o secret-path e secret-field podem ser cercados por aspas duplas "..."
se contiverem caracteres especiais como .
e :
. Por exemplo, ((source:"my.secret"."field:1"))
definirá o secret-path como my.secret
e o secret-field como field:1
.
Variáveis estáticas podem ser especificadas em etapas de tarefas:
Or usando os seguintes fly
argumentos:
-v
ou --var
NAME=VALUE
define a string VALUE
como o valor para a var NAME
.
-y
ou --yaml-var
NAME=VALUE
analisa VALUE
como YAML e define como o valor para a var NAME
.
-i
ou --instance-var
NAME=VALUE
analisa VALUE
como YAML e define como o valor para a var de instância NAME
. Veja Agrupando Pipelines para saber mais sobre vars de instância.
-l
ou --load-vars-from
FILE
carrega FILE
, um documento YAML contendo mapeamento de nomes de var para valores, e define todos eles.
Existem diferentes maneiras de um Gerenciador de Credenciais ser especificado em um pipeline, leia como em https://concourse-ci.org/creds.html. Além disso, o Concourse suporta diferentes gerenciadores de credenciais:
Observe que se você tiver algum tipo de acesso de gravação ao Concourse, pode criar jobs para exfiltrar esses segredos, pois o Concourse precisa ser capaz de acessá-los.
Para enumerar um ambiente do concourse, você primeiro precisa coletar credenciais válidas ou encontrar um token autenticado, provavelmente em um arquivo de configuração .flyrc
.
Para fazer login, você precisa saber o endpoint, o nome da equipe (o padrão é main
) e uma equipe à qual o usuário pertence:
fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]
Obter alvos configurados:
fly targets
Verificar se a conexão do alvo configurado ainda é válida:
fly -t <target> status
Obter papel do usuário em relação ao alvo indicado:
fly -t <target> userinfo
Observe que o token da API é salvo em $HOME/.flyrc
por padrão, você, ao invadir uma máquina, pode encontrar lá as credenciais.
Obter uma lista das Equipes
fly -t <target> teams
Obter papéis dentro da equipe
fly -t <target> get-team -n <team-name>
Obter uma lista de usuários
fly -t <target> active-users
Listar pipelines:
fly -t <target> pipelines -a
Obter yaml do pipeline (informações sensíveis podem ser encontradas na definição):
fly -t <target> get-pipeline -p <pipeline-name>
Obter todas as vars declaradas na configuração do 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
Obter todos os nomes de segredos de pipelines usados (se você puder criar/modificar um job ou sequestrar um contêiner, poderá exfiltrá-los):
Listar workers:
fly -t <target> workers
Listar containers:
fly -t <target> containers
Listar builds (para ver o que está rodando):
fly -t <target> builds
admin:admin
test:test
Na seção anterior, vimos como você pode obter todos os nomes e variáveis dos segredos usados pelo pipeline. As variáveis podem conter informações sensíveis e o nome dos segredos será útil mais tarde para tentar roubá-los.
Se você tiver privilégios suficientes (papel de membro ou mais) você poderá listar pipelines e papéis e apenas obter uma sessão dentro do container <pipeline>/<job>
usando:
Com essas permissões, você pode ser capaz de:
Roubar os segredos dentro do container
Tentar escapar para o nó
Enumerar/Abusar do endpoint de metadados da nuvem (do pod e do nó, se possível)
Se você tiver privilégios suficientes (papel de membro ou mais), você poderá criar/modificar novos pipelines. Confira este exemplo:
Com a modificação/criação de um novo pipeline, você poderá:
Roubar os segredos (via ecoando-os ou entrando no contêiner e executando env
)
Escapar para o nó (dando a você privilégios suficientes - privileged: true
)
Enumerar/Abusar do endpoint de metadados da nuvem (do pod e do nó)
Excluir o pipeline criado
Isso é semelhante ao método anterior, mas em vez de modificar/criar um novo pipeline inteiro, você pode apenas executar uma tarefa personalizada (que provavelmente será muito mais furtiva):
Nas seções anteriores, vimos como executar uma tarefa privilegiada com concourse. Isso não dará ao contêiner exatamente o mesmo acesso que a flag privilegiada em um contêiner docker. Por exemplo, você não verá o dispositivo do sistema de arquivos do nó em /dev, então a fuga pode ser mais "complexa".
No seguinte PoC, vamos usar o release_agent para escapar com algumas pequenas modificações:
Como você pode ter notado, isso é apenas uma escapada regular do release_agent apenas modificando o caminho do cmd no nó
Uma escapada regular do release_agent com uma modificação menor é suficiente para isso:
Mesmo que o contêiner web tenha algumas defesas desativadas, não está rodando como um contêiner privilegiado comum (por exemplo, você não pode montar e as capacidades são muito limitadas, então todas as maneiras fáceis de escapar do contêiner são inúteis).
No entanto, ele armazena credenciais locais em texto claro:
Você pode usar essas credenciais para fazer login no servidor web e criar um contêiner privilegiado e escapar para o nó.
No ambiente, você também pode encontrar informações para acessar a instância do postgresql que o concourse usa (endereço, nome de usuário, senha e banco de dados, entre outras informações):
Estas são apenas algumas notas interessantes sobre o serviço, mas como ele está apenas ouvindo no localhost, essas notas não apresentarão nenhum impacto que já não tenhamos explorado antes.
Por padrão, cada trabalhador do concourse estará executando um Garden serviço na porta 7777. Este serviço é usado pelo mestre da Web para indicar ao trabalhador o que ele precisa executar (baixar a imagem e executar cada tarefa). Isso soa muito bem para um atacante, mas há algumas boas proteções:
Está apenas exposto localmente (127..0.0.1) e eu acho que quando o trabalhador se autentica contra a Web com o serviço SSH especial, um túnel é criado para que o servidor web possa conversar com cada serviço Garden dentro de cada trabalhador.
O servidor web está monitorando os contêineres em execução a cada poucos segundos, e contêineres inesperados são deletados. Portanto, se você quiser executar um contêiner personalizado, precisará interferir na comunicação entre o servidor web e o serviço garden.
Os trabalhadores do Concourse são executados com altos privilégios de contêiner:
No entanto, técnicas como montar o dispositivo /dev do nó ou release_agent não funcionarão (já que o dispositivo real com o sistema de arquivos do nó não é acessível, apenas um virtual). Não podemos acessar processos do nó, então escapar do nó sem exploits de kernel se torna complicado.
Na seção anterior, vimos como escapar de um contêiner privilegiado, então se pudermos executar comandos em um contêiner privilegiado criado pelo trabalhador atual, poderíamos escapar para o nó.
Note que brincando com o concourse, percebi que quando um novo contêiner é gerado para executar algo, os processos do contêiner são acessíveis a partir do contêiner do trabalhador, então é como se um contêiner estivesse criando um novo contêiner dentro dele.
Entrando em um contêiner privilegiado em execução
Criando um novo contêiner privilegiado
Você pode criar muito facilmente um novo contêiner (basta executar um UID aleatório) e executar algo nele:
No entanto, o servidor web está verificando a cada poucos segundos os contêineres que estão em execução, e se um inesperado for descoberto, ele será excluído. Como a comunicação está ocorrendo em HTTP, você poderia manipular a comunicação para evitar a exclusão de contêineres inesperados:
https://concourse-ci.org/vars.html
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)