[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

时间:2022-12-27 08:04:59

???? 博主介绍

????‍???? 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~
✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】
????点赞➕评论➕收藏 == 养成习惯(一键三连)????
????欢迎关注????一起学习????一起讨论⭐️一起进步????文末有彩蛋
????作者水平有限,欢迎各位大佬指点,相互学习进步!

一、什么是SQL注入?

1、SQL注入

是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程 序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以 此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

2、简单来说

使用某些手段,在原来的SQL语句基础上,添加了一段SQL并执行。从而达到某一些不 被管理员允许的目的。

3、SQL注入危害

一般使用SQL注入,主要是拿数据库里面的数据,所以会导致数据泄露。

4、SQL注入防御

现在使用的最多也最有效的就是预编译功能防止SQL注入。

二、案例

前面我们提交到了SQL注入会造成数据泄露,那他会泄露些什么,又是怎么泄露的呢,我们慢慢往下看。

1、环境搭建

这里我搭建了一个环境存在SQL注入的环境。由于重点是代码审计,建议大家搭建环境自己操作一遍。

源代码下载链接:https://download.csdn.net/download/qq_51577576/87346584
Eclipse下载链接:https://download.csdn.net/download/qq_51577576/87346579
Tomcat下载链接:https://download.csdn.net/download/qq_51577576/87346570

2、工具扫描

使用 fortify 扫描,发现源代码中存在一个SQL注入.

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

3、黑盒测试发现存在SQL注入

1、查看登录逻辑

打开登录页面,简单看一下他的登录逻辑
1、输入正确账号密码,跳转到图书信息列表页面

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2、输入错误密码提示,用户名或者密码错误

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2、测试注入语句

这里我们输入一个万能密码试一下

' or 1=1 #

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

点击登录发现登录成功,怎么登陆页面存在SQL注入

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

4、白盒测试发现存在SQL注入

白盒就是看源代码

1、点击登录发了一个login请求

1、点击登录,我们会发现,其实点击登录之后,会去请求login页面,我们根据源代码一步步进行追踪。
[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2、我们尝试找一下这个login。
3、因为这是页面上的请求,所以我们需要去找servlet,应该在servlet的controller里面。

2、找到了LoginServlet

1、我们在LoginServlet里面找到了这个login。

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2、我们查看这个LoginServlet代码,发现首先拿到了用户名和密码,然后调用了service层的login方法。

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

3、那么接下来我们就需要去寻找service层的login方法。

3、找到service层的这个login方法

我们找到service层的login方法,发现这个login方法没有啥操作,直接调用了dao层的login方法,那接下来我们就需要去dao层。

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

4、找到dao层的这个login方法

我们发现这个daoc层的login方法采用了JDBC连接数据库的方法去连接数据库。
它执行的SQL语句是:

SELECT * from userinfo WHERE userName= '"+uname+" 'and userPass= '"+upass+"'

其实就是拿着这个用户名密码到schooldb里面userinfo表去进行匹配。
匹配的上就跳转,匹配不上就提示错误(LoginServlet执行)。大概就是这么一个逻辑。

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

5、执行的SQL语句

我们来详细的看一下这个SQL语句,为什么输入正确的密码能登陆成功,为什么输入错误密码登陆不成功,为什么输入万能密码登陆成功。

SELECT * from userinfo WHERE userName= '"+uname+" 'and userPass= '"+upass+"'

1、正确账号密码

根据SQL语句的逻辑,其实输入正确账号密码之后执行的SQL语句就是下面这个。账号密码都是admin。

SELECT * from userinfo WHERE userName= 'admin'and userPass= 'admin'

我们在数据库里面执行以下这条SQL语句。
发现找到一条 admin:admin 的数据,能查到结果,证明在 dao 层 login 方法进行匹配时匹配成功了,所以在 LoginServlet 方法种进行了跳转,所以登录成功。

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

那么输入错误的账号密码就是在数据库种找不到输入的账号密码,就是是在dao层login方法种匹配不成功,也就会在 LoginServlet 种进行错误提示,也就登录不成功。

2、输入万能密码

同样的,我们看输入万能密码之后的SQL语句如下。

SELECT * from userinfo WHERE userName= ' 'or 1=1 #'and userPass= 'admin'

发现也能查到结果,所以也能登录成功

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

'or 1=1 #

'先闭合前面的,or 1=1恒成立,一定是真,所以它会查询所有的账号密码,#注释后面的内容,后面的内容不会执行。

我们就可以执行任意恶意的SQL语句,去获取数据库中的数据。

6、SQL注入获取数据

1、SQL语句获取数据

1. 获得当前使用的数据库库名

SELECT DATABASE();

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2. 获得所有的数据库库名

SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

3. 获得表名

SELECT * from information_schema.`TABLES` WHERE TABLE_SCHEMA='schooldb'

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

4. 获得列名

SELECT * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='schooldb' and TABLE_NAME ='userinfo'

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

5. 获取表数据

SELECT userID,userName,userPass from userinfo

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2、SQL注入获取数据

1. 获得当前使用的数据库库名

SELECT DATABASE();
SELECT * from userinfo WHERE userName= ''   union SELECT 1,DATABASE(),2 # and userPass= ''

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2. 获得表名

SELECT * from information_schema.`TABLES` WHERE TABLE_SCHEMA='schooldb'
SELECT * from userinfo WHERE userName= ''   union SELECT 1,GROUP_CONCAT(table_Name),2 from information_schema.`TABLES` WHERE TABLE_SCHEMA='schooldb' # and userPass= ''

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

3. 获得列名

SELECT * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='schooldb' and TABLE_NAME ='userinfo'
SELECT * from userinfo WHERE userName= ''   union SELECT 1,GROUP_CONCAT(column_name) ,2 from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='schooldb' and TABLE_NAME ='userinfo' #and userPass= ''

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

4. 获取表数据

SELECT userID,userName,userPass from userinfo
SELECT * from userinfo WHERE userName= '' union SELECT userID,userName,userpass FROM userinfo  #and userPass= ''

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

7、修复

1、修复过程

这里我们采用的是JDBC自带的预编译功能呢。这里只展示修复过程,详解看下一个部分。

String sql="SELECT * from userinfo WHERE userName= ? and userPass= ?";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1, uname);
ps.setString(2, upass);

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2、修复结果

同样的输入注入语句,提示用户名或密码错误

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

三、SQL注入如何防止?

1、防御措施

1、预编译
2、内容过滤
3、引号转义(转义)
4、错误信息(报错注入)
5、数据库权限(严格的权限控制,你只能干什么)
6、数据加密(拿到数据解不了密)
7、应用防火墙(WAF)

2.JDBC防止SQL注入

4.4.1 拼接原理

SQL注入到底是怎么发生的,为什么他能拼接我的SQL注入,以及在代码层次如何防御

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

变量和SQL语句通过+连接,这个uname可以是任何的字符串,当然也可以是SQL语句,我们怎么解决这个问题呢

4.4.2 在JDBC里面提供了一个解决方案

在处理SQL语句的时候我们不能使用Statement这个对象,这个对象会原封不动的执行SQL语句

而要使用PreparedStatement这个对象,他会预编译之后才去执行

SELECT * from userinfo WHERE userName= '?'and userPass= '?'

不管你传进来的什么值我一直把你当字符串,就直接限定了这么查询,以及两个变量值

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

3.防御(like和in很容易出现注入漏洞)

1. 原因

Statment不能防止sql注入
“+”号直接拼接参数(要溯源对参数进行过滤)

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2. 解决办法

PreparedStatement预处理

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

3. 当预处理遇到 like (模糊)

不正确写法

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

预处理遇到like—正确处理方法

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

4. 当预处理遇到 in (一般接数字)

不正确写法

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

正确写法
先把数字变成字符串数组,在变成一个个的?

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

4、第三方框架防SQL注入-Mybatis防注入

在实际开发中很少用到这种JDBC的代码,更多的会使用JDBC的代码,向Mybatis就是很常见的,这次先讲这个,下次将一个maven的项目。

1.简单预编译防护

${}直接拼接,存在漏洞

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

#{} 预编译

[ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例

2.like防注入

Mysql:

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

Oracle:

select * from t_user where name like '%' | | #{name} | | '%'

Sql Server:

select * from t_user where name like '%' + #{name} + '%'

3.in防注入

<if test="paramBrands != null" >•and brand.brand_id in <foreach             collection="paramBrands" item="perBrand" open="(" close=")" separator=","> # {perBrand.brandId}</foreach></if>

四、相关资源

1、源代码下载链接
2、Eclipse下载链接
3、Tomcat下载链接
4、[ 代码审计篇 ] Fortify 安装及使用详解(一)
5、DBeaver数据库下载