cnhackteam7 发布于2022年11月8日 分享 发布于2022年11月8日 0x00 前言 在上篇文章《Zimbra漏洞调试环境搭建》 提到了通过反射枚举JspServletWrapper实例的实现,本文将要以此为例,详细介绍实现的思路和细节,便于以此类推,实现其他功能。 0x01 简介 本文将要介绍以下内容: 反射中的常用操作 获得类的所有字段 获得类的所有方法 调用类的方法 枚举JspServletWrapper实例的实现细节 0x02 反射中的常用操作 1.获得类的所有字段 getField(): 能够获取本类以及父类中的公众的字段 getDeclaredField(): 能够获取本类中的所有字段 这里以津布拉环境为例,给出示例代码 (1)获取request对象的所有字段 %@个页面导入='java.lang.reflect.Field' % % Field[] fields=request.getClass().getDeclaredFields(); for(int I=0;我字段。长度;i ) { out.println(fields[i].getName()' '); } % (2)获取request对象的父类的所有字段 %@个页面导入='java.lang.reflect.Field' % % Field[] fields=request.getClass().getSuperclass().getDeclaredFields(); for(int I=0;我字段。长度;i ) { out.println(fields[i].getName()' '); } % 2.获得类的所有方法 getMethods(): 能够获取本类以及父类或者父接口中的公共方法(公共修饰符修饰的) getDeclaredMethods(): 能够获取本类中的所有方法,包括私人的、受保护的、默认以及公众的的方法 这里以津布拉环境为例,给出示例代码 (1)获取request对象的所有方法 %@个页面导入='java.lang.reflect.Field '% %@个页面导入='java.lang.reflect.Method '% % 方法[]方法=请求。getclass().getDeclaredMethods(); 对于(方法方法:方法){ out.print(method.getName()' '); } % (2)获取request对象的父类的所有方法 %@个页面导入='java.lang.reflect.Field '% %@个页面导入='java.lang.reflect.Method '% % 方法[]方法=请求。getclass().getSuperclass().getDeclaredMethods(); 对于(方法方法:方法){ out.print(method.getName()' '); } % 3.调用类的指定方法 这里以津布拉环境为例,给出示例代码 搭建好津布拉漏洞调试环境后,定位请求对象的getHeader(字符串名称)方法,代码细节如下: 公共字符串getHeader(字符串名称){ org。月食。码头。http。元数据。请求元数据=这个._元数据; 返回元数据==null?null : metadata.getFields().获取(名称); } 对照代码细节,参数类型为线 调用请求对象的getHeader(字符串名称)方法,参数为'用户代理,实现代码如下: %@个页面导入='java.lang.reflect.Field '% %@个页面导入='java.lang.reflect.Method '% % 方法m1=request.getClass().getDeclaredMethod('getHeader ',字符串。类); out.println(m1.invoke(请求,'用户代理')); % 0x03 枚举JspServletWrapper实例的实现细节 1.下断点 选择文件servlet-api-3.1.jar,依次选中javax。http-http servlet。类,在合适的位置下断点,当运行到断点时,可以查看请求对象的完整结构,如下图 查看请求对象的结构,我们最终定位到了JspServletWrapper实例的位置,直观的映射为:请求-_范围-_ servlet-RCT XT-JSP 接下来,我们需要按照这个映射,通过多次反射最终获得JspServletWrapper实例 (1)读取request对象的所有字段 %@个页面导入='java.lang.reflect.Field' % % Field[] fields=request.getClass().getDeclaredFields(); for(int I=0;我字段。长度;i ) { out.println(fields[i].getName()' '); } % 在回显的结果中能够找到_范围 (2)从request对象获得_scope实例并再次枚举字段 %@个页面导入='java.lang.reflect.Field' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); Field[] fields=obj1.getClass().getDeclaredFields(); for(int I=0;我字段。长度;i ) { out.println(fields[i].getName()' '); } % 在回显的结果中能够找到_servlet (3)获得_servlet实例并再次枚举字段 %@个页面导入='java.lang.reflect.Field' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); f=obj1.getClass().getDeclaredField(' _ servlet '); f。设置可访问性(true); object obj 2=f . get(obj 1); Field[] fields=obj2.getClass().getDeclaredFields(); for(int I=0;我字段。长度;i ) { out.println(fields[i].getName()' '); } % 回显的结果为:serialVersionUID 这里没有rctxt字段 尝试寻找原因:开启调试器,定位至关键位置,如下图 从图中可以看到,_servlet的类为JettyJspServlet JettyJspServlet继承自JspServlet,成员变量只有serialVersionUID,这与我们通过访问jsp页面得到的结果一致 查看JspServlet的相关实现代码,如下图 从图中可以看到,rctxt为JspServlet的成员变量,属性为私人的,所以子类JettyJspServlet无法继承成员变量rctxt 这里我们可以直接选取_servlet实例的父类进行枚举字段 (4)选取_servlet实例的父类进行枚举字段 %@个页面导入='java.lang.reflect.Field' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); f=obj1.getClass().getDeclaredField(' _ servlet '); f。设置可访问性(true); object obj 2=f . get(obj 1); f=obj2.getClass().getSuperclass().getDeclaredField(' rctxt '); f。设置可访问性(true); object obj 3=f . get(obj 2); Field[] fields=obj3.getClass().getDeclaredFields(); for(int I=0;我字段。长度;i ) { out.println(fields[i].getName()' '); } % 在回显的结果中能够找到JSP (5)获得jsps实例并枚举字段 开启调试器,查看JSP的类型,如下图 从图中可以看到,JSP的类为并发哈希表,这里只需要枚举出所有钥匙即可 添加需要导入的包后,得出最终实现代码: %@个页面导入='java.lang.reflect.Field' % %@个页面导入=' Java。util。并发。并发哈希表' % %@个页面导入=' Java . util . * ' ' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); f=obj1.getClass().getDeclaredField(' _ servlet '); f。设置可访问性(true); object obj 2=f . get(obj 1); f=obj2.getClass().getSuperclass().getDeclaredField(' rctxt '); f。设置可访问性(true); object obj 3=f . get(obj 2); f=obj3.getClass().getDeclaredField(' JSP '); f。设置可访问性(true); 并发hashmap obj 4=(并发hashmap)f . get(obj 3); 枚举enu=obj 4。keys(); while (enu.hasMoreElements()) { out.println(enu.nextElement()' '); } % 补充:删除指定JspServletWrapper的实例 只需要调用并发哈希表的去除方法即可 示例代码: %@个页面导入='java.lang.reflect.Field' % %@个页面导入=' Java。util。并发。并发哈希表' % %@个页面导入=' Java . util . * ' ' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); f=obj1.getClass().getDeclaredField(' _ servlet '); f。设置可访问性(true); object obj 2=f . get(obj 1); f=obj2.getClass().getSuperclass().getDeclaredField(' rctxt '); f。设置可访问性(true); object obj 3=f . get(obj 2); f=obj3.getClass().getDeclaredField(' JSP '); f。设置可访问性(true); 并发hashmap obj 4=(并发hashmap)f . get(obj 3); obj 4。移除('/test。JSP’); % 0x04 小结 本文介绍了通过反射枚举JspServletWrapper实例的具体实现,记录思路和细节,便于以此类推,修改其他内容。 留下回复 链接帖子 意见的链接 分享到其他网站 更多分享选项…
推荐的帖子