网站首页 > java教程 正文
2022 年 3 月 8 日
0x00 前言
在上篇文章《Zim 开源环境实现实现》中提到了通过反射枚举 JServletWrapper 实例的实现,本文将通过各种细节、细节和细节来实现,以便于介绍诸如此类、调试其他功能。
0x01简介
本文将要介绍以下内容:
- 反射中的常用操作
- 获得同类的所有领域
- 获得类的所有方法
- 类的方法
- 枚举JspServletWrapper实例的实现细节
0x02 反射中的常用操作
1. 获得类的所有领域
获取字段():
能够获取本类以及父类中的公共场所
getDeclaredField():
能够获取本类中的所有领域
这里以 Zimbra 环境,提供示例代码
(1) 请求对象的所有获取
<%@ page import="java.lang.reflect.Field" %>
<%
Field[] fields=request.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
out.println(fields[i].getName() + "<br>");
}
%>
(2) 获取对象的父类的所有字段
<%@ page import="java.lang.reflect.Field" %>
<%
Field[] fields=request.getClass().getSuperclass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
out.println(fields[i].getName() + "<br>");
}
%>
2.获得类的所有方法
获取方法():
公共获取本类以及父类或父接口中的方法(公共物质符物质的)
getDeclaredMethods():
获取本类中的所有方法,包括私有的、受保护的、默认的以及公共的方法
这里以 Zimbra 环境,提供示例代码
(1)获取请求对象的所有方法
<%@ page import="java.lang.reflect.Field "%>
<%@ page import="java.lang.reflect.Method "%>
<%
Method[] methods = request.getClass().getDeclaredMethods();
for(Method method:methods){
out.print(method.getName() + "<br>");
}
%>
(2)获取请求对象的父类的所有方法
<%@ page import="java.lang.reflect.Field "%>
<%@ page import="java.lang.reflect.Method "%>
<%
Method[] methods = request.getClass().getSuperclass().getDeclaredMethods();
for(Method method:methods){
out.print(method.getName() + "<br>");
}
%>
3.调用类的指定方法
这里以 Zimbra 环境,提供示例代码
类似问题的解决方法Zimbra漏洞,解决问题的getHeader(String name)方法,细节:
public String getHeader(String name) {
org.eclipse.jetty.http.MetaData.Request metadata = this._metaData;
return metadata == null ? null : metadata.getFields().get(name);
}
对照组代码细节,参数类型为String
调用请求对象的getHeader(String name)方法,参数为"User-Agent",实现如下:
<%@ page import="java.lang.reflect.Field "%>
<%@ page import="java.lang.reflect.Method "%>
<%
Method m1 = request.getClass().getDeclaredMethod("getHeader", String.class);
out.println(m1.invoke(request, "User-Agent"));
%>
0x03 枚举JspServletWrapper实例的实现细节
1.下断点
选择文件servlet-api-3.1.jar,截断点javax.servlet-> http-> HttpServlet.class,当在某个位置运行的位置下断点,到点时,可以查看请求对象的完整结构,如下图
查看请求对象的结构,最终我们定位到了JspServlet实例的位置,映射的Wrapper为:request-> _scope-> _servlet-> rctxt->jsps
,需要按照这个映射,通过多次发射我们最终获得JspServletWrapper实例
(1) 读取请求对象的所有字段
<%@ page import="java.lang.reflect.Field" %>
<%
Field[] fields=request.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
out.println(fields[i].getName() + "<br>");
}
%>
在回显的结果中能够找到_scope
(2) 从请求对象获得_scope实例并再次枚举字段
<%@ page import="java.lang.reflect.Field" %>
<%
Field f = request.getClass().getDeclaredField("_scope");
f.setAccessible(true);
Object obj1 = f.get(request);
Field[] fields=obj1.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
out.println(fields[i].getName() + "<br>");
}
%>
在回显的结果中能够找到_servlet
(3)获取_servlet实例并重新枚举字段
<%@ page import="java.lang.reflect.Field" %>
<%
Field f = request.getClass().getDeclaredField("_scope");
f.setAccessible(true);
Object obj1 = f.get(request);
f = obj1.getClass().getDeclaredField("_servlet");
f.setAccessible(true);
Object obj2 = f.get(obj1);
Field[] fields=obj2.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
out.println(fields[i].getName() + "<br>");
}
%>
回显的结果为:serialVersionUID
这里没有rctxt字段
尝试寻找原因:开启调试器,定位到关键位置,如下图
从图中可以看到,_servlet的类为JettyJspServlet
JettyJspServlet继承自JspServlet,成员只有serialVersionUID,这与我们通过访问jsp结果的结果一致
查看JspServlet的相关实现代码,如下图
从图中可以看到,rctxt 的成员,属性为private,所以子JettyJspServlet 不能继承的成员变量为rctxt
这里可以指定我们_servlet的父类实例直接进行枚举
(4)_servlet对象的父类进行枚举
<%@ page import="java.lang.reflect.Field" %>
<%
Field f = request.getClass().getDeclaredField("_scope");
f.setAccessible(true);
Object obj1 = f.get(request);
f = obj1.getClass().getDeclaredField("_servlet");
f.setAccessible(true);
Object obj2 = f.get(obj1);
f = obj2.getClass().getSuperclass().getDeclaredField("rctxt");
f.setAccessible(true);
Object obj3 = f.get(obj2);
Field[] fields=obj3.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
out.println(fields[i].getName() + "<br>");
}
%>
在回显的结果中能够找到jsps
(5)获取jsps实例并枚举字段
开启调试器,查看jsps的类型,如下图
从图中可以看到,jsps的类为ConcurrentHashMap,这里只需要枚举出所有的Key即可
添加需要导入的包后,最终实现代码:
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.concurrent.ConcurrentHashMap" %>
<%@ page import="java.util.*" %>
<%
Field f = request.getClass().getDeclaredField("_scope");
f.setAccessible(true);
Object obj1 = f.get(request);
f = obj1.getClass().getDeclaredField("_servlet");
f.setAccessible(true);
Object obj2 = f.get(obj1);
f = obj2.getClass().getSuperclass().getDeclaredField("rctxt");
f.setAccessible(true);
Object obj3 = f.get(obj2);
f = obj3.getClass().getDeclaredField("jsps");
f.setAccessible(true);
ConcurrentHashMap obj4 = (ConcurrentHashMap)f.get(obj3);
Enumeration enu = obj4.keys();
while (enu.hasMoreElements()) {
out.println(enu.nextElement() + "<br>");
}
%>
补充:删除指定JspServletWrappers的实例
只需调用ConHashMap的remove方法即可
示例代码:
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.concurrent.ConcurrentHashMap" %>
<%@ page import="java.util.*" %>
<%
Field f = request.getClass().getDeclaredField("_scope");
f.setAccessible(true);
Object obj1 = f.get(request);
f = obj1.getClass().getDeclaredField("_servlet");
f.setAccessible(true);
Object obj2 = f.get(obj1);
f = obj2.getClass().getSuperclass().getDeclaredField("rctxt");
f.setAccessible(true);
Object obj3 = f.get(obj2);
f = obj3.getClass().getDeclaredField("jsps");
f.setAccessible(true);
ConcurrentHashMap obj4 = (ConcurrentHashMap)f.get(obj3);
obj4.remove("/test.jsp");
%>
0x04 小结
本文通过反射枚举 JspServ 修改实例的具体实现,记录思路和细节,便于进行此类推文,其他内容。
猜你喜欢
- 2024-10-12 java基础之反射,反射API的组成,反射机制的应用场景
- 2024-10-12 Java反射与反射优化(java反射与反射优化的区别)
- 2024-10-12 尚学堂讲有关Java反射的那些事(java反射如何通俗易懂理解)
- 2024-10-12 Java面试手册:反射(java面试反射机制)
- 2024-10-12 如何通过反射获得方法的真实参数名(以及扩展研究)
- 2024-10-12 Java中的反射使用(java 反射使用)
- 2024-10-12 Java面试技术,这31个反射问题你都会嘛?(有答案)
- 2024-10-12 Java反射机制详解(java中的反射机制)
- 2024-10-12 测试开发必须掌握的知识点:Java反射
- 2024-10-12 Java反射机制(Java反射机制主要提供了以下哪些功能)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)