Code前端首页关于Code前端联系我们

渗透攻防网章:SQL注入简单讲解

terry 2年前 (2023-09-28) 阅读数 56 #Web安全

1背景

京东SRC(安全响应中心)收集了大量外部白帽报告的SQL注入漏洞。大多数漏洞是由SQL语句拼接和Mybatis使用不当引起的。 ? 。 information_schema 模式中的三个表成为 SQL 注入构造的关键。

1) infromation_schema.columns:

  • table_schema 数据库名称
  • table_name 表名称
  • column_name 列名称 数据库schema_schema2)
  • table_name表名

3) information_schema.schemata

  • schema_name数据库名称

SQL注入常用SQL函数

  • length(str):返回字符串长度str
  • substr(str,str pos,len)位置 开始截取长度len的字符并返回。注意这里的 pos 位置从 1 开始,而不是数组中的 0
  • mid (str,pos,len):同上,中断字符串
  • ascii (str):返回字符串 str 的最后一部分左侧字符的 ASCII 码值
  • ord (str):将字符或布尔值转换为 ascll 码
  • if (a,b,c):a 为条件,a 为真,返回 b,否则返回 c ,例如如果(1>2,1,0),则返回0

2.2 输入类型

2.2.1 参数类型分类

  • 整数输入
    例如? id=1 其中id是注入点,type是int类型。
  • 角色注入
    例如? id="1" 其中 id 是注入点,type 是字符。考虑关闭尾随 sql 语句中的引号。

2.2.2 输入方式分类

  • 盲注入
    • 布尔盲注入:语句执行后的布尔值只能从应用程序返回中推导出来。
    • 时间盲注入:应用程序没有明显的回声,只能使用睡眠、基准等特定时间特征进行评估。
  • 错误注入:应用程序显示错误消息或部分错误消息
  • 堆叠注入:可以添加一些应用程序;可以同时执行多条语句
  • 其他

2.3 手动检测步骤(以字符输入为例)

// sqli vuln code
Statement statement = con.createStatement();
String sql = "select * from users where username = '" + username + "'";
logger.info(sql);
ResultSet rs = statement.executeQuery(sql);
// fix code 如果要使用原始jdbc,请采用预编译执行
String sql = "select * from users where username = ?";
PreparedStatement st = con.prepareStatement(sql);

使用非预编译的原始jdbc作为demo。注意,本demo中sql语句的参数是用引号括起来的。

2.3.1 判断插入点

对于字符类型插入,通常会先尝试单引号来判断SQL语句中是否包含单引号。建议使用浏览器扩展 fork 作为手动测试工具。 https://chrome.google.com/webstore/detail/hackbar/ginpbkfigcoaokgflihfhhmglmbchinc

正常页面应该是这样显示的:

渗透攻防 Web 篇 :深入浅出 SQL 注入

在admin后面添加单引号,导致没有任何信息。原因是SQL后台执行错误信息,炫耀了引号。与 SQL 语句合并

渗透攻防 Web 篇 :深入浅出 SQL 注入

渗透攻防 Web 篇 :深入浅出 SQL 注入

select * from users where username = 'admin' #正常sql
select * from users where username = 'admin'' #admin'被带入sql执行导致报错无法显示信息

2.3.2 设置字段数量

Mysql 使用 order by 进行排序。 不仅可以是字段名称,还可以是字段序号。因此,它可以用来确定表中字段的数量。如果序列超过字段数,则报告错误。

渗透攻防 Web 篇 :深入浅出 SQL 注入

评估字段数量

如果序列超过4,就会报错,所以这个表总共有4个字段。

渗透攻防 Web 篇 :深入浅出 SQL 注入

后端程序执行的sql语句

select * from users where username = 'admin' order by 1-- '

这里我们将原来的用户名值admin替换为order admin order 1 —+ 其中admin后面的单引号用来结束原来sql语句的前言, — +用于注释SQL语​​句的反引号。 +号之后的主要任务是分配空间。 SQL语句中的单行注释后面必须跟一个空格,+被解码为空格。

2.3.3 定位echo

主要用于定位前端显示的后端SQL字段,由联合查询确定。注意,串联查询前后的字段必须一致,所以我们进行第二步。

从下图中可以看到,后端询问和回显的字段位置为2和3。

渗透攻防 Web 篇 :深入浅出 SQL 注入

普通查询后面的字段可以是任意的。这次使用数字 1 到 4 是为了直观方便。

渗透攻防 Web 篇 :深入浅出 SQL 注入

2.3.4 使用information_schemas库实现注入 group_concat()函数用于将查询结果连接成字符串。

  • 查看现有数据库

渗透攻防 Web 篇 :深入浅出 SQL 注入

  • 查看当前数据库中的表

渗透攻防 Web 篇 :深入浅出 SQL 注入

  • 查看指定表字段

渗透攻防 Web 篇 :深入浅出 SQL 注入

  • 利用以上信息读取users表中的用户名和密码

渗透攻防 Web 篇 :深入浅出 SQL 注入

3自动检测

3.1 使用sqlmap

sqlmap兼容python2和python3,可以自动检测各种注入和几乎所有数据库类型。 ? —dbs 读取当前用户下的数据库

渗透攻防 Web 篇 :深入浅出 SQL 注入

读取指定库下的表
-D java_sec_code —tables

渗透攻防 Web 篇 :深入浅出 SQL 注入

删除用户的表数据
-D java_s 改进

4.1 Mybatis 注入

1) $ 的错误使用导致注入

//采用#不会导致sql注入,mybatis会使用预编译执行
@Select("select * from users where username = #{username}")
User findByUserName(@Param("username") String username);
//采用$作为入参可导致sql注入
@Select("select * from users where username = '${username}'")
List<User> findByUserNameVuln01(@Param("username") String username);

2) 模糊查询拼接

//错误写法
<select id="findByUserNameVuln02" parameterType="String" resultMap="User">
select * from users where username like '%${_parameter}%'
</select>

//正确写法
<select id="findByUserNameVuln02" parameterType="String" resultMap="User">
select * from users where username like concat(‘%’,#{_parameter}, ‘%’)
</select>

3) 如果在报告错误 #{} 后插入或,则序列,因为默认情况下#{} 引号导致它不会被发现并报告错误。

//错误写法
<select id="findByUserNameVuln03" parameterType="String" resultMap="User">
select * from users
<if test="order != null">
order by ${order} asc
</if>
</select>
//正确写法 id指字段id 此表字段共四个 所以id为1-4
<select id="OrderByUsername" resultMap="User">
select * from users order by id asc limit 1
</select>

以上所有测试均在本地进行,未经许可请勿进行渗透测试

5 推荐文章和资料

slqmap手册:https://octobug.gitbooks.io/sqlzhmap-wi /Users-manual/简介.html
SQL注入详细解释:http://sqlwiki.radare.cn/#/

作者:罗宇(物流安全组)

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门