【网络安全】SQL注入_sql注入攻击实例(网安人必学系列)

news2025/1/20 15:41:52

1.1 .Sql注入攻击原理

SQL注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一,它也是目前被利用得最多的漏洞。要学会如何防御SQL注入,首先我们要学习它的原理。

针对SQL注入的攻击行为可描述为通过在用户可控参数中注入SQL语法,破坏原有SQL结构,达到编写程序时意料之外结果的攻击行为。

其成因可以归结为以下两个原因叠加造成的:

**1.**程序编写者在处理应用程序和数据库交互时,使用字符串拼接的方式构造SQL语句。未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。
**2.**注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件:用户能够控制输入。原本程序要执行的代码,拼接了用户输入的数据。

1.2 .Sql审计方法

手动找的话,可以直接找到sqlmapper.xml文件或者直接搜索 select、update、delete、insert “String sql=”等关键词,定位SQL xml配置文件。

如果 sql 语句中有出现 $ 进行参数拼接,则存在SQL注入风险。

当找到某个变量关键词有 SQL 注入风险时,可以再根据调用链找到该存在注入风险的业务逻辑代码,查看参数来源是否安全、是否有配置SQL危险参数过滤的过滤器,最终确认是否存在SQL注入。以下给出可能造成sql注入攻击的关键字,审计时可根据实际情况进项查找

常见SQL语句关键词

在这里插入图片描述

1.3Sql注入漏洞危害

1 、 攻击者可以做到

  • 业务运营的所有数据被攻击

  • 对当前数据库用户拥有的所有表数据进行增、删、改、查等操作

  • 若当前数据库用户拥有file_priv权限,攻击者可通过植入木马的方式进一步控制DB所在服务器

  • 若当前数据库用户为高权限用户,攻击者甚至可以直接执行服务器命令从而通过该漏洞直接威胁整个内网系统

2、可能对业务造成的影响

① 用户信息被篡改

② 攻击者偷取代码和用户数据恶意获取

线上代码被非法篡改,并造成为恶意攻击者输送流量或其他利益的影响

为了帮助大家更好的学习网络安全,参加护网行动,我给大家准备了一份网络安全入门/进阶学习资料,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂这些资料!

因篇幅有限,仅展示部分资料,需要扫描下方卡片即可前往获取

1.4 Sql注入漏洞代码示例

Java 代码动态构建 SQL

Statement stmt = null;

ResultSet rs = null;

try{

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + request.getParameter("itemName") + "'";

stmt = connection.createStatement();

rs = stmt.executeQuery(sqlString);

// ... result set handling

}

catch (SQLException se){

// ... logging and error handling

}

这里将查询字符串常量与用户输入进行拼接来动态构建SQL查询命令。仅当itemName不包含单引号时,这条查询语句的行为才会是正确的。如果一个攻击者以用户名wiley发起一个请求,并使用以下条目名称参数进行查询:

name' OR 'a' = 'a

那么这个查询将变成:

SELECT * FROM t_item WHERE owner = 'wiley' AND itemname = 'name' OR 'a'='a';

此处,额外的OR ‘a’='a’条件导致整个WHERE子句的值总为真。那么,这个查询便等价于如下非常简单的查询:

SELECT * FROM t_item

这个简化的查询使得攻击者能够绕过原有的条件限制:这个查询会返回items表中所有储存的条目,而不管它们的所有者是谁,而原本应该只返回属于当前已认证用户的条目。

在存储过程中动态构建SQL

Java代码:

CallableStatement = null

ResultSet results = null;

try

{

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

cs = connection.prepareCall("{call sp_queryItem(?,?)}");

cs.setString(1, userName);

cs.setString(2, itemName);

results = cs.executeQuery();

// ... result set handling

}

catch (SQLException se)

{

// ... logging and error handling

}

SQL Server存储过程:

CREATE PROCEDURE sp_queryItem

@userName varchar(50),

@itemName varchar(50)

AS

BEGIN

DECLARE @sql nvarchar(500);

SET @sql = 'SELECT * FROM t_item

WHERE owner = ''' + @userName + '''

AND itemName = ''' + @itemName + '''';

EXEC(@sql);

END

GO

在存储过程中,通过拼接参数值来构建查询字符串,和在应用程序代码中拼接参数一样,同样是有SQL注入风险的。

Hibernate 动态构建 SQL/HQL

原生SQL查询:

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

Query sqlQuery = session.createSQLQuery("select * from t_item where owner = '" + userName + "' and itemName = '" + itemName + "'");

List<Item> rs = (List<Item>) sqlQuery.list();

HQL查询:

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

Query hqlQuery = session.createQuery("from Item as item where item.owner = '" + userName + "' and item.itemName = '" + itemName + "'");

List<Item> hrs = (List<Item>) hqlQuery.list();

即使是使用Hibernate,如果在动态构建SQL/HQL查询时包含了不可信输入,同样也会面临SQL/HQL注入的问题。

HQL代码中,session.createQuery使用HQL语句将查询到的数据存到到list集合中,需要时在拿出来使用。而参数中itemName是通过request.getParameter直接获取。攻击者若在此处写入恶意语句,程序将恶意语句查询出来的数据存放在list集合中,再通过某处调用成功将数据显示在前台。

1.5 .实战案例-OFCMS SQL注入漏洞分析

本文中使用ofcms进行SQL注入漏洞讲解,此CMS算是对新手学习代码审计比较友好的CMS。
在这里插入图片描述
上述为安装成功页面,如何安装CMS本章不在赘述。

后台页面:http://localhost:8080/ofcms-admin/admin/index.html
在这里插入图片描述
漏洞点:

ofcms-admin/src/main/java/com/ofsoft/cms/admin/controller/system/SystemGeneratrController.java

create方法

| 

/**

* 创建表

*/

public void create() {

try {

String sql = getPara("sql");

Db.update(sql);

rendSuccessJson();

} catch (Exception e) {

e.printStackTrace();

rendFailedJson(ErrorCode.get("9999"), e.getMessage());

}

}

上述代码中使用getpara获取sql的参数值,并update,跟进一下getpara和update方法。

跳转至 jfinal-3.2.jar/com/jfinal/core/controller.class

public String getPara(String name) {

return this.request.getParameter(name);

}

上述代码无特殊用意,就是获取参数值,继续跟进 Db.update 方法。

跳转至 jfinal-3.2.jar/com/jfinal/plugin/activerecord/Db.class

public static int update(String sql) {

return MAIN.update(sql);

}

发现调用 MAIN.update , 继续跟进。

跳转至 jfinal-3.2.jar/com/jfinal/plugin/activerecord/DbPro.class

public int update(String sql) {

return this.update(sql, DbKit.NULL_PARA_ARRAY);

}

继续跟进到最后,发现华点。

public int update(String sql, Object... paras) {

Connection conn = null;

int var4;

try {

conn = this.config.getConnection();//连接

var4 = this.update(this.config, conn, sql, paras);//调用update更新

} catch (Exception var8) {

throw new ActiveRecordException(var8);

} finally {

this.config.close(conn);

}

return var4;

}

重点:Object…

Object是所有类的基类,而 Object… 是不确定方法参数情况下的一种多态表现形式(可以传递多个参数)。

再继续跟进 update ,同文件代码

int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {

PreparedStatement pst = conn.prepareStatement(sql);

config.dialect.fillStatement(pst, paras);

int result = pst.executeUpdate();

DbKit.close(pst);

return result;

}

上述代码执行SQL语句,并返回结果。

至此,整个功能流程结束,在我们跟进的过程中,代码中无任何过滤语句,获取参数值,调用update方法更新,更新成功后返回结果。

漏洞验证
在这里插入图片描述
漏洞点打上断点,网页中输入poc进行验证

update of_cms_topic set topic_url=updatexml(1,concat(0x7e,(user())),0) where topic_id = 1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据如上截图可看出我们传入的SQL语句是被完整的接收,并未做任何过滤直接带入数据库执行,所以此处直接写入漏洞代码爆出当前数据库账户为 root。

上述为sqlmap工具跑出来的注入点。

1.6 漏洞修复方法

添加全局过滤器,过滤特殊字符

在这里插入图片描述
SQLFilter.java中:

在这里插入图片描述

PreparedStatement 参数化

如果使用参数化查询,则在SQL语句中使用占位符表示需在运行时确定的参数值。参数化查询使得SQL查询的语义逻辑被预先定义,而实际的查询参数值则等到程序运行时再确定。参数化查询使得数据库能够区分SQL语句中语义逻辑和数据参数,以确保用户输入无法改变预期的SQL查询语义逻辑。

在Java中,可以使用java.sql.PreparedStatement来对数据库发起参数化查询。在这个正确示例中,如果一个攻击者将itemName输入为name’ OR ‘a’ = ‘a,这个参数化查询将免受攻击,而是会查找一个itemName匹配name’ OR ‘a’ = 'a这个字符串的条目。

PreparedStatement stmt = null

ResultSet rs = null

try

{

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

// ...Ensure that the length of userName and itemName is legitimate

// ...

String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName=?";

stmt = connection.prepareStatement(sqlString);

stmt.setString(1, userName);

stmt.setString(2, itemName);

rs = stmt.executeQuery();

// ... result set handling

}

catch (SQLException se)

{

// ... logging and error handling

}

存储过程参数化
这个存储过程使用参数化查询,而未包含不安全的动态SQL构建。数据库编译此存储过程时,会生成一个SELECT查询的执行计划,只允许原始的SQL语义被执行。任何参数值,即使是被注入的SQL语句也不会被执行,因为它们不是执行计划的一部分。

CallableStatement = null

ResultSet results = null;

try

{

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

// ... Ensure that the length of userName and itemName is legitimate

// ...

cs = connection.prepareCall("{call sp_queryItem(?,?)}");

cs.setString(1, userName);

cs.setString(2, itemName);

results = cs.executeQuery();

// ... result set handling

}

catch (SQLException se)

{

// ... logging and error handling

}

Hibernate 参数化查询
Hibernate支持SQL/HQL参数化查询。为了防止SQL注入以及改善性能,以上这些示例使用了参数化绑定 的方式来设置查询参数。

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

Query hqlQuery = session.createQuery("from Item as item where item.owner = ? and item.itemName = ?");

hqlQuery.setString(1, userName);

hqlQuery.setString(2, itemName);

List<Item> rs = (List<Item>) hqlQuery.list();

HQL基于名称的参数化查询

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

Query hqlQuery = session.createQuery("from Item as item where item.owner = :owner and item.itemName = :itemName");

hqlQuery.setString("owner", userName);

hqlQuery.setString("itemName", itemName);

List<Item> rs = (List<Item>) hqlQuery.list();

原生参数化查询

String userName = ctx.getAuthenticatedUserName(); //this is a constant

String itemName = request.getParameter("itemName");

Query sqlQuery = session.createSQLQuery("select * from t_item where owner = ? and itemName = ?");

sqlQuery.setString(0, owner);

sqlQuery.setString(1, itemName);

List<Item> rs = (List<Item>) sqlQuery.list();

MyBatis框架的修复方案

尽量使用#描述参数,如果一定要使用$,则需要自己过滤用户输入

模糊查询like SQL注入修复建议

按照新闻标题对新闻进行模糊查询,可将SQL查询语句设计如下:

select * from news where name like concat(%,#{name },%)

采用预编译机制,避免了SQL语句拼接的问题,从根源上防止了SQL注入漏洞的产生。

in之后的参数SQL注入修复建议

在对新闻进行同条件多值查询的时候,可使用Mybatis自带循环指令解决SQL语句动态拼接的问题:

select * from news where id in<foreach collection="ids" item="item" open="("separator="," close=")">#{item} </foreach>

在Java层面做映射预编译机制只能处理查询参数,其他地方还需要研发人员根据具体情况来解决。如前面提到的排序情景:

Select * from news where title =‘淘宝’ order by #{time} asc,

这里time不是查询参数,无法使用预编译机制,只能这样拼接:

Select * from news where title =‘淘宝’ order by ${time} asc

针对这种情况研发人员可以在java层面做映射来进行解决。如当存在发布时间time和点击量click两种排序选择时,我们可以限制用户只能输入1和2。

当用户输入1时,我们在代码层面将其映射为time,当用户输入2时,将其映射为click。而当用户输入1和2之外的其他内容时,我们可以将其转换为默认排序选择time(或者click)。

为了帮助大家更好的学习网络安全,参加护网行动,我给大家准备了一份网络安全入门/进阶学习资料,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂这些资料!

因篇幅有限,仅展示部分资料,需要扫描下方卡片即可前往获取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

容器镜像详解

1. 镜像组成 一个标准的OCI容器镜像由index, manifest, config, image layers这几个部分组成。 以docker镜像为例&#xff0c;下载的镜像文件保存在/var/lib/docker/目录下面 image/overlay2子目录下面保存着镜像相关的一些元数据 在下面的介绍主要以nginx:latest镜像为例子…

Django定时任务之django_apscheduler使用

Django定时任务之django_apscheduler使用 今天在写一个任务需求时需要用到定时任务来做一部分数据处理与优化&#xff0c;于是在了解完现有方法&#xff0c;结合自己需求决定使用django_apscheduler&#xff0c;记录一下过程&#xff0c;有几篇值得参考的文章放在结尾&#xf…

超详细!彻底说明白Redis持久化

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 Redis持久化方式RDBfork 函数与写时复制RDB 相关配置 AOFAOF 文件解读AOF 的写入与同步AOF 重写AOF重写的实现AOF 重写面临的问题AOF重写缓存区 AOF相关配置AOF …

【深入了解设计模式】适配器设计模式

适配器设计模式 适配器设计模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换成客户端所期望的另一个接口&#xff0c;从而使得原本由于接口不兼容而不能一起工作的类能够一起工作。适配器模式通常用于以下场景&#xff1a; 现有接口与需求不匹配&#xff1a;当需要…

Escalate_Linux(4)-利用SUDO实现提权

利用SUDO实现提权 利用用户的sudo授权获得root的shell cat /etc/passwd cat /etc/sudoers 命令没有权限 echo "cat /etc/sudoers" >/tmp/ls chmod 755 /tmp/ls export PATH/tmp:$PATH /home/user5/script 想办法更改user1的口令 echo echo "user1:xiao…

【C语言基础】:操作符详解(一)

文章目录 操作符详解1. 操作符的分类2. 二进制和进制转换2.1 什么是二进制、八进制、十进制、十六进制2.1.1 二进制和进制转换2.1.2 二进制转十进制2.2.3 二进制转八进制2.2.4 二进制转十六进制 3. 源码、反码、补码4. 移位操作符4.1 左移操作符4.2 右移操作符 5. 位操作符&…

协议的概念+本质+作用+最终表现形式,网络问题(技术+应用+解决的协议+存在原因),主机的对称性

目录 协议 概念 示例 -- 摩斯密码 本质 作用 网络问题 引入 技术问题 应用问题 主机的对称性 问题对应的协议 问题出现的原因 理解协议(代码层面) 举例 -- 快递单 协议的最终表现形式 协议被双方主机认知的基础 协议 概念 协议是在计算机通信和数据传输中规定通…

Seata Server 服务搭建

概述 Seata 分布式事务需要 Seata Seaver 支持&#xff0c;Seata Server在 架构中扮演着 事务管理器的角色。Seata 服务需要往 Nacos 注册中心注册、以及读取配置文件&#xff0c;因此 Seata 启动前需要部署 Nacos 环境。 安装包下载 下载地址: https://download.csdn.net/dow…

【Redis学习笔记03】Java客户端

1. 初识Jedis Jedis的官网地址&#xff1a;https://github.com/redis/jedis 1.1 快速入门 使用步骤&#xff1a; 注意&#xff1a;如果是云服务器用户使用redis需要先配置防火墙&#xff01; 引入maven依赖 <dependencies><!-- 引入Jedis依赖 --><dependency&g…

CSS 的圆角矩形

CSS 的圆角矩形 通过 border-radius 属性使矩形边框带圆角效果成为圆角矩形 语法&#xff1a;border-radius: length; length 是内切圆的半径&#xff0c;其数值越大, 弧线越明显 border-radius 属性值描述length定义圆角的形状%以百分比定义圆角的形状 生成圆形 让 border-…

英伟达狂飙,上演大象坐火箭

英伟达市值破 2W 亿 这两天全球资本市场最大的事情就是英伟达&#xff08;NVDA&#xff09;公布了财报。 本来市场&#xff08;分析师&#xff09;的预期就高&#xff0c;结果财报公布比预期还要高出不少。 NVDA 直接上演「大象坐火箭」&#xff0c;在财报公布后的第一个交易日…

Spring Cloud Gateway官方文档学习

文章目录 推荐写在前面一、熟悉Gateway基本概念与原理1、三大概念2、工作流程 二、基本使用路由断言的两种写法 三、路由断言工厂1、After路由断言工厂2、Before路由断言工厂3、Between路由断言工厂4、Cookie路由断言工厂5、Header路由断言工厂6、Host路由断言工厂7、Method路由…

[C++]18:set和map的使用

set和map的使用 一.关联式容器&#xff1a;1.简单概念&#xff1a;2.<key , value>--->键值对3.set和map的底层结构&#xff08;平衡搜索树或者红黑树&#xff09; 二.set1.set (排序不重复)1.模板参数&#xff1a;2.set是一个有序存储的容器&#xff1a;3.set中每个数…

STL常用容器(string容器)---C++

STL常用容器目录 1.string容器1.1 string基本概念1.2 string构造函数1.3 string赋值操作1.4 string字符串拼接1.5 string查找和替换1.6 string字符串比较1.7 string字符存取1.8 string插入和删除1.9 string子串 1.string容器 1.1 string基本概念 本质&#xff1a; string是C…

Peter算法小课堂—动态规划

Peter来啦&#xff0c;好久没有更新了呢 今天&#xff0c;我们来讨论讨论提高组的动态规划。 动态规划 动态规划有好多经典的题&#xff0c;有什么背包问题、正整数拆分、杨辉三角……但是&#xff0c;如果考到陌生的题&#xff0c;怎么办呢&#xff1f;比如说2000年提高组的…

计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号程序员刘同学&#xff0c;回复思科获取下载链接。 实验目的实验环境实验内容MAC地址、IP地址、ARP协议总线型以太网的…

渗透工具——kali中wpscan简介

一、什么是wpscan 1、常用于做用户名枚举爆破 2、WPScan是一个扫描 WordPress 漏洞的黑盒子扫描器&#xff0c;它可以为所有 Web 开发人员扫描 WordPress 漏洞并在他们开发前找到并解决问题。我们还使用了 Nikto &#xff0c;它是一款非常棒的Web 服务器评估工具&#xff0c;…

MySQL数据库调优之关联查询、排序查询、分页查询、子查询、Group by优化

关联查询优化 1.准备工作 CREATE TABLE IF NOT EXISTS type(id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,card INT(10) UNSIGNED NOT NULL,PRIMARY KEY(id));CREATE TABLE IF NOT EXISTS book( bookid INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, card INT(10) UNSIGNED N…

智慧应急与物联网相结合:物联网技术如何提升智慧应急响应能力

目录 一、引言 二、智慧应急与物联网技术的结合 三、物联网技术提升智慧应急响应能力的途径 四、物联网技术在智慧应急中的应用案例 五、物联网技术在智慧应急中面临的挑战与解决方案 挑战一&#xff1a;技术标准与规范不统一 解决方案&#xff1a; 挑战二&#xff1a;…

【考研数学】基础阶段习题1800和660怎么选❓

我建议以1800题为主 1800题包含基础和强化两部分&#xff0c;基础部分题量很大&#xff0c;类型也很全面&#xff0c;并且难度一点也不高&#xff0c;适合基础不好的学生来做。 660题难度比较大&#xff0c;不适合基础阶段做。 660题虽然名字叫基础训练&#xff0c;但是不适…