
CVE-2020-13277 Laboratório: Vulnerabilidade lógica do Gitlab - Acesso não autorizado de qualquer usuário a repositórios privados
Lab CVE-2020-13277: Vulnerabilidade lógica do Gitlab - Acesso não autorizado de qualquer usuário a repositórios privados
CVE-2020-13277
├── README.md ............... [此 README 说明]
├── imgs .................... [辅助 README 说明的图片]
├── gitlab .................. [Gitlab 容器的挂载目录]
│ ├── Dockerfile .......... [Gitlab 的 Docker 构建文件]
│ ├── config .............. [Gitlab 配置挂载目录]
│ ├── data ................ [Gitlab 数据挂载目录]
│ ├── logs ................ [Gitlab 日志挂载目录]
│ ├── keys ................ [Gitlab 破解 License 存储目录]
│ └── runner .............. [Runner 容器的挂载目录]
├── license ................. [破解 License 的容器构建目录]
│ ├── Dockerfile .......... [License 的 Docker 构建文件]
│ └── license.rb .......... [生成破解 License 的 Ruby 脚本]
├── docker-compose.yml ...... [Docker 的构建配置]
├── keygen.ps1 .............. [Windows: 一键生成破解 License]
├── keygen.sh ............... [Linux: 一键生成破解 License]
├── run.ps1 ................. [Windows: 一键运行 Gitlab 靶场]
├── run.sh .................. [Linux: 一键运行 Gitlab 靶场]
├── register.ps1 ............ [Windows: 一键注册 Runner]
├── register.sh ............. [Linux: 一键注册 Runner]
├── stop.ps1 ................ [Windows: 一键停止 Gitlab 靶场]
└── stop.sh ................. [Linux: 一键停止 Gitlab 靶场]
O núcleo desta vulnerabilidade utiliza principalmente o Mirror Repository - o recurso de sincronização/backup de repositórios espelhados.
A direção de sincronização do Mirror é dividida em dois tipos:
Pull: puxa o conteúdo de um Repository especificado para o Repository atualPush: envia o conteúdo do Repository atual para um Repository especificadoEsta vulnerabilidade explora o Mirror Repository na direção Pull
Saiba que o Gitlab é dividido em duas versões: CE (Community Edition gratuita) e EE (Enterprise Edition paga), e o Gitlab também afirma oficialmente que esta vulnerabilidade afeta as seguintes versões de CE e EE:
>=10.6, <12.9.10>=12.10, <12.10.11>=13.0, <13.0.6Mas isso não significa que o Gitlab Docker Image dessas versões possa ser usado para montar o lab, porque:
Em outras palavras, para montar o lab com Docker, só é possível usar a versão Gitlab-EE e crackeá-la (os ricos também podem optar por comprar uma License) para ativar o recurso Mirror Repository - Pull.
Mas mesmo com o Gitlab-EE crackeado, seja 10.x, 12.x ou 13.x, quando a URL do Mirror Repository - Pull contém um caminho local, ocorre o erro Import url is blocked: Requests to localhost are not allowed.
Embora seja possível configurar uma URL local ativando Allow requests to the local network from hooks and services em Admin area => Settings => Network => Outbound requests, ao sincronizar o espelho ocorre o erro 2:Fetching remote upstream failed: fatal: unable to access http://127.0.0.1/xxxx/: The requested URL returned error: 301. Em outras palavras, apenas o Pull Remote Repository é utilizável.
Porém, felizmente, embora 12.x e 13.x tenham métodos de validação de URL local muito rigorosos, na versão 10.x há uma forma de contornar: ao configurar a Pull URL, basta usar o nome do serviço DNS configurado localmente para contornar a restrição.
Diante disso, só é possível construir este lab usando a Docker Image da versão gitlab-ee:10.6.0-ee.0.
Na verdade, pela descrição anterior, também se percebe que as condições de exploração desta vulnerabilidade são bastante restritas; basicamente, é muito difícil alguém sem recursos ser afetado por ela.
./keygen.sh ou ./keygen.ps1./run.sh ou ./run.ps1Ao gerar o par de chaves de crack anteriormente, a chave pública já foi gravada no backend do contêiner Gitlab; agora é necessário enviar a chave privada pelo frontend para o Gitlab para concluir o crack:
./gitlab/keys/; copie o conteúdo de .gitlab-license (a chave privada)Enter license key, cole a chave privada e clique no botão Upload license para concluir o crackNeste ponto, o recurso Mirror Repository - Pull foi ativado

Outbound requests na parte inferior, marque Allow requests to the local network from hooks and services e salveNeste ponto, o Mirror Repository - Pull já suporta puxar Repository local

./register.sh $TOKEN ou ./register.ps1 $TOKENNeste ponto, todos os Repository podem usar este Runner para executar scripts de CI (Pipeline Jobs)

O processo de verificação pode consultar a Issue oficial, mas o processo abaixo ajusta alguns passos de acordo com este lab
Com o usuário root, abra a página http://127.0.0.1/admin/users e crie 3 contas:
victim: conta da vítimaattacker1: conta do atacante 1attacker2: conta do atacante 2Ao criar a conta, não é possível definir uma senha inicial; o Gitlab envia a senha inicial para o Email configurado. Para facilitar, você pode preencher qualquer Email, criar a conta e em seguida editar a conta imediatamente; nesse momento é possível usar root para definir a senha inicial dessa conta, sem precisar do Email

victimNew Project:
targetPrivateREADME.md e defina o conteúdo como mykey is abcxyzObviamente,
targeté o repositório privado devictim, e nosso objetivo é usar a vulnerabilidade para obter o conteúdo desse repositório

attacker1New Project:
pocPublic.gitlab-ci.yml com o seguinte conteúdo:image: "ruby:2.6"
rspec:
script:
- git clone http://gitlab-ci-token:[email protected]/victim/target.git
- cd target
- ls -lah .
- cat README.md
【Propósito】Nas próximas etapas, algumas técnicas farão com que victim, sem saber, execute este script de CI usando suas permissões.
Como o lab atual não possui certificado configurado, só é possível usar o protocolo
http; além disso,172.168.30.2é o IP atribuído ao contêiner Gitlab pelodocker-compose.yml. Como este script de CI será executado pelo Runner, e o Runner e o Gitlab neste lab não estão no mesmo contêiner, é necessário usar o endereço IP atribuído pelo Docker

attacker2New Group:
testPublictest, crie um repositório completamente vazio New Project:
pocPublic
Configure o repositório espelho em Settings => Repository => Pull from a remote repository:
Mirror repository: marqueGit repository URL: preencha com http://GITLAB/attacker1/pocPassword: (deixe em branco; o repositório de origem do Pull é Public, não precisa de senha)Trigger pipelines for mirror updates: marque (dispara a execução do script de CI durante a sincronização do espelho)Após a configuração, a cada 30 minutos o repositório de origem é verificado para ver se houve alterações; se houver, a sincronização é forçada.
A
Git repository URLaponta para o repositório poc criado anteriormente. Não se usa 127.0.0.1 porque o Pull proíbe puxar repositórios locais, mas é possível contornar usando DNS:GITLABé o hostname atribuído ao contêiner Gitlab pelodocker-compose.ymle, por padrão, é configurado no/etc/hosts. Embora o host não consiga resolverGITLAB, dentro do contêiner é equivalente a acessarhttp://127.0.0.1/attacker1/poc

attacker2testvictim ao grupo:
Add new member to test: victimPermissions: OwnerExpiration date: (deixe em branco, ou seja, sem prazo)=> Setting => Account => Delete account para excluir a conta atual (attacker2)【Propósito】No grupo test, há apenas dois Owner: victim e attacker2. Quando o usuário attacker2 for excluído, a propriedade do grupo test e de todos os repositórios sob ele será transferida à força para victim. Como atualmente há um repositório test/poc sob o grupo test, espelhado a partir de attacker1/poc, isso equivale a transferir à força o repositório test/poc para o usuário victim.


Vamos primeiro organizar a situação atual até aqui:
test/poc para a vítima victimtest/poc é sincronizado por espelhamento a partir do repositório attacker1/poc (a cada 30 minutos é verificado se houve alterações que precisam ser sincronizadas)attacker1/poc é controlado pelo atacante, incluindo o script de CI .gitlab-ci.ymltest/poc tem Trigger pipelines for mirror updates habilitado, o script de CI é executado a cada sincronizaçãoOwner do repositório test/poc é victim, o script de CI é executado com as permissões de victim
Revisando o conteúdo do script de CI .gitlab-ci.yml configurado anteriormente, este poc usa as permissões de victim no Runner para acessar a estrutura de diretórios e o README.md do repositório privado target de victim:
image: "ruby:2.6"
rspec:
script:
- git clone http://gitlab-ci-token:[email protected]/victim/target.git
- cd target
- ls -lah .
- cat README.md
Em seguida, o atacante só precisa modificar arbitrariamente algum conteúdo irrelevante no repositório attacker1/poc; no pior caso, basta esperar 30 minutos para executar o script de CI definido com as permissões de victim.
Embora o atacante não tenha permissão direta para acessar os resultados da execução dos Pipeline Jobs, basta ajustar o destino de saída do script, por exemplo enviando o conteúdo do repositório para um Email ou servidor FTP especificado, para roubar o código do repositório.
