JspWebShell新姿势解读 {#JspWebShell新姿势解读}
写在前面 {#写在前面}
刚刚无意间发现我yzddmr6发了篇新文章,里面提到了一个jspwebshell的新姿势,但是没有具体分析,那么这里我就接着来分析一波
首先代码长这样
|-------------------|--------------------------------------------------------------------------------|
| 1 2 3 4 5
| <% Runtime.getRuntime(). //\u000d\uabcdexec("open -na Calculator"); %>
|
正文 {#正文}
如果按照传统Java的javac的方式编译这样一定是会出错的,这里不贴图自己试试,而jsp不同于普通的java程序,jsp是有自己的对类编译时的实现机制,其编译类的时候最终是在org.apache.jasper.compiler.JDTCompiler#generateClass
生成我们的class文件(省略中途的很多步骤直捣黄龙,不然讲着也费劲)
这是调用栈,有兴趣可以深入分析
|---------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| getNextToken0:1482, Scanner (org.eclipse.jdt.internal.compiler.parser) getNextToken:1462, Scanner (org.eclipse.jdt.internal.compiler.parser) fetchNextToken:12999, Parser (org.eclipse.jdt.internal.compiler.parser) parse:12891, Parser (org.eclipse.jdt.internal.compiler.parser) parse:13277, Parser (org.eclipse.jdt.internal.compiler.parser) parseStatements:225, MethodDeclaration (org.eclipse.jdt.internal.compiler.ast) parseMethods:1152, TypeDeclaration (org.eclipse.jdt.internal.compiler.ast) getMethodBodies:11941, Parser (org.eclipse.jdt.internal.compiler.parser) process:888, Compiler (org.eclipse.jdt.internal.compiler) processCompiledUnits:575, Compiler (org.eclipse.jdt.internal.compiler) compile:475, Compiler (org.eclipse.jdt.internal.compiler) compile:426, Compiler (org.eclipse.jdt.internal.compiler) generateClass:457, JDTCompiler (org.apache.jasper.compiler) compile:397, Compiler (org.apache.jasper.compiler) compile:367, Compiler (org.apache.jasper.compiler) compile:351, Compiler (org.apache.jasper.compiler) compile:605, JspCompilationContext (org.apache.jasper) service:399, JspServletWrapper (org.apache.jasper.servlet) serviceJspFile:379, JspServlet (org.apache.jasper.servlet) service:327, JspServlet (org.apache.jasper.servlet) service:763, HttpServlet (javax.servlet.http) internalDoFilter:227, ApplicationFilterChain (org.apache.catalina.core) doFilter:162, ApplicationFilterChain (org.apache.catalina.core) doFilter:53, WsFilter (org.apache.tomcat.websocket.server) internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core) doFilter:162, ApplicationFilterChain (org.apache.catalina.core) invoke:197, StandardWrapperValve (org.apache.catalina.core) invoke:97, StandardContextValve (org.apache.catalina.core) invoke:540, AuthenticatorBase (org.apache.catalina.authenticator) invoke:135, StandardHostValve (org.apache.catalina.core) invoke:92, ErrorReportValve (org.apache.catalina.valves) invoke:687, AbstractAccessLogValve (org.apache.catalina.valves) invoke:78, StandardEngineValve (org.apache.catalina.core) service:357, CoyoteAdapter (org.apache.catalina.connector) service:382, Http11Processor (org.apache.coyote.http11) process:65, AbstractProcessorLight (org.apache.coyote) process:895, AbstractProtocol$ConnectionHandler (org.apache.coyote) doRun:1732, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net) run:49, SocketProcessorBase (org.apache.tomcat.util.net) runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads) run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads) run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads) run:844, Thread (java.lang)
|
好了不扯那么多,回到正题,在讲之前我们需要知道有个东西叫javadoc相信大家都很熟悉了就是用于描述方法或者类的作用的东西,而造成可以解析的原因其实和这个有关系(jsp编译过程当中用到了AST,这里不多扯)
在生成最终class的过程当中,它会遍历文件当中的字符并做unicode解码处理,下图可以看到正在遍历的过程
而对于unicode的处理最终在org.eclipse.jdt.internal.compiler.parser.Scanner#getNextToken0
,简单看了眼代码其实是为了让AST兼容注释功能,回到代码如果开头是/
,之后会判断下一个字符是/
还是*
,也就是单行或者多行注释咯
根据代码我们这里显然lookAhead
为0,因此我们来看if分支,继续往下走当前为\r
如果下一个又是unicode编码的字符会进行unicode解码同时isJavadoc属性会赋值true
接着往下我们的\uabcd
是乱码字符和下面条件也不符合所以也不继续走了简单看看代码呗,不走的原因一方面是这个下一个字符不是\n
另一方面checkNonExternalizedStringLiterals在我这个tomcat版本默认为false
但是我还是好奇的看了一眼parseTags函数,在里面处理的注释前缀是TAG_PREFIX = "//$NON-NLS-".toCharArray();
,以及IDENTITY_COMPARISON_TAG = "//$IDENTITY-COMPARISON$"
很神奇简单考古可以看到https://stackoverflow.com/questions/654037/what-does-non-nls-1-mean,从描述可以看出作用是为了国际化,但更具体的可以看看官方的这篇文章了解写的很详细https://www.eclipse.org/articles/Article-Internationalization/how2I18n.html
当然肯定能在这个层面上做更多的混淆,接下来的灵活的工作就交给大家自己构造了,感谢我yzddmr6,之前还没想到可以这样
但是还是不知道如果默认属性开的情况下,为什么出现//\u000d\u000a
或//\u000d\u000d
就会判别是要去识别那两个标签,希望有懂的师傅说说