Tomcat AJP协议包伪造
2023-03-14 10:32:13 时间
部署到Tomcat上的应用一般会搭配一个Apache,
从浏览器(或其他User Agent)发送的请求要经过两个协议才能转到Tomcat:
请求 => http协议 => Apache => ajp协议 => Tomcat
从这个处理链来看,ajp协议数据包只能由Apache生成,
用户不能通过浏览器(或其他User Agent)直接发送ajp协议数据包到Tomcat。
从Apache发送到Tomcat的ajp协议数据包主要有下面几种类型:
类型代码用1个字节表示,
Data类型没有类型代码,它的数据包的前两个字节表示包的长度,并且采用大端编码(BigEndian),
比如长度1792采用大端编码是0x0700,放到字节数组时,buf[0]=07, buf[1]=00
看到没有,如果长度等于1792,第一个字节buf[0]=07,也是Shutdown数据包的类型代码,
前面说了我们不能自己构造ajp协议数据包,
加上Forward Request和Data是一个整体,所以Data数据包一般情况不把它看成一条特殊指令,
不过奇迹总是可以发生的。
Tomcat是怎么处理ajp协议数据包的呢?
Shutdown 和CPing 不会有请求体,
所以Tomcat收到这两种类型的包后就马上处理了,然后返回响应,
Forward Request 可以有Data,比如POST请求就可以有,
但是呢,Tomcat采用的是延迟读入策略,比如说POST请求体中包含了一个表单参数name=myname
只有当你在servlet中显示调用request.getParameter(“name”)时Tomcat才读入表单数据包,
如果你什么都不做,这个表单数据包还在InputStream中没被读出来,
此时Tomcat认为这个Forward Request 已经处理完了,但是连接没有关闭,所以InputStream也没有关,
接着Tomcat继续处理下一个请求,这次它从InputStream中读出的是上次剩下的表单Data数据包,
当它取出这个数据包的第一个字节时,因为数据包长度的第一个字节可能是02、07、0A(10),
所以只要用心构造一个POST请求就能让Tomcat执行错误操作。
我们知道访问静态资源文件(比如html,jpg)是不会产生request.getParameter这样的调用的,
所以只要构造一个类似这样的请求就可以了:
这样一个请求理论上就能关掉Tomcat,
不过,Tomcat实际上忽略Shutdown数据包了(Jetty倒是实现了).
下面举两个例子:
从浏览器(或其他User Agent)发送的请求要经过两个协议才能转到Tomcat:
请求 => http协议 => Apache => ajp协议 => Tomcat
从这个处理链来看,ajp协议数据包只能由Apache生成,
用户不能通过浏览器(或其他User Agent)直接发送ajp协议数据包到Tomcat。
从Apache发送到Tomcat的ajp协议数据包主要有下面几种类型:
写道
类型代码 类型 说明
=================================================
2 Forward Request 从Apache转发过来的请求头
7 Shutdown 关闭Tomcat
10 CPing 心跳检测
没有 Data 从Apache转发过来的请求体
=================================================
2 Forward Request 从Apache转发过来的请求头
7 Shutdown 关闭Tomcat
10 CPing 心跳检测
没有 Data 从Apache转发过来的请求体
类型代码用1个字节表示,
Data类型没有类型代码,它的数据包的前两个字节表示包的长度,并且采用大端编码(BigEndian),
比如长度1792采用大端编码是0x0700,放到字节数组时,buf[0]=07, buf[1]=00
看到没有,如果长度等于1792,第一个字节buf[0]=07,也是Shutdown数据包的类型代码,
前面说了我们不能自己构造ajp协议数据包,
加上Forward Request和Data是一个整体,所以Data数据包一般情况不把它看成一条特殊指令,
不过奇迹总是可以发生的。
Tomcat是怎么处理ajp协议数据包的呢?
Shutdown 和CPing 不会有请求体,
所以Tomcat收到这两种类型的包后就马上处理了,然后返回响应,
Forward Request 可以有Data,比如POST请求就可以有,
但是呢,Tomcat采用的是延迟读入策略,比如说POST请求体中包含了一个表单参数name=myname
只有当你在servlet中显示调用request.getParameter(“name”)时Tomcat才读入表单数据包,
如果你什么都不做,这个表单数据包还在InputStream中没被读出来,
此时Tomcat认为这个Forward Request 已经处理完了,但是连接没有关闭,所以InputStream也没有关,
接着Tomcat继续处理下一个请求,这次它从InputStream中读出的是上次剩下的表单Data数据包,
当它取出这个数据包的第一个字节时,因为数据包长度的第一个字节可能是02、07、0A(10),
所以只要用心构造一个POST请求就能让Tomcat执行错误操作。
我们知道访问静态资源文件(比如html,jpg)是不会产生request.getParameter这样的调用的,
所以只要构造一个类似这样的请求就可以了:
这样一个请求理论上就能关掉Tomcat,
不过,Tomcat实际上忽略Shutdown数据包了(Jetty倒是实现了).
下面举两个例子:
*/
本文来源于"阿里中间件团队播客",原文发表时间" 2011-09-10"
相关文章
- 负载均衡 - 高并发网关设计原理与实践
- Java开发工具IntelliJ IDEA 2020.2完整授权流程
- JVM-内存结构篇笔记
- CSDN蓝桥杯算法题——题解Java版本——切面条
- 第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-195 1的个数
- 第十四届蓝桥杯集训——练习解题阶段(无序阶段)-A+B问题四种语言比较
- Java解析XML的实践
- 为什么说写 Java 的人 for循环得用好?
- Java工程师多年之后看指针
- 类是如何加载的?
- 1.类加载器
- 面试必问:说一下 Java 虚拟机的内存布局?
- 对线面试官:浅聊一下 Java 虚拟机栈?
- 为什么用元空间替代永久代?
- 9 个 yyds 的 Java 项目,可应对各种私活!
- Java 实现读取出来的文件大小变成KB,MB,TB,PB大小,或者将大单位变成KB
- 搞明白 Java 的通配符泛型
- Java 动态代理机制 (一) JDK Proxy详解
- java-内部类
- java-接口、lambda表达式