技術乾貨丨Java Web本地提權以及資料劫持思路(以Tomcat為例)
最近偶然接觸到一個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加密的內容也可以修改和盜取。
這並不是一個Bug或者漏洞,而是一個完全正規的Java特性,所以。。。
應該是不可被修復的吧。
*本文作者:jfeiyi 。轉載請註明來自FreeBuf.com
置頂懸鏡安全實驗室公眾號,給你最新,最有料的資訊,安全技術乾貨。