SQL注入算是我比较熟悉的漏洞了,因为它是我这辈子接触的第一个漏洞,初中十几岁就接触了,只可惜当初听不懂什么and 1=1,or 1=1,因为确实当时连Access和MySQL都没学过,哪里听得懂嘛。我老师当初还手把手教我SQL注入漏洞,可惜当时没学会。
老样子,上Pikachu对SQL注入的解释:
Sql Inject(SQL注入)概述
在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。
一个严重的SQL注入漏洞,可能会直接导致一家公司破产!
SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。
哦,SQL注入漏洞,可怕的漏洞。
在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.使用参数化(Parameterized Query 或 Parameterized Statement);
3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了”拼接”的方式,所以使用时需要慎重!
SQL注入在网络上非常热门,也有很多技术专家写过非常详细的关于SQL注入漏洞的文章,这里就不在多写了。
我的理解:
动态网站呈现在你面前的内容都是放在数据库里面的,在你想看的时候(发起请求),网站在背后用SQL查询语句给你把内容查出来给你看的。在这个前提下,所有和数据库交互的地方都有可能存在SQL注入漏洞,那什么是SQL注入漏洞呢。
所谓SQL注入,究其本质就是没有对前端传过来的参数进行处理,直接拿去查询用,导致别有用心的人精心构造恶意内容,然后网站直接拿去查询,返回了一些敏感内容,或者是不应该被看到的东西。说人话就是,假设本来网站设定是你传递一个1我就给你返回编号为1的内容,你传2我就返回编号为2的内容,但是网站万万没想到你居然传的不是1,而是SQL语句内容,导致网站去执行了,还完全乖乖的照你预想的去执行,返回了你想知道的敏感内容,或者去做了你想它做的事。
在这里我建议学安全的人一定要先去学一下,MySQL、Linux、PHP,因为如果你连SQL都没学过,还学SQL注入,那不是听天书嘛,那不是搞笑嘛,就像没长牙的婴儿非要硬啃核桃,百害无一利,自找罪受,乖乖先长牙,如果连这都不愿意或者做不到,那走不长远。不接受反驳
- 数字型注入(post):
如图所示,有6个数字,不同的数字点查询后,就会出现与数字对应的结果。经验叫我看看前端源码
这里涉及form表单和SQL查询的知识,前提要懂这个。当你懂的话,你看到这个你就应该去想背后的SQL查询语句具体怎么写的,经验告诉我说SQL语句大概是:select username,email from users where id=1 (颜色部分意思是我猜的大概)然后我再去看源码验证。
果然猜的八九不离十,重点是where id=$id,然后$id就是我们传过来的值嘛,比如1、2、3、4、5、6
照我上面所说,开发人员本意想的是你传个1,2,3….. 但是万万没想到你传了sql语句的内容,导致网站返回了你本不应该看到的东西
然后脑洞告诉我,如果把value=”1”改成value=”1 or id=2”会怎么样呢,id是select的name值。于是我去试了一下。
有意思,居然还能查出两条信息,小解释一下,数据库有条信息满足了id=1的条件,然后我写了一个or id=2,效果是数据库另一条数据满足了id=2的条件,所以就出了两条。也就是把查询语句变成了“selct username,email from member where id=1 or id=2” 然后受到其他地方的SQL注入知识告诉我说,如果我改成value=”1 or 1=1”,那么将会查出所有的信息,因为第一条信息满足id=1,其余信息满足1=1,因为1=1是绝对为真,既然是绝对为真,那所有的数据都绝对满足这个or 1=1条件咯,先测试一下
看样子我是对的。这一关考的是数字型SQL注入,因为SQL注入是分数字型和字符型的,所以要分清楚,分清楚之后要去考虑怎么闭合前面的条件,好方便我们写后面的内容,要是你不闭合,那我们输入的所有内容岂不是都被一对引号包裹,输再多内容都会被当成某个字段的值,那肯定就没法实现SQL注入的目的了。遇到字符型再说。
先看数字型特征,如图所示。
可以看出,不用闭合,直接输恶意内容就行。下一关
- 字符型注入(get):
字符型注入就是把你输入的内容加上引号而已,需要注意闭合的问题。如图
我们可以输入:1’ or 1=1 # 或者 1’ or ‘1’=’1
相当于查询语句就变成了select id,email from member where username=’1’ or 1=1 #’ 或 select id,email from member where username=’1’ or ‘1’=’1’
只要闭合前面的内容,后面就可以输入自己想查询的内容,在这里只讲闯关,不讲怎么深入利用漏洞,#号是注释符号,可以让#号后面的内容不生效,在这里也就是让后面那个单引号被注释掉,让其不产生干扰,下一关。
- 搜索型注入:
搜索型注入一般出现在网站搜索内容的地方,这里要注意闭合有所区别而已。如图
我们试着输入:1%’ or 1=1 #
可以安装一个phpstudy来实验一下效果。下一关
- xx型注入:
其实搜索型和xx型都只是闭合有所区别罢了,只是字符型的变种罢了。在闭合上有讲究
我们可以输入:1’) or 1=1 #
之所以有这么多型,是因为现实世界当中有些网站背后写的查询语句不同,然后大致被分为这么几类,然后我们要学会怎么闭合他们。
- “insert/update”注入:
顾名思义,这次不再是在select查询的地方搞注入了,而是在注册(insert)或修改信息(update)的地方,不过大差不差。
提示叫注册,那就先注册一个吧
再看源码,太长了不好截图,还是自己举个例吧
也就是说,这关在注册时在用户哪里输入:’ or updatexml(0,concat(0x7e,database()),1) or ‘
这里涉及许多的知识点,一是闭合不同,二是updatexml这种报错注入。要注意insert和update是和select不同的,不能使用#和其他的注释符号。
再看update注入的源码,还是太长,一样举例子,原理都是相通的。
成功了,下一关
- “delete”注入:
顾名思义,应该是我们发起删除请求的时候,引发的delete注入。如图
点了删除后会跳转当前界面传递一个id参数,就是当前这条留言的id,然后我们修改id的值,就可以实现注入了,我们应该先判断注入类型。
把56改成:56 or 1=1,看看能不能删除成功
删除成功了,应该是数字型的,因为要是字符型的话,那SQL语句大概应该就是:delete from liuyan where id=’59 or 1=1’; 要是这样的话,那就不可能删除成功啊,因为没有那条数据的id会满足等于’59 or 1=1’这个条件啊,数字型就会成功了,因为数字型是:id=59 or 1=1,就会执行,不用闭合。下一关
不好意思,看了博客才发现应该使用报错注入查询当前数据库名等敏感信息,我上面那个玩意只是会把所有的留言全部删干净。我们应该在id的数字后面输入:or updatexml(0,concat(0x7e,database()),1)
database()可以换成其他的sql语句,自由发挥
- “http header”注入:
127.0.0.1和localhost开头的本地网站数据包burp不抓,给我折磨惨了,后来发现了一个方法,终于间接解决了,所以先写那个文章。传送阵
这一关据我了解,应该是会把访客的http请求的头信息插入到数据库中,然后我们搞清楚插得哪个的值,然后把它改成恶意语句,应该就可以完成SQL注入。
插入的是user agent的值,也就是我们的注入点
分析结束,开始操作,反正本质就是insert语句,有个注意的地方,这关要先登录,再点刷新才可以做,不然做不了,因为你不先登陆后台的话,没法insert,抓了包也没用,你登录了的话,insert又结束了,没有了请求还抓不了包。但是像我说的那么做就没事了。
- 先登录
- 开启抓包:
再开抓包的那些基础操作
- 再按F5刷新触发抓包:
再发送到Repeater模块
在修改User-Agent的值:’ or updatexml(0,concat(0x7e,database()),1) or ‘ 再点左上角的send放包
查看结果
结果出现,只要明白咋回事,就不难,反正原理就那样,赶时间,下一关,pikachu只是个入门小靶场,随便写写,以后再重新写个深入版本的笔记吧。
- 盲注(base on boolian):
先引导一下思路,前面的注入大家有没有注意到基本页面都会给你显示信息呢,要么是报错信息,要么就是正常的信息,总之都会显示信息,但是什么叫盲注呢,简单来说就是你输入恶意内容,但是页面没什么内容显示,那是不是就代表没有SQL注入漏洞呢,不一定,可能就是开发人员屏蔽报错,不让错误信息显示在前端而已。
基于布尔(真假)的盲注的应用场景在于你输入了恶意语句,页面要么显示正常结果,要么什么都不显示,没有别的内容,是不是就像:你输的恶意语句为真我就显示,为假我就不显示。这就是所谓的布尔盲注
我们分别输入:’ 和 vince’ and 1=1# 和 vince’ and 1=2# 来看看效果。
假设我们输入:vince’ or 1=1#时会如何呢?
无结果,有意思,建议去看下源码,参悟一下
附上源码:
然后我们输入:vince’ and 1=2 union select database(),version()# 看效果
反正我满足了条件,那就是sql执行成功,而且查出的数据为一行。既然满足条件,没有利用不返回,至于这条语句,涉及的是union联合注入的知识,博客没有,有空我写个地方。这关照博客的说法不应该这么过,所以我照着博客再做一下。
参考博客认为,只有当前后都为真时,才能显示正常内容证明我们输入的恶意内容为真,说起来听不懂,所以举例就好。我们输入:vince’ and ascii(substr(database(),1,1))<100# 看效果
先解释:vince’ and ascii(substr(database(),1,1))<100# 这句话and后面的意思是,读取当前数据库名,并对它进行字符串截取,从第1个字符开始截取,截取1个字符,然后再把它转换成ASCII码,然后判断它是否小于100,是就返回真,不是就返回假,以此来推测当前数据库的名字,效率真™高啊这玩意。之所以要从1开始截取,是因为从0开始截取1个的话是空白符。先去找一找ASCII表吧。
由于我们知道当前数据库是小写的:pikachu,所以我们可以这样写:vince’ and ascii(substr(database(),1,1))=112#
显示正常,说明and后面的是对的,由此可以逐渐判断出数据库的名字。下一关
- 盲注(base on time):我们输入的内容如果连正常和不正常都不显示的话,那就不能再用基于真假的布尔盲注了,而是用基于时间的盲注。
始终显示这个,输入:lucy’ and sleep(5)#,再看响应时间
页面加载了5秒,说明执行了我们输入的内容,说明存在SQL注入。然后我们就可以在and后面写猜信息的内容,比如:vince’ and if(ascii(substr(database(),1,1))=112,sleep(5),null)#
至此,可以推测出完整的库名,下一关
- 宽字节注入:
先了解什么是宽字节注入:传送阵,简单来说就是闭合字符型需要输入引号,但是呢php会转义,就是把引号那些前面加一个\,这样引号就被转义了,没有了闭合效果,变成了普通字符,但是如果mysql用了gbk,我们输入%df’,将会变成%df\’,然后还会经历这个过程。
意思就是php与mysql交互还会经历一个十六进制转换的过程,%df\’转换成十六进制会变成%df%5C%27,但是mysql解码的时候又把%df%5C当成了汉字:縗,这么说来%df%5C%27在MySQL里面会变成:縗’,这样单引号就逃出来了,就可以闭合前面的单引号了,就可以实施SQL注入了,详细的可参考两大文章:1. 云社区,2. CSDN
Payload:%df’ union select version(),database()#,要用抓包工具,不然又会把%df变成%25df。
这里还涉及union的知识,以后单独开一个模块。至此pikachu的sql注入模块全部结束
总结:SQL注入可是漏洞之王,不仅可以泄露信息,还可以写入一句话木马,危害还挺大的。被称为漏洞之王,也是OWASP top1,要好好学习一下所有的常见数据库及SQL语句,及php等脚本语言。还要入门练闭合,深入练绕过,以后会碰到千奇百怪的过滤,如何一 一绕过?
修复建议:
- 输入过滤,检测前端所有的输入,先过滤敏感内容再拼接SQL语句
- 采用预处理机制,可以有效防范SQL注入
- 屏蔽报错,不要显示在前端
- 开启waf防火墙,什么都解决了