
CVE-2020-13277 Laboratorio: vulnerabilidad lógica de Gitlab - acceso no autorizado de cualquier usuario a repositorios privados
Laboratorio CVE-2020-13277: Vulnerabilidad lógica de Gitlab: acceso no autorizado de cualquier usuario a repositorios 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 靶场]
El núcleo de esta vulnerabilidad consiste principalmente en explotar Mirror Repository, la función de sincronización y respaldo por espejo de los repositorios.
La dirección de sincronización de Mirror se divide a su vez en dos tipos:
Esta vulnerabilidad explota el Mirror Repository en dirección Pull
Cabe señalar que Gitlab se divide en dos versiones: CE (Community Edition, gratuita) y EE (Enterprise Edition, de pago), y Gitlab declara oficialmente que esta vulnerabilidad afecta tanto a CE como a EE en las siguientes versiones:
>=10.6, <12.9.10>=12.10, <12.10.11>=13.0, <13.0.6Pero esto no significa que las imágenes Docker de Gitlab de esas versiones puedan utilizarse para montar el laboratorio, porque:
En otras palabras, para montar el laboratorio con Docker solo se puede elegir la versión Gitlab-EE y crackearla (quien tenga dinero también puede optar por comprar una License) para activar la función Mirror Repository - Pull.
Pero incluso con Gitlab-EE crackeado, ya sea 10.x, 12.x o 13.x, cuando la URL de Mirror Repository - Pull contiene una ruta local, se muestra el error Import url is blocked: Requests to localhost are not allowed.
Aunque tras configurar Allow requests to the local network from hooks and services mediante Admin area => Settings => Network => Outbound requests se puede configurar una URL local, al sincronizar el espejo aparece el error 2:Fetching remote upstream failed: fatal: unable to access http://127.0.0.1/xxxx/: The requested URL returned error: 301. En otras palabras, solo es utilizable el Pull de un Remote Repository.
Por suerte, aunque 12.x y 13.x son muy estrictos a la hora de detectar URL locales, en la versión 10.x hay una forma de sortearlo: al configurar la URL de Pull basta con utilizar el nombre del servicio DNS configurado localmente para evadir la restricción.
En resumen, solo se puede utilizar la imagen Docker de la versión gitlab-ee:10.6.0-ee.0 para construir este laboratorio.
De hecho, por lo descrito anteriormente se puede saber que las condiciones para explotar esta vulnerabilidad son bastante exigentes; básicamente es difícil que los menos pudientes se vean afectados por esta vulnerabilidad
./keygen.sh o ./keygen.ps1./run.sh o ./run.ps1Al generar el par de claves de crackeo anteriormente, la clave pública ya se ha escrito en el contenedor de Gitlab; todavía hay que subir la clave privada a Gitlab a través de la interfaz web para completar el crackeo:
./gitlab/keys/; copia el contenido de .gitlab-license que se encuentra en él (la clave privada)Enter license key, pega la clave privada y haz clic en el botón Upload license para completar el crackeoEn este punto, la función Mirror Repository - Pull ya está activada

Outbound requests en la parte inferior, marca Allow requests to the local network from hooks and services y guardaEn este punto, Mirror Repository - Pull ya admite la extracción de un Repository local

./register.sh $TOKEN o ./register.ps1 $TOKENEn este punto, todos los Repository pueden usar este Runner para ejecutar scripts de CI (Pipeline Jobs)

El proceso de verificación puede consultarse en el Issue oficial, pero el proceso de verificación siguiente ajustará ligeramente algunos pasos según este laboratorio
Con el usuario root abre la página http://127.0.0.1/admin/users para crear 3 cuentas:
victim: la cuenta de la víctimaattacker1: la cuenta del atacante 1attacker2: la cuenta del atacante 2Al crear la cuenta no se puede establecer una contraseña inicial; Gitlab envía por defecto la contraseña inicial al Email configurado. Para mayor comodidad, se puede poner cualquier Email, crear la cuenta primero y luego editarla inmediatamente; en ese momento se puede usar root para establecer la contraseña inicial de esa cuenta sin necesidad del Email

victimNew Project:
targetPrivateREADME.md en el repositorio y ponle como contenido, por ejemplo, mykey is abcxyzObviamente
targetes el repositorio privado devictim, y nuestro objetivo es obtener el contenido de este repositorio explotando la vulnerabilidad

attacker1New Project:
pocPublic.gitlab-ci.yml en el repositorio con el siguiente contenido:image: "ruby:2.6"
rspec:
script:
- git clone http://gitlab-ci-token:[email protected]/victim/target.git
- cd target
- ls -lah .
- cat README.md
【Objetivo】En las operaciones siguientes, mediante ciertas técnicas se logrará que victim, sin saberlo, ejecute este script de CI con sus permisos.
Debido a que el laboratorio actual no tiene certificados configurados, solo se puede usar el protocolo
http; además,172.168.30.2es la IP quedocker-compose.ymlasigna al contenedor de Gitlab. Como este script de CI se ejecutará finalmente a través del Runner, y el Runner y Gitlab de este laboratorio no están en el mismo contenedor, hay que usar la dirección IP asignada por Docker

attacker2New Group:
testPublictest, crea un repositorio completamente vacío en New Project:
pocPublic
Configura el repositorio espejo en Settings => Repository => Pull from a remote repository:
Mirror repository: marcarGit repository URL: rellenar con http://GITLAB/attacker1/pocPassword: (dejar en blanco; el nivel de confidencialidad del repositorio de Pull es Public, no requiere contraseña)Trigger pipelines for mirror updates: marcar (dispara la ejecución del script de CI al sincronizar el espejo)Una vez configurado correctamente, se comprobará cada 30 minutos si el repositorio de origen ha cambiado y, si es así, se forzará la sincronización.
Git repository URLapunta al repositorio poc creado anteriormente. No se usa 127.0.0.1 porque Pull prohíbe extraer repositorios locales, pero se puede evadir mediante DNS:GITLABes el hostname quedocker-compose.ymlasigna al contenedor de Gitlab y se añade por defecto a/etc/hosts. Aunque el host no puede resolverGITLAB, dentro del contenedor equivale a acceder ahttp://127.0.0.1/attacker1/poc

attacker2testvictim al grupo:
Add new member to test: victimPermissions: OwnerExpiration date: (dejar en blanco, es decir, sin límite de tiempo)=> Setting => Account => Delete account para eliminar la cuenta actual (attacker2)【Objetivo】En el grupo test solo hay dos Owner: victim y attacker2. Cuando el usuario attacker2 es eliminado, la propiedad del grupo test y de todos los repositorios que contiene se transfiere forzosamente a victim. Como actualmente el grupo test contiene un repositorio test/poc sincronizado por espejo desde attacker1/poc, esto equivale a transferir forzosamente el repositorio test/poc al usuario victim.


Primero repasemos la situación actual hasta ahora:
test/poc para la víctima victimtest/poc se sincroniza por espejo desde el repositorio attacker1/poc (cada 30 minutos se comprueba si hay cambios que requieran sincronización)attacker1/poc, incluido el script de CI .gitlab-ci.yml, está controlado por el atacantetest/poc tiene marcada la opción Trigger pipelines for mirror updates, el script de CI se ejecuta en cada sincronizaciónOwner del repositorio test/poc es victim, el script de CI se ejecuta con los permisos de victim
Revisando el contenido del script de CI .gitlab-ci.yml configurado anteriormente, este poc utiliza los permisos de victim en el Runner para acceder a la estructura de directorios y al README.md de su repositorio privado target:
image: "ruby:2.6"
rspec:
script:
- git clone http://gitlab-ci-token:[email protected]/victim/target.git
- cd target
- ls -lah .
- cat README.md
Después, el atacante solo necesita modificar arbitrariamente algún contenido intrascendente del repositorio attacker1/poc; en el peor de los casos solo tiene que esperar 30 minutos para poder ejecutar el script de CI configurado con los permisos de victim.
Aunque el atacante no tiene permiso directo para acceder a los resultados de ejecución de los Pipeline Jobs, basta con ajustar el destino de salida del script, por ejemplo enviando el contenido del repositorio a un Email o a un servidor FTP determinados, para robar el código del repositorio.
